Submitted changed files from AppleWin-Tom branch to trunk

. Change: Added support for SSC receive IRQ (eg. Z-Link)
. Fix: [Bug #7231] AppleWin installed in path with spaces

Internal:
. Modified operation of interrupt assert/deassert
This commit is contained in:
tomch 2006-05-02 21:56:28 +00:00
parent 8a453a479e
commit 0b8d9e723c
11 changed files with 258 additions and 162 deletions

View File

@ -358,9 +358,6 @@
<Filter <Filter
Name="Docs" Name="Docs"
Filter=""> Filter="">
<File
RelativePath=".\docs\Bugs.txt">
</File>
<File <File
RelativePath=".\docs\CodingConventions.txt"> RelativePath=".\docs\CodingConventions.txt">
</File> </File>

View File

@ -46,23 +46,6 @@ END
#endif // APSTUDIO_INVOKED #endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDS_TFE_CAPTION "Ethernet Settings"
IDS_TFE_ETHERNET "Ethernet"
IDS_TFE_INTERFACE "Interface"
END
STRINGTABLE
BEGIN
IDS_OK "OK"
IDS_CANCEL "Cancel"
END
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
@ -216,8 +199,8 @@ BEGIN
GROUPBOX "Harddisk Controller",IDC_STATIC,2,113,205,71 GROUPBOX "Harddisk Controller",IDC_STATIC,2,113,205,71
END END
IDD_TFE_SETTINGS_DIALOG DIALOG DISCARDABLE 0, 0, 270, 100 IDD_TFE_SETTINGS_DIALOG DIALOG 0, 0, 270, 100
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Ethernet Settings" CAPTION "Ethernet Settings"
FONT 8, "MS Sans Serif" FONT 8, "MS Sans Serif"
BEGIN BEGIN
@ -233,6 +216,7 @@ BEGIN
PUSHBUTTON "Cancel",IDCANCEL,80,75,50,14 PUSHBUTTON "Cancel",IDCANCEL,80,75,50,14
END END
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
// Icon // Icon
@ -249,8 +233,8 @@ DISK_ICON ICON "DISK.ICO"
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,12,9,1 FILEVERSION 1,13,0,0
PRODUCTVERSION 1,12,9,1 PRODUCTVERSION 1,13,0,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -268,12 +252,12 @@ BEGIN
VALUE "Comments", "http://applewin.berlios.de" VALUE "Comments", "http://applewin.berlios.de"
VALUE "CompanyName", "Michael O'Brien, Oliver Schmidt, Tom Charlesworth" VALUE "CompanyName", "Michael O'Brien, Oliver Schmidt, Tom Charlesworth"
VALUE "FileDescription", "Apple //e Emulator for Windows" VALUE "FileDescription", "Apple //e Emulator for Windows"
VALUE "FileVersion", "1, 12, 9, 1" VALUE "FileVersion", "1, 13, 0, 0"
VALUE "InternalName", "APPLEWIN" VALUE "InternalName", "APPLEWIN"
VALUE "LegalCopyright", "© 1994-2006 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski" VALUE "LegalCopyright", "© 1994-2006 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski"
VALUE "OriginalFilename", "APPLEWIN.EXE" VALUE "OriginalFilename", "APPLEWIN.EXE"
VALUE "ProductName", "Apple //e Emulator" VALUE "ProductName", "Apple //e Emulator"
VALUE "ProductVersion", "1, 12, 9, 1" VALUE "ProductVersion", "1, 13, 0, 0"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
@ -302,7 +286,6 @@ END
IDR_HDDRVR FIRMWARE "Hddrvr.bin" IDR_HDDRVR FIRMWARE "Hddrvr.bin"
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// //
// ROM // ROM
@ -341,6 +324,25 @@ BEGIN
END END
END END
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_TFE_CAPTION "Ethernet Settings"
IDS_TFE_ETHERNET "Ethernet"
IDS_TFE_INTERFACE "Interface"
END
STRINGTABLE
BEGIN
IDS_OK "OK"
IDS_CANCEL "Cancel"
END
#endif // English (U.S.) resources #endif // English (U.S.) resources
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View File

@ -34,6 +34,11 @@
#include <crtdbg.h> #include <crtdbg.h>
#include "ay8910.h" #include "ay8910.h"
#include "Common.h"
#include "Structs.h"
#include "Applewin.h" // For g_fh
#include "Mockingboard.h" // For g_uTimer1IrqCount
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// typedefs & dummy funcs to allow MAME code to compile: // typedefs & dummy funcs to allow MAME code to compile:
@ -105,7 +110,56 @@ struct AY8910
static struct AY8910 AYPSG[MAX_8910]; /* array of PSG's */ static struct AY8910 AYPSG[MAX_8910]; /* array of PSG's */
static bool g_bAYReset = false; // Doing AY8910_reset()
//-----------------------------------------------------------------------------
//#define LOG_AY8910
#ifdef LOG_AY8910
static void LogAY8910(int n, int r, UINT uFreq)
{
// TO DO: Determine freq from 6522 timer
if ((g_fh == NULL) || g_bAYReset)
return;
static UINT nCnt = 0;
const UINT nNumAYs = 4; // 1..4
if((r == 0))
{
if(nCnt == 0)
{
fprintf(g_fh, "Time : ");
for(UINT i=0; i<nNumAYs; i++)
fprintf(g_fh, "APer BPer CPer NP EN AV BV CV ");
fprintf(g_fh, "\n");
}
fprintf(g_fh, "%02d.%02d: ", g_uTimer1IrqCount/uFreq, g_uTimer1IrqCount%uFreq);
for(int j=0; j<n*(3*5+5*3+1); j++)
fprintf(g_fh, " ");
UINT i=n;
{
UCHAR* pAYRegs = &AYPSG[i].Regs[0];
fprintf(g_fh, "%04X ", *(USHORT*)&pAYRegs[AY_AFINE]);
fprintf(g_fh, "%04X ", *(USHORT*)&pAYRegs[AY_BFINE]);
fprintf(g_fh, "%04X ", *(USHORT*)&pAYRegs[AY_CFINE]);
fprintf(g_fh, "%02X ", pAYRegs[AY_NOISEPER]);
fprintf(g_fh, "%02X ", pAYRegs[AY_ENABLE]);
fprintf(g_fh, "%02X ", pAYRegs[AY_AVOL]);
fprintf(g_fh, "%02X ", pAYRegs[AY_BVOL]);
fprintf(g_fh, "%02X ", pAYRegs[AY_CVOL]);
}
fprintf(g_fh, "\n");
nCnt++;
}
}
#endif
//-----------------------------------------------------------------------------
void _AYWriteReg(int n, int r, int v) void _AYWriteReg(int n, int r, int v)
{ {
@ -115,27 +169,8 @@ void _AYWriteReg(int n, int r, int v)
PSG->Regs[r] = v; PSG->Regs[r] = v;
//#define LOG_AY8910
#ifdef LOG_AY8910 #ifdef LOG_AY8910
extern FILE* g_fh; // Filehandle for log file LogAY8910(n, r, 60);
static UINT nCnt = 0;
if((n == 0) && (r == 0) && g_fh)
{
if(nCnt == 0)
fprintf(g_fh, "Time : APer BPer CPer NP EN AV BV CV\n");
fprintf(g_fh, "%02d.%02d: ", nCnt/60, nCnt%60);
nCnt++;
fprintf(g_fh, "%04X ", *(USHORT*)&PSG->Regs[AY_AFINE]);
fprintf(g_fh, "%04X ", *(USHORT*)&PSG->Regs[AY_BFINE]);
fprintf(g_fh, "%04X ", *(USHORT*)&PSG->Regs[AY_CFINE]);
fprintf(g_fh, "%02X ", PSG->Regs[AY_NOISEPER]);
fprintf(g_fh, "%02X ", PSG->Regs[AY_ENABLE]);
fprintf(g_fh, "%02X ", PSG->Regs[AY_AVOL]);
fprintf(g_fh, "%02X ", PSG->Regs[AY_BVOL]);
fprintf(g_fh, "%02X\n", PSG->Regs[AY_CVOL]);
}
#endif #endif
/* A note about the period of tones, noise and envelope: for speed reasons,*/ /* A note about the period of tones, noise and envelope: for speed reasons,*/
@ -692,6 +727,8 @@ void ay8910_write_ym(int chip, int addr, int data)
void AY8910_reset(int chip) void AY8910_reset(int chip)
{ {
g_bAYReset = true;
int i; int i;
struct AY8910 *PSG = &AYPSG[chip]; struct AY8910 *PSG = &AYPSG[chip];
@ -706,6 +743,8 @@ void AY8910_reset(int chip)
_AYWriteReg(chip,i,0); /* AYWriteReg() uses the timer system; we cannot */ _AYWriteReg(chip,i,0); /* AYWriteReg() uses the timer system; we cannot */
/* call it at this time because the timer system */ /* call it at this time because the timer system */
/* has not been initialized. */ /* has not been initialized. */
g_bAYReset = false;
} }
//------------------------------------- //-------------------------------------

View File

@ -412,38 +412,50 @@ void LoadConfiguration () {
} }
//=========================================================================== //===========================================================================
void RegisterExtensions () { void RegisterExtensions ()
TCHAR command[MAX_PATH]; {
GetModuleFileName((HMODULE)0,command,MAX_PATH); TCHAR szCommandTmp[MAX_PATH];
command[MAX_PATH-1] = 0; GetModuleFileName((HMODULE)0,szCommandTmp,MAX_PATH);
TCHAR icon[MAX_PATH];
wsprintf(icon,TEXT("%s,1"),(LPCTSTR)command); TCHAR command[MAX_PATH];
_tcscat(command,TEXT(" %1")); wsprintf(command, "\"%s\"", szCommandTmp); // Wrap path & filename in quotes & null terminate
RegSetValue(HKEY_CLASSES_ROOT,".bin",REG_SZ,"DiskImage",10);
RegSetValue(HKEY_CLASSES_ROOT,".do" ,REG_SZ,"DiskImage",10); TCHAR icon[MAX_PATH];
RegSetValue(HKEY_CLASSES_ROOT,".dsk",REG_SZ,"DiskImage",10); wsprintf(icon,TEXT("%s,1"),(LPCTSTR)command);
RegSetValue(HKEY_CLASSES_ROOT,".nib",REG_SZ,"DiskImage",10);
RegSetValue(HKEY_CLASSES_ROOT,".po" ,REG_SZ,"DiskImage",10); _tcscat(command,TEXT(" \"%1\"")); // Append "%1"
// RegSetValue(HKEY_CLASSES_ROOT,".aws",REG_SZ,"DiskImage",10); // TO DO
// RegSetValue(HKEY_CLASSES_ROOT,".hdv",REG_SZ,"DiskImage",10); // TO DO RegSetValue(HKEY_CLASSES_ROOT,".bin",REG_SZ,"DiskImage",10);
RegSetValue(HKEY_CLASSES_ROOT, RegSetValue(HKEY_CLASSES_ROOT,".do" ,REG_SZ,"DiskImage",10);
"DiskImage", RegSetValue(HKEY_CLASSES_ROOT,".dsk",REG_SZ,"DiskImage",10);
REG_SZ,"Disk Image",21); RegSetValue(HKEY_CLASSES_ROOT,".nib",REG_SZ,"DiskImage",10);
RegSetValue(HKEY_CLASSES_ROOT, RegSetValue(HKEY_CLASSES_ROOT,".po" ,REG_SZ,"DiskImage",10);
"DiskImage\\DefaultIcon", // RegSetValue(HKEY_CLASSES_ROOT,".aws",REG_SZ,"DiskImage",10); // TO DO
REG_SZ,icon,_tcslen(icon)+1); // RegSetValue(HKEY_CLASSES_ROOT,".hdv",REG_SZ,"DiskImage",10); // TO DO
RegSetValue(HKEY_CLASSES_ROOT,
"DiskImage\\shell\\open\\command", RegSetValue(HKEY_CLASSES_ROOT,
REG_SZ,command,_tcslen(command)+1); "DiskImage",
RegSetValue(HKEY_CLASSES_ROOT, REG_SZ,"Disk Image",21);
"DiskImage\\shell\\open\\ddeexec",
REG_SZ,"%1",3); RegSetValue(HKEY_CLASSES_ROOT,
RegSetValue(HKEY_CLASSES_ROOT, "DiskImage\\DefaultIcon",
"DiskImage\\shell\\open\\ddeexec\\application", REG_SZ,icon,_tcslen(icon)+1);
REG_SZ,"applewin",9);
RegSetValue(HKEY_CLASSES_ROOT, RegSetValue(HKEY_CLASSES_ROOT,
"DiskImage\\shell\\open\\ddeexec\\topic", "DiskImage\\shell\\open\\command",
REG_SZ,"system",7); REG_SZ,command,_tcslen(command)+1);
RegSetValue(HKEY_CLASSES_ROOT,
"DiskImage\\shell\\open\\ddeexec",
REG_SZ,"%1",3);
RegSetValue(HKEY_CLASSES_ROOT,
"DiskImage\\shell\\open\\ddeexec\\application",
REG_SZ,"applewin",9);
RegSetValue(HKEY_CLASSES_ROOT,
"DiskImage\\shell\\open\\ddeexec\\topic",
REG_SZ,"system",7);
} }
//=========================================================================== //===========================================================================

View File

@ -106,6 +106,14 @@ static ULONG g_nCyclesExecuted;
static signed long nInternalCyclesLeft; static signed long nInternalCyclesLeft;
//
// Assume all interrupt sources assert until the device is told to stop:
// - eg by r/w to device's register or a machine reset
static CRITICAL_SECTION g_CriticalSection; // To guard /g_bmIRQ/
static volatile UINT32 g_bmIRQ = 0;
/**************************************************************************** /****************************************************************************
* *
* GENERAL PURPOSE MACROS * GENERAL PURPOSE MACROS
@ -488,21 +496,6 @@ static DWORD InternalCpuExecute (DWORD totalcycles)
nInternalCyclesLeft = (totalcycles<<8) - (cycles<<8); nInternalCyclesLeft = (totalcycles<<8) - (cycles<<8);
USHORT uExtraCycles = 0; USHORT uExtraCycles = 0;
if(regs.bIRQ && !(regs.ps & AF_INTERRUPT))
{
g_nCycleIrqStart = g_nCumulativeCycles + cycles;
regs.bIRQ = 0;
PUSH(regs.pc >> 8)
PUSH(regs.pc & 0xFF)
EF_TO_AF
regs.ps |= AF_RESERVED;
PUSH(regs.ps)
regs.ps |= AF_INTERRUPT;
regs.pc = * (WORD*) (mem+0xFFFE);
CYC(7)
continue;
}
switch (*(mem+regs.pc++)) switch (*(mem+regs.pc++))
{ {
case 0x00: BRK CYC(7) break; case 0x00: BRK CYC(7) break;
@ -764,6 +757,20 @@ static DWORD InternalCpuExecute (DWORD totalcycles)
case 0xFE: ABSX INC CYC(6) break; case 0xFE: ABSX INC CYC(6) break;
case 0xFF: INVALID1 CYC(1) break; case 0xFF: INVALID1 CYC(1) break;
} }
if(g_bmIRQ && !(regs.ps & AF_INTERRUPT))
{
// IRQ signals are deasserted when a specific r/w operation is done on device
g_nCycleIrqStart = g_nCumulativeCycles + cycles;
PUSH(regs.pc >> 8)
PUSH(regs.pc & 0xFF)
EF_TO_AF
regs.ps |= AF_RESERVED;
PUSH(regs.ps)
regs.ps |= AF_INTERRUPT;
regs.pc = * (WORD*) (mem+0xFFFE);
CYC(7)
}
} }
while (cycles < totalcycles); while (cycles < totalcycles);
EF_TO_AF EF_TO_AF
@ -784,6 +791,8 @@ void CpuDestroy () {
cpugetcodefunc[loop] = NULL; cpugetcodefunc[loop] = NULL;
cpulibrary[loop] = (HINSTANCE)0; cpulibrary[loop] = (HINSTANCE)0;
} }
DeleteCriticalSection(&g_CriticalSection);
} }
//=========================================================================== //===========================================================================
@ -902,9 +911,15 @@ void CpuInitialize () {
regs.ps = 0x20; regs.ps = 0x20;
regs.pc = *(LPWORD)(mem+0xFFFC); regs.pc = *(LPWORD)(mem+0xFFFC);
regs.sp = 0x01FF; regs.sp = 0x01FF;
regs.bIRQ = 0;
InitializeCriticalSection(&g_CriticalSection);
CpuIrqReset();
#ifdef _X86_ #ifdef _X86_
// TO DO:
// . FreeLibrary isn't being called if DLLs' version is too low
// . This code is going to get ditched, so ignore this!
if (mem) { if (mem) {
TCHAR filename[MAX_PATH]; TCHAR filename[MAX_PATH];
_tcscpy(filename,progdir); _tcscpy(filename,progdir);
@ -998,11 +1013,27 @@ BOOL CpuSupportsFastPaging () {
} }
//=========================================================================== //===========================================================================
void CpuIRQ()
void CpuIrqReset()
{ {
regs.bIRQ = 1; EnterCriticalSection(&g_CriticalSection);
g_bmIRQ = 0;
LeaveCriticalSection(&g_CriticalSection);
} }
void CpuIrqAssert(eIRQSRC Device)
{
EnterCriticalSection(&g_CriticalSection);
g_bmIRQ |= 1<<Device;
LeaveCriticalSection(&g_CriticalSection);
}
void CpuIrqDeassert(eIRQSRC Device)
{
EnterCriticalSection(&g_CriticalSection);
g_bmIRQ &= ~(1<<Device);
LeaveCriticalSection(&g_CriticalSection);
}
//=========================================================================== //===========================================================================
DWORD CpuGetSnapshot(SS_CPU6502* pSS) DWORD CpuGetSnapshot(SS_CPU6502* pSS)
@ -1026,7 +1057,7 @@ DWORD CpuSetSnapshot(SS_CPU6502* pSS)
regs.ps = pSS->P; regs.ps = pSS->P;
regs.sp = (USHORT)pSS->S + 0x100; regs.sp = (USHORT)pSS->S + 0x100;
regs.pc = pSS->PC; regs.pc = pSS->PC;
regs.bIRQ = 0; CpuIrqReset();
g_nCumulativeCycles = pSS->g_nCumulativeCycles; g_nCumulativeCycles = pSS->g_nCumulativeCycles;
return 0; return 0;

View File

@ -28,6 +28,8 @@ void CpuReinitialize ();
void CpuResetCompilerData (); void CpuResetCompilerData ();
void CpuSetupBenchmark (); void CpuSetupBenchmark ();
BOOL CpuSupportsFastPaging (); BOOL CpuSupportsFastPaging ();
void CpuIRQ (); void CpuIrqReset();
void CpuIrqAssert(eIRQSRC Device);
void CpuIrqDeassert(eIRQSRC Device);
DWORD CpuGetSnapshot(SS_CPU6502* pSS); DWORD CpuGetSnapshot(SS_CPU6502* pSS);
DWORD CpuSetSnapshot(SS_CPU6502* pSS); DWORD CpuSetSnapshot(SS_CPU6502* pSS);

View File

@ -1,7 +1,8 @@
#pragma once #pragma once
const double _M14 = 14.31818e6; const double _M14 = 14.31818e6;
const double CLK_6502 = (_M14 / 14.0); const double CLK_6502 = (_M14 / 14.0); // 1022727 + 1/7
//const double CLK_6502 = 23 * 44100; // 1014300
const UINT uCyclesPerLine = 65; // 25 cycles of HBL & 40 cycles of HBL' const UINT uCyclesPerLine = 65; // 25 cycles of HBL & 40 cycles of HBL'
const UINT uVisibleLinesPerFrame = 64*3; // 192 const UINT uVisibleLinesPerFrame = 64*3; // 192
@ -71,3 +72,4 @@ typedef BYTE (__stdcall *cxfunction)(WORD nPC, WORD nAddr, BYTE nWriteFlag, BYTE
typedef struct _IMAGE__ { int unused; } *HIMAGE; typedef struct _IMAGE__ { int unused; } *HIMAGE;
enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC};

View File

@ -983,7 +983,7 @@ void MemReset ()
// INITIALIZE PAGING, FILLING IN THE 64K MEMORY IMAGE // INITIALIZE PAGING, FILLING IN THE 64K MEMORY IMAGE
ResetPaging(1); ResetPaging(1);
regs.pc = *(LPWORD)(mem+0xFFFC); regs.pc = *(LPWORD)(mem+0xFFFC);
regs.bIRQ = 0; CpuIrqReset();
} }
//=========================================================================== //===========================================================================

View File

@ -120,9 +120,10 @@ typedef struct
// IFR & IER: // IFR & IER:
#define PERIPHERAL (1<<1) #define IxR_PERIPHERAL (1<<1)
#define TIMER2 (1<<5) #define IxR_VOTRAX (1<<4) // TO DO: Get proper name from 6522 datasheet!
#define TIMER1 (1<<6) #define IxR_TIMER2 (1<<5)
#define IxR_TIMER1 (1<<6)
// ACR: // ACR:
#define RUNMODE (1<<6) // 0 = 1-Shot Mode, 1 = Free Running Mode #define RUNMODE (1<<6) // 0 = 1-Shot Mode, 1 = Free Running Mode
@ -194,6 +195,7 @@ static const double g_f6522TimerPeriod_NoIRQ = CLK_6502 / 60.0; // Constant wha
// External global vars: // External global vars:
bool g_bMBTimerIrqActive = false; bool g_bMBTimerIrqActive = false;
UINT32 g_uTimer1IrqCount = 0; // DEBUG
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -208,7 +210,7 @@ static void StartTimer(SY6522_AY8910* pMB)
if((pMB->nAY8910Number & 1) != SY6522_DEVICE_A) if((pMB->nAY8910Number & 1) != SY6522_DEVICE_A)
return; return;
if((pMB->sy6522.IER & TIMER1) == 0x00) if((pMB->sy6522.IER & IxR_TIMER1) == 0x00)
return; return;
USHORT nPeriod = pMB->sy6522.TIMER1_LATCH.w; USHORT nPeriod = pMB->sy6522.TIMER1_LATCH.w;
@ -216,14 +218,6 @@ static void StartTimer(SY6522_AY8910* pMB)
if(nPeriod <= 0xff) // Timer1L value has been written (but TIMER1H hasn't) if(nPeriod <= 0xff) // Timer1L value has been written (but TIMER1H hasn't)
return; return;
#if 0
if(nPeriod < 0x3000) // Bit of IRQ protection (probably not needed) - Phasor has ~0x800 cycle period
{
_ASSERT(0);
return;
}
#endif
pMB->nTimerStatus = 1; pMB->nTimerStatus = 1;
// 6522 CLK runs at same speed as 6502 CLK // 6522 CLK runs at same speed as 6502 CLK
@ -285,7 +279,6 @@ static void AY8910_Write(BYTE nDevice, BYTE nReg, BYTE nValue, BYTE nAYDevice)
case AY_WRITE: // 6: WRITE TO PSG case AY_WRITE: // 6: WRITE TO PSG
_AYWriteReg(nDevice+2*nAYDevice, pMB->nAYCurrentRegister, pMB->sy6522.ORA); _AYWriteReg(nDevice+2*nAYDevice, pMB->nAYCurrentRegister, pMB->sy6522.ORA);
// AY8910_write_ym(nDevice+2*nAYDevice, pMB->nAYCurrentRegister, pMB->sy6522.ORA);
break; break;
case AY_LATCH: // 7: LATCH ADDRESS case AY_LATCH: // 7: LATCH ADDRESS
@ -303,6 +296,17 @@ static void UpdateIFR(SY6522_AY8910* pMB)
if(pMB->sy6522.IFR & pMB->sy6522.IER & 0x7F) if(pMB->sy6522.IFR & pMB->sy6522.IER & 0x7F)
pMB->sy6522.IFR |= 0x80; pMB->sy6522.IFR |= 0x80;
// Now update the IRQ signal from all 6522s
// . OR-sum of all active TIMER1, TIMER2 & SPEECH sources (from all 6522s)
UINT bIRQ = 0;
for(UINT i=0; i<NUM_SY6522; i++)
bIRQ |= g_MB[i].sy6522.IFR & 0x80;
if (bIRQ)
CpuIrqAssert(IS_6522);
else
CpuIrqDeassert(IS_6522);
} }
static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue) static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
@ -360,7 +364,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
/* Initiates timer1 & clears time-out of timer1 */ /* Initiates timer1 & clears time-out of timer1 */
// Clear Timer Interrupt Flag. // Clear Timer Interrupt Flag.
pMB->sy6522.IFR &= ~TIMER1; pMB->sy6522.IFR &= ~IxR_TIMER1;
UpdateIFR(pMB); UpdateIFR(pMB);
pMB->sy6522.TIMER1_LATCH.h = nValue; pMB->sy6522.TIMER1_LATCH.h = nValue;
@ -371,7 +375,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
case 0x07: // TIMER1H_LATCH case 0x07: // TIMER1H_LATCH
// Clear Timer1 Interrupt Flag. // Clear Timer1 Interrupt Flag.
pMB->sy6522.TIMER1_LATCH.h = nValue; pMB->sy6522.TIMER1_LATCH.h = nValue;
pMB->sy6522.IFR &= ~TIMER1; pMB->sy6522.IFR &= ~IxR_TIMER1;
UpdateIFR(pMB); UpdateIFR(pMB);
break; break;
case 0x08: // TIMER2L case 0x08: // TIMER2L
@ -379,7 +383,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
break; break;
case 0x09: // TIMER2H case 0x09: // TIMER2H
// Clear Timer2 Interrupt Flag. // Clear Timer2 Interrupt Flag.
pMB->sy6522.IFR &= ~TIMER2; pMB->sy6522.IFR &= ~IxR_TIMER2;
UpdateIFR(pMB); UpdateIFR(pMB);
pMB->sy6522.TIMER2_LATCH.h = nValue; pMB->sy6522.TIMER2_LATCH.h = nValue;
@ -410,7 +414,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
UpdateIFR(pMB); UpdateIFR(pMB);
// Check if timer has been disabled. // Check if timer has been disabled.
if(pMB->sy6522.IER & TIMER1) if(pMB->sy6522.IER & IxR_TIMER1)
break; break;
if(pMB->nTimerStatus == 0) if(pMB->nTimerStatus == 0)
@ -461,7 +465,7 @@ static BYTE SY6522_Read(BYTE nDevice, BYTE nReg)
break; break;
case 0x04: // TIMER1L_COUNTER case 0x04: // TIMER1L_COUNTER
nValue = pMB->sy6522.TIMER1_COUNTER.l; nValue = pMB->sy6522.TIMER1_COUNTER.l;
pMB->sy6522.IFR &= ~TIMER1; // Also clears Timer1 Interrupt Flag pMB->sy6522.IFR &= ~IxR_TIMER1; // Also clears Timer1 Interrupt Flag
UpdateIFR(pMB); UpdateIFR(pMB);
break; break;
case 0x05: // TIMER1H_COUNTER case 0x05: // TIMER1H_COUNTER
@ -475,7 +479,7 @@ static BYTE SY6522_Read(BYTE nDevice, BYTE nReg)
break; break;
case 0x08: // TIMER2L case 0x08: // TIMER2L
nValue = pMB->sy6522.TIMER2_COUNTER.l; nValue = pMB->sy6522.TIMER2_COUNTER.l;
pMB->sy6522.IFR &= ~TIMER2; // Also clears Timer2 Interrupt Flag pMB->sy6522.IFR &= ~IxR_TIMER2; // Also clears Timer2 Interrupt Flag
UpdateIFR(pMB); UpdateIFR(pMB);
break; break;
case 0x09: // TIMER2H case 0x09: // TIMER2H
@ -543,32 +547,12 @@ const BYTE AMPLITUDE_MASK = 0x0F;
static BYTE SSI263_Read(BYTE nDevice, BYTE nReg) static BYTE SSI263_Read(BYTE nDevice, BYTE nReg)
{ {
BYTE nValue;
SY6522_AY8910* pMB = &g_MB[nDevice]; SY6522_AY8910* pMB = &g_MB[nDevice];
switch(nReg) // Regardless of register, just return inverted A/!R in bit7
{ // . A/!R is low for IRQ
case SSI_DURPHON:
nValue = pMB->SpeechChip.DurationPhonome;
break;
case SSI_INFLECT:
nValue = pMB->SpeechChip.Inflection;
break;
case SSI_RATEINF:
nValue = pMB->SpeechChip.RateInflection;
break;
case SSI_CTTRAMP:
nValue = pMB->SpeechChip.CtrlArtAmp;
break;
case SSI_FILFREQ:
nValue = pMB->SpeechChip.FilterFreq;
break;
default:
break;
}
return nValue; return pMB->SpeechChip.CurrentMode << 7;
} }
static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue) static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
@ -581,6 +565,14 @@ static void SSI263_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
#if LOG_SSI263 #if LOG_SSI263
if(g_fh) fprintf(g_fh, "DUR = 0x%02X, PHON = 0x%02X\n\n", nValue>>6, nValue&PHONEME_MASK); if(g_fh) fprintf(g_fh, "DUR = 0x%02X, PHON = 0x%02X\n\n", nValue>>6, nValue&PHONEME_MASK);
#endif #endif
// Datasheet is not clear, but a write to DURPHON must clear the IRQ
if(g_bPhasorEnable)
CpuIrqDeassert(IS_SPEECH);
pMB->sy6522.IFR &= ~IxR_PERIPHERAL;
UpdateIFR(pMB);
pMB->SpeechChip.CurrentMode &= ~1; // Clear SSI263's D7 pin
pMB->SpeechChip.DurationPhonome = nValue; pMB->SpeechChip.DurationPhonome = nValue;
// Phoneme output not dependent on CONTROL bit // Phoneme output not dependent on CONTROL bit
@ -703,6 +695,11 @@ static void Votrax_Write(BYTE nDevice, BYTE nValue)
{ {
g_bVotraxPhoneme = true; g_bVotraxPhoneme = true;
// !A/R: Acknowledge receipt of phoneme data (signal goes from high to low)
SY6522_AY8910* pMB = &g_MB[nDevice];
pMB->sy6522.IFR &= ~IxR_VOTRAX;
UpdateIFR(pMB);
SSI263_Play(Votrax2SSI263[nValue & PHONEME_MASK]); SSI263_Play(Votrax2SSI263[nValue & PHONEME_MASK]);
} }
@ -895,18 +892,19 @@ static DWORD WINAPI SSI263Thread(LPVOID lpParameter)
{ {
if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED)) if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED))
{ {
CpuIRQ(); pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
// Is Phasor's SSI263.IRQ wired directly to IRQ? (Bypassing the 6522)
CpuIrqAssert(IS_SPEECH);
} }
} }
else else
{ {
if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C)) if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C))
{ {
pMB->sy6522.IFR |= PERIPHERAL; pMB->sy6522.IFR |= IxR_PERIPHERAL;
UpdateIFR(pMB); UpdateIFR(pMB);
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
if(pMB->sy6522.IER & PERIPHERAL)
CpuIRQ();
} }
} }
@ -914,11 +912,10 @@ static DWORD WINAPI SSI263Thread(LPVOID lpParameter)
if(g_bVotraxPhoneme && (pMB->sy6522.PCR == 0xB0)) if(g_bVotraxPhoneme && (pMB->sy6522.PCR == 0xB0))
{ {
pMB->sy6522.IFR |= 0x10; // !A/R: Time-out of old phoneme (signal goes from low to high)
UpdateIFR(pMB);
if(pMB->sy6522.IER & 0x10) pMB->sy6522.IFR |= IxR_VOTRAX;
CpuIRQ(); UpdateIFR(pMB);
g_bVotraxPhoneme = false; g_bVotraxPhoneme = false;
} }
@ -939,6 +936,10 @@ static void SSI263_Play(unsigned int nPhoneme)
g_nCurrentActivePhoneme = nPhoneme; g_nCurrentActivePhoneme = nPhoneme;
hr = SSI263Voice[g_nCurrentActivePhoneme].lpDSBvoice->SetCurrentPosition(0);
if(FAILED(hr))
return;
hr = SSI263Voice[g_nCurrentActivePhoneme].lpDSBvoice->Play(0,0,0); // Not looping hr = SSI263Voice[g_nCurrentActivePhoneme].lpDSBvoice->Play(0,0,0); // Not looping
if(FAILED(hr)) if(FAILED(hr))
return; return;
@ -1449,7 +1450,7 @@ void MB_EndOfFrame()
if(g_SoundcardType == SC_NONE) if(g_SoundcardType == SC_NONE)
return; return;
if(!g_bFullSpeed && !g_bMBTimerIrqActive && !(g_MB[0].sy6522.IFR & TIMER1)) if(!g_bFullSpeed && !g_bMBTimerIrqActive && !(g_MB[0].sy6522.IFR & IxR_TIMER1))
MB_Update(); MB_Update();
} }
@ -1478,9 +1479,11 @@ void MB_UpdateCycles(USHORT nClocks)
if( bTimer1Underflow && (g_nMBTimerDevice == i) && g_bMBTimerIrqActive ) if( bTimer1Underflow && (g_nMBTimerDevice == i) && g_bMBTimerIrqActive )
{ {
pMB->sy6522.IFR |= TIMER1; g_uTimer1IrqCount++; // DEBUG
pMB->sy6522.IFR |= IxR_TIMER1;
UpdateIFR(pMB); UpdateIFR(pMB);
CpuIRQ();
if((pMB->sy6522.ACR & RUNMODE) == RM_ONESHOT) if((pMB->sy6522.ACR & RUNMODE) == RM_ONESHOT)
{ {
// One-shot mode // One-shot mode
@ -1524,7 +1527,7 @@ void MB_SetSoundcardType(eSOUNDCARDTYPE NewSoundcardType)
double MB_GetFramePeriod() double MB_GetFramePeriod()
{ {
return (g_bMBTimerIrqActive||(g_MB[0].sy6522.IFR & TIMER1)) ? (double)g_n6522TimerPeriod : g_f6522TimerPeriod_NoIRQ; return (g_bMBTimerIrqActive||(g_MB[0].sy6522.IFR & IxR_TIMER1)) ? (double)g_n6522TimerPeriod : g_f6522TimerPeriod_NoIRQ;
} }
bool MB_IsActive() bool MB_IsActive()
@ -1606,15 +1609,18 @@ DWORD MB_SetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD /*dwSlot*/)
// //
// Crude - currently only support a single speech chip // 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.DurationPhonome) if(pMB->SpeechChip.DurationPhonome)
{ {
g_nSSI263Device = nDeviceNum; g_nSSI263Device = nDeviceNum;
if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C) && (pMB->sy6522.IER & PERIPHERAL)) if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C) && (pMB->sy6522.IER & IxR_PERIPHERAL))
{ {
pMB->sy6522.IFR |= PERIPHERAL; pMB->sy6522.IFR |= IxR_PERIPHERAL;
UpdateIFR(pMB); UpdateIFR(pMB);
CpuIRQ(); pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
} }
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
extern bool g_bMBTimerIrqActive; extern bool g_bMBTimerIrqActive;
extern UINT32 g_uTimer1IrqCount; // DEBUG
void MB_Initialize(); void MB_Initialize();
void MB_Reinitialize(); void MB_Reinitialize();

View File

@ -1,4 +1,6 @@
// // Structs used by save-state file
// *** DON'T CHANGE ANY STRUCT WITHOUT CONSIDERING BACKWARDS COMPATIBILITY WITH .AWS FORMAT ***
#define MAKE_VERSION(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | (d)) #define MAKE_VERSION(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | (d))
@ -34,6 +36,8 @@ typedef struct
// IRQ = OR-sum of all interrupt sources // IRQ = OR-sum of all interrupt sources
} SS_CPU6502; } SS_CPU6502;
const UINT uRecvBufferSize = 9;
typedef struct typedef struct
{ {
DWORD baudrate; DWORD baudrate;
@ -42,7 +46,7 @@ typedef struct
DWORD comminactivity; // If non-zero then COM port open DWORD comminactivity; // If non-zero then COM port open
BYTE controlbyte; BYTE controlbyte;
BYTE parity; BYTE parity;
BYTE recvbuffer[9]; BYTE recvbuffer[uRecvBufferSize];
DWORD recvbytes; DWORD recvbytes;
BYTE stopbits; BYTE stopbits;
} SS_IO_Comms; } SS_IO_Comms;
@ -232,7 +236,7 @@ typedef struct
BYTE CtrlArtAmp; BYTE CtrlArtAmp;
BYTE FilterFreq; BYTE FilterFreq;
// //
BYTE CurrentMode; BYTE CurrentMode; // b7:6=Mode; b0=D7 pin (for IRQ)
} SSI263A; } SSI263A;
typedef struct typedef struct