mirror of
https://github.com/AppleWin/AppleWin.git
synced 2025-02-28 19:30:11 +00:00
Merge from Tom branch to trunk
. Mouse interface now implemented & selectable from UI . Scroll Lock toggle also configurable from UI
This commit is contained in:
parent
9d5c56bc1c
commit
1c5ee1302b
@ -209,6 +209,14 @@
|
||||
Name="Source"
|
||||
Filter=".cpp"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\source\6821.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\source\6821.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\source\Applewin.cpp"
|
||||
>
|
||||
@ -305,6 +313,14 @@
|
||||
RelativePath=".\source\Mockingboard.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\source\MouseInterface.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\source\MouseInterface.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\source\ParallelPrinter.cpp"
|
||||
>
|
||||
@ -673,6 +689,10 @@
|
||||
RelativePath=".\source\Common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\resource\MouseInterface.rom"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\resource\resource.h"
|
||||
>
|
||||
|
@ -75,10 +75,10 @@ IDB_DEBUG_FONT_7X8 BITMAP "Debug_Font.bmp"
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_PROPPAGE_CONFIG DIALOG 0, 0, 210, 221
|
||||
IDD_PROPPAGE_CONFIG DIALOGEX 0, 0, 210, 221
|
||||
STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Configuration"
|
||||
FONT 8, "MS Sans Serif"
|
||||
FONT 8, "MS Sans Serif", 0, 0, 0x0
|
||||
BEGIN
|
||||
GROUPBOX "Emulation Speed Control",IDC_STATIC,5,115,200,85
|
||||
CONTROL "Use &Authentic Machine Speed",IDC_AUTHENTIC_SPEED,
|
||||
@ -98,6 +98,7 @@ BEGIN
|
||||
COMBOBOX IDC_SERIALPORT,45,48,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Monochrome Color...",IDC_MONOCOLOR,15,90,80,14
|
||||
PUSHBUTTON "Ethernet Settings...",IDC_ETHERNET,15,70,78,14
|
||||
CONTROL "Mouse interface in slot 4",IDC_MOUSE_IN_SLOT4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,15,206,106,10
|
||||
END
|
||||
|
||||
IDD_PROPPAGE_INPUT DIALOGEX 0, 0, 210, 221
|
||||
@ -117,6 +118,8 @@ BEGIN
|
||||
LTEXT "Y-trim:",IDC_STATIC,115,72,28,8
|
||||
CTEXT "0",IDC_STATIC,137,65,24,20,SS_CENTERIMAGE
|
||||
CONTROL "Spin1",IDC_SPIN_YTRIM,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNLEFT | UDS_AUTOBUDDY,161,69,10,14
|
||||
CONTROL "Scroll Lock acts as toggle for full-speed CPU",IDC_SCROLLLOCK_TOGGLE,
|
||||
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,114,166,10
|
||||
LTEXT "(Shift+Insert during emulation)",IDC_STATIC,89,166,94,8
|
||||
END
|
||||
|
||||
@ -207,8 +210,8 @@ DISK_ICON ICON "DISK.ICO"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,13,2,0
|
||||
PRODUCTVERSION 1,13,2,0
|
||||
FILEVERSION 1,13,3,0
|
||||
PRODUCTVERSION 1,13,3,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@ -226,12 +229,12 @@ BEGIN
|
||||
VALUE "Comments", "http://applewin.berlios.de"
|
||||
VALUE "CompanyName", "Michael O'Brien, Oliver Schmidt, Tom Charlesworth"
|
||||
VALUE "FileDescription", "Apple //e Emulator for Windows"
|
||||
VALUE "FileVersion", "1, 13, 2, 0"
|
||||
VALUE "FileVersion", "1, 13, 3, 0"
|
||||
VALUE "InternalName", "APPLEWIN"
|
||||
VALUE "LegalCopyright", "© 1994-2007 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, 13, 2, 0"
|
||||
VALUE "ProductVersion", "1, 13, 3, 0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
@ -263,6 +266,7 @@ IDR_SSC_FW FIRMWARE "SSC.rom"
|
||||
IDR_HDDRVR_FW FIRMWARE "Hddrvr.bin"
|
||||
IDR_PRINTDRVR_FW FIRMWARE "Parallel.rom"
|
||||
IDR_MOCKINGBOARD_D_FW FIRMWARE "Mockingboard-D.rom"
|
||||
IDR_MOUSEINTERFACE_FW FIRMWARE "MouseInterface.rom"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@ -272,7 +276,7 @@ IDR_MOCKINGBOARD_D_FW FIRMWARE "Mockingboard-D.rom"
|
||||
IDR_APPLE2_ROM ROM "Apple2.rom"
|
||||
IDR_APPLE2_PLUS_ROM ROM "Apple2_Plus.rom"
|
||||
IDR_APPLE2E_ROM ROM "Apple2e.rom"
|
||||
IDR_APPLE2E_ENHANCED_ROM ROM "Apple2e_Enhanced.rom"
|
||||
IDR_APPLE2E_ENHANCED_ROM ROM "Apple2e_Enhanced.rom"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -38,6 +38,7 @@
|
||||
#define IDR_DISK2_FW 133
|
||||
#define IDR_SSC_FW 134
|
||||
#define IDR_MOCKINGBOARD_D_FW 135
|
||||
#define IDR_MOUSEINTERFACE_FW 136
|
||||
#define IDC_KEYB_BUFFER_ENABLE 1005
|
||||
#define IDC_SAVESTATE 1006
|
||||
#define IDC_SAVESTATE_ON_EXIT 1007
|
||||
@ -72,6 +73,8 @@
|
||||
#define IDS_OK 1040
|
||||
#define IDS_CANCEL 1041
|
||||
#define IDC_ETHERNET 1042
|
||||
#define IDC_SCROLLLOCK_TOGGLE 1043
|
||||
#define IDC_MOUSE_IN_SLOT4 1044
|
||||
#define IDM_EXIT 40001
|
||||
#define IDM_HELP 40002
|
||||
#define IDM_ABOUT 40003
|
||||
@ -84,9 +87,9 @@
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NO_MFC 1
|
||||
#define _APS_NEXT_RESOURCE_VALUE 136
|
||||
#define _APS_NEXT_RESOURCE_VALUE 137
|
||||
#define _APS_NEXT_COMMAND_VALUE 40007
|
||||
#define _APS_NEXT_CONTROL_VALUE 1043
|
||||
#define _APS_NEXT_CONTROL_VALUE 1045
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
531
source/6821.cpp
Normal file
531
source/6821.cpp
Normal file
@ -0,0 +1,531 @@
|
||||
// Based on MAME's 6821pia.c
|
||||
// - by Kyle Kim (Apple in PC)
|
||||
|
||||
//
|
||||
// From mame.txt (http://www.mame.net/readme.html)
|
||||
//
|
||||
// VI. Reuse of Source Code
|
||||
// --------------------------
|
||||
// This chapter might not apply to specific portions of MAME (e.g. CPU
|
||||
// emulators) which bear different copyright notices.
|
||||
// The source code cannot be used in a commercial product without the written
|
||||
// authorization of the authors. Use in non-commercial products is allowed, and
|
||||
// indeed encouraged. If you use portions of the MAME source code in your
|
||||
// program, however, you must make the full source code freely available as
|
||||
// well.
|
||||
// Usage of the _information_ contained in the source code is free for any use.
|
||||
// However, given the amount of time and energy it took to collect this
|
||||
// information, if you find new information we would appreciate if you made it
|
||||
// freely available as well.
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "6821.h"
|
||||
|
||||
// Ctrl-A(B) register bit mask define
|
||||
/*
|
||||
0 1
|
||||
bit0 IRQ1_DISABLED IRQ1_ENABLED
|
||||
bit1 C1_HIGH_TO_LOW C1_LOW_TO_HIGH
|
||||
bit2 DDR_SELECTED OUTPUT_SELECTED
|
||||
|
||||
bit3 RESET_C2 SET_C2 ( C2_OUTPUT & C2_SETMODE )
|
||||
bit3 STROBE_C1_RESET STROBE_E_RESET ( C2_OUTPUT & C2_STROBE_MODE )
|
||||
bit4 C2_STROBE_MODE C2_SETMODE ( C2_OUTPUT )
|
||||
|
||||
bit3 IRQ2_DISABLED IRQ2_ENABLED ( C2_INPUT )
|
||||
bit4 C2_HIGH_TO_LOW C2_HIGH_TO_LOW ( C2_INPUT )
|
||||
bit5 C2_INPUT C2_OUTPUT
|
||||
*/
|
||||
#define PIA_IRQ1 0x80
|
||||
#define PIA_IRQ2 0x40
|
||||
#define SET_IRQ1(c) c |= PIA_IRQ1;
|
||||
#define SET_IRQ2(c) c |= PIA_IRQ2;
|
||||
#define CLEAR_IRQ1(c) c &= ~PIA_IRQ1;
|
||||
#define CLEAR_IRQ2(c) c &= ~PIA_IRQ2;
|
||||
#define IRQ1(c) ( c & PIA_IRQ1 )
|
||||
#define IRQ2(c) ( c & PIA_IRQ2 )
|
||||
|
||||
#define IRQ1_ENABLED(c) ( c & 0x01 )
|
||||
#define IRQ1_DISABLED(c) !( c & 0x01 )
|
||||
#define C1_LOW_TO_HIGH(c) ( c & 0x02 )
|
||||
#define C1_HIGH_TO_LOW(c) !( c & 0x02 )
|
||||
#define OUTPUT_SELECTED(c) ( c & 0x04 )
|
||||
#define DDR_SELECTED(c) !( c & 0x04 )
|
||||
#define IRQ2_ENABLED(c) ( c & 0x08 )
|
||||
#define IRQ2_DISABLED(c) !( c & 0x08 )
|
||||
#define STROBE_E_RESET(c) ( c & 0x08 )
|
||||
#define STROBE_C1_RESET(c) !( c & 0x08 )
|
||||
#define SET_C2(c) ( c & 0x08 )
|
||||
#define RESET_C2(c) !( c & 0x08 )
|
||||
#define C2_LOW_TO_HIGH(c) ( c & 0x10 )
|
||||
#define C2_HIGH_TO_LOW(c) !( c & 0x10 )
|
||||
#define C2_SET_MODE(c) ( c & 0x10 )
|
||||
#define C2_STROBE_MODE(c) !( c & 0x10 )
|
||||
#define C2_OUTPUT(c) ( c & 0x20 )
|
||||
#define C2_INPUT(c) !( c & 0x20 )
|
||||
|
||||
#define PIA_W_CALLBACK(st, val) \
|
||||
if ( st.func ) st.func( this, st.objTo, 0, val )
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
C6821::C6821()
|
||||
{
|
||||
Reset();
|
||||
m_stOutA.objTo = NULL;
|
||||
m_stOutA.func = NULL;
|
||||
m_stOutB.objTo = NULL;
|
||||
m_stOutB.func = NULL;
|
||||
m_stOutCA2.objTo = NULL;
|
||||
m_stOutCA2.func = NULL;
|
||||
m_stOutCB2.objTo = NULL;
|
||||
m_stOutCB2.func = NULL;
|
||||
m_stOutIRQA.objTo = NULL;
|
||||
m_stOutIRQA.func = NULL;
|
||||
m_stOutIRQB.objTo = NULL;
|
||||
m_stOutIRQB.func = NULL;
|
||||
}
|
||||
|
||||
C6821::~C6821()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void C6821::SetListenerA(void *objTo, mem_write_handler func)
|
||||
{
|
||||
m_stOutA.objTo = objTo;
|
||||
m_stOutA.func = func;
|
||||
}
|
||||
|
||||
void C6821::SetListenerB(void *objTo, mem_write_handler func)
|
||||
{
|
||||
m_stOutB.objTo = objTo;
|
||||
m_stOutB.func = func;
|
||||
}
|
||||
|
||||
void C6821::SetListenerCA2(void *objTo, mem_write_handler func)
|
||||
{
|
||||
m_stOutCA2.objTo = objTo;
|
||||
m_stOutCA2.func = func;
|
||||
}
|
||||
|
||||
void C6821::SetListenerCB2(void *objTo, mem_write_handler func)
|
||||
{
|
||||
m_stOutCB2.objTo = objTo;
|
||||
m_stOutCB2.func = func;
|
||||
}
|
||||
|
||||
BYTE C6821::Read(BYTE byRS)
|
||||
{
|
||||
BYTE retval = 0;
|
||||
byRS &= 3;
|
||||
switch ( byRS )
|
||||
{
|
||||
/******************* port A output/DDR read *******************/
|
||||
case PIA_DDRA:
|
||||
// read output register
|
||||
if ( OUTPUT_SELECTED(m_byCTLA) )
|
||||
{
|
||||
// combine input and output values
|
||||
retval = ( m_byOA & m_byDDRA ) | ( m_byIA & ~m_byDDRA );
|
||||
// IRQ flags implicitly cleared by a read
|
||||
CLEAR_IRQ1( m_byCTLA );
|
||||
CLEAR_IRQ1( m_byCTLB );
|
||||
UpdateInterrupts();
|
||||
// CA2 is configured as output and in read strobe mode
|
||||
if ( C2_OUTPUT(m_byCTLA) && C2_STROBE_MODE(m_byCTLA) )
|
||||
{
|
||||
// this will cause a transition low; call the output function if we're currently high
|
||||
if ( m_byOCA2 )
|
||||
PIA_W_CALLBACK( m_stOutCA2, 0 );
|
||||
m_byOCA2 = 0;
|
||||
|
||||
// if the CA2 strobe is cleared by the E, reset it right away
|
||||
if ( STROBE_E_RESET( m_byCTLA ) )
|
||||
{
|
||||
PIA_W_CALLBACK( m_stOutCA2, 1 );
|
||||
m_byOCA2 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// read DDR register
|
||||
else
|
||||
{
|
||||
retval = m_byDDRA;
|
||||
}
|
||||
break;
|
||||
|
||||
/******************* port B output/DDR read *******************/
|
||||
case PIA_DDRB:
|
||||
|
||||
// read output register
|
||||
if ( OUTPUT_SELECTED( m_byCTLB ) )
|
||||
{
|
||||
// combine input and output values
|
||||
retval = ( m_byOB & m_byDDRB ) + ( m_byIB & ~m_byDDRB );
|
||||
|
||||
// IRQ flags implicitly cleared by a read
|
||||
CLEAR_IRQ2( m_byCTLA );
|
||||
CLEAR_IRQ2( m_byCTLB );
|
||||
UpdateInterrupts();
|
||||
}
|
||||
/* read DDR register */
|
||||
else
|
||||
{
|
||||
retval = m_byDDRB;
|
||||
}
|
||||
break;
|
||||
|
||||
/******************* port A control read *******************/
|
||||
case PIA_CTLA:
|
||||
// read control register
|
||||
retval = m_byCTLA;
|
||||
// when CA2 is an output, IRQA2 = 0, and is not affected by CA2 transitions.
|
||||
if ( C2_OUTPUT( m_byCTLA ) )
|
||||
retval &= ~PIA_IRQ2;
|
||||
break;
|
||||
|
||||
/******************* port B control read *******************/
|
||||
case PIA_CTLB:
|
||||
retval = m_byCTLB;
|
||||
// when CB2 is an output, IRQB2 = 0, and is not affected by CB2 transitions.
|
||||
if ( C2_OUTPUT( m_byCTLB ) )
|
||||
retval &= ~PIA_IRQ2;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void C6821::Write(BYTE byRS, BYTE byData)
|
||||
{
|
||||
byRS &= 3;
|
||||
|
||||
switch( byRS )
|
||||
{
|
||||
/******************* port A output/DDR write *******************/
|
||||
case PIA_DDRA:
|
||||
|
||||
// write output register
|
||||
if ( OUTPUT_SELECTED( m_byCTLA ) )
|
||||
{
|
||||
// update the output value
|
||||
m_byOA = byData;
|
||||
|
||||
// send it to the output function
|
||||
if ( m_byDDRA )
|
||||
PIA_W_CALLBACK( m_stOutA, m_byOA & m_byDDRA );
|
||||
}
|
||||
|
||||
// write DDR register
|
||||
else
|
||||
{
|
||||
if ( m_byDDRA != byData )
|
||||
{
|
||||
m_byDDRA = byData;
|
||||
|
||||
// send it to the output function
|
||||
if ( m_byDDRA )
|
||||
PIA_W_CALLBACK( m_stOutA, m_byOA & m_byDDRA );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/******************* port B output/DDR write *******************/
|
||||
case PIA_DDRB:
|
||||
|
||||
// write output register
|
||||
if ( OUTPUT_SELECTED( m_byCTLB ) )
|
||||
{
|
||||
// update the output value
|
||||
m_byOB = byData;
|
||||
|
||||
// send it to the output function
|
||||
if ( m_byDDRB )
|
||||
PIA_W_CALLBACK( m_stOutB, m_byOB & m_byDDRB );
|
||||
|
||||
// CB2 is configured as output and in write strobe mode
|
||||
if ( C2_OUTPUT( m_byCTLB ) && C2_STROBE_MODE( m_byCTLB ) )
|
||||
{
|
||||
// this will cause a transition low; call the output function if we're currently high
|
||||
if ( m_byOCB2 )
|
||||
PIA_W_CALLBACK( m_stOutCB2, 0 );
|
||||
m_byOCB2 = 0;
|
||||
|
||||
// if the CB2 strobe is cleared by the E, reset it right away
|
||||
if ( STROBE_E_RESET( m_byCTLB ) )
|
||||
{
|
||||
PIA_W_CALLBACK( m_stOutCB2, 1 );
|
||||
m_byOCB2 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// write DDR register
|
||||
else
|
||||
{
|
||||
if ( m_byDDRB != byData )
|
||||
{
|
||||
m_byDDRB = byData;
|
||||
|
||||
// send it to the output function
|
||||
if ( m_byDDRB )
|
||||
PIA_W_CALLBACK( m_stOutB, m_byOB & m_byDDRB );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/******************* port A control write *******************/
|
||||
case PIA_CTLA:
|
||||
// Bit 7 and 6 read only
|
||||
byData &= 0x3f;
|
||||
|
||||
// CA2 is configured as output and in set/reset mode
|
||||
if ( C2_OUTPUT( byData ) )
|
||||
{
|
||||
// determine the new value
|
||||
int temp = SET_C2( byData ) ? 1 : 0;
|
||||
|
||||
// if this creates a transition, call the CA2 output function
|
||||
if ( m_byOCA2 ^ temp)
|
||||
PIA_W_CALLBACK( m_stOutCA2, temp );
|
||||
|
||||
// set the new value
|
||||
m_byOCA2 = temp;
|
||||
}
|
||||
|
||||
// update the control register
|
||||
m_byCTLA = ( m_byCTLA & ~0x3F ) | byData;
|
||||
|
||||
// update externals
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
|
||||
/******************* port B control write *******************/
|
||||
case PIA_CTLB:
|
||||
|
||||
/* Bit 7 and 6 read only - PD 16/01/00 */
|
||||
|
||||
byData &= 0x3f;
|
||||
|
||||
// CB2 is configured as output and in set/reset mode
|
||||
if ( C2_OUTPUT( byData ) )
|
||||
{
|
||||
// determine the new value
|
||||
int temp = SET_C2( byData ) ? 1 : 0;
|
||||
|
||||
// if this creates a transition, call the CA2 output function
|
||||
if ( m_byOCB2 ^ temp)
|
||||
PIA_W_CALLBACK( m_stOutCB2, temp );
|
||||
|
||||
// set the new value
|
||||
m_byOCB2 = temp;
|
||||
}
|
||||
|
||||
// update the control register
|
||||
m_byCTLB = ( m_byCTLB & ~0x3F ) | byData;
|
||||
|
||||
// update externals
|
||||
UpdateInterrupts();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void C6821::Reset()
|
||||
{
|
||||
m_byIA = 0;
|
||||
m_byCA1 = 0;
|
||||
m_byICA2 = 0;
|
||||
m_byOA = 0;
|
||||
m_byOCA2 = 0;
|
||||
m_byDDRA = 0;
|
||||
m_byCTLA = 0;
|
||||
m_byIRQAState = 0;
|
||||
|
||||
m_byIB = 0;
|
||||
m_byCB1 = 0;
|
||||
m_byICB2 = 0;
|
||||
m_byOB = 0;
|
||||
m_byOCB2 = 0;
|
||||
m_byDDRB = 0;
|
||||
m_byCTLB = 0;
|
||||
m_byIRQBState = 0;
|
||||
}
|
||||
|
||||
void C6821::UpdateInterrupts()
|
||||
{
|
||||
BYTE byNewState;
|
||||
|
||||
// start with IRQ A
|
||||
byNewState = 0;
|
||||
if ( ( IRQ1( m_byCTLA ) && IRQ1_ENABLED( m_byCTLA ) ) ||
|
||||
( IRQ2( m_byCTLA ) && IRQ2_ENABLED( m_byCTLA ) ) )
|
||||
byNewState = 1;
|
||||
|
||||
if ( byNewState != m_byIRQAState )
|
||||
{
|
||||
m_byIRQAState = byNewState;
|
||||
PIA_W_CALLBACK( m_stOutIRQA, m_byIRQAState );
|
||||
}
|
||||
|
||||
/* then do IRQ B */
|
||||
byNewState = 0;
|
||||
if ( ( IRQ1( m_byCTLB ) && IRQ1_ENABLED( m_byCTLB ) ) ||
|
||||
( IRQ2( m_byCTLB ) && IRQ2_ENABLED( m_byCTLB ) ) )
|
||||
byNewState = 1;
|
||||
|
||||
if ( byNewState != m_byIRQBState )
|
||||
{
|
||||
m_byIRQBState = byNewState;
|
||||
PIA_W_CALLBACK( m_stOutIRQB, m_byIRQBState );
|
||||
}
|
||||
}
|
||||
|
||||
void C6821::SetCA1(BYTE byData)
|
||||
{
|
||||
byData = byData ? 1 : 0;
|
||||
|
||||
// the new state has caused a transition
|
||||
if ( m_byCA1 ^ byData )
|
||||
{
|
||||
// handle the active transition
|
||||
if ( ( byData && C1_LOW_TO_HIGH( m_byCTLA ) ) ||
|
||||
( !byData && C1_HIGH_TO_LOW( m_byCTLA ) ) )
|
||||
{
|
||||
// mark the IRQ
|
||||
SET_IRQ1(m_byCTLA);
|
||||
|
||||
// update externals
|
||||
UpdateInterrupts();
|
||||
|
||||
// CA2 is configured as output and in read strobe mode and cleared by a CA1 transition
|
||||
if ( C2_OUTPUT( m_byCTLA ) && C2_STROBE_MODE( m_byCTLA ) && STROBE_C1_RESET( m_byCTLA ) )
|
||||
{
|
||||
// call the CA2 output function
|
||||
if ( !m_byOCA2 )
|
||||
PIA_W_CALLBACK( m_stOutCA2, 1 );
|
||||
|
||||
// clear CA2
|
||||
m_byOCA2 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set the new value for CA1
|
||||
m_byCA1 = byData;
|
||||
}
|
||||
|
||||
void C6821::SetCA2(BYTE byData)
|
||||
{
|
||||
byData = byData ? 1 : 0;
|
||||
|
||||
// CA2 is in input mode
|
||||
if ( C2_INPUT( m_byCTLA ) )
|
||||
{
|
||||
// the new state has caused a transition
|
||||
if ( m_byICA2 ^ byData )
|
||||
{
|
||||
// handle the active transition
|
||||
if ( ( byData && C2_LOW_TO_HIGH( m_byCTLA ) ) ||
|
||||
( !byData && C2_HIGH_TO_LOW( m_byCTLA ) ) )
|
||||
{
|
||||
// mark the IRQ
|
||||
SET_IRQ2( m_byCTLA );
|
||||
|
||||
// update externals
|
||||
UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set the new value for CA2
|
||||
m_byICA2 = byData;
|
||||
}
|
||||
|
||||
void C6821::SetCB1(BYTE byData)
|
||||
{
|
||||
byData = byData ? 1 : 0;
|
||||
|
||||
// the new state has caused a transition
|
||||
if ( m_byCB1 ^ byData )
|
||||
{
|
||||
// handle the active transition
|
||||
if ( ( byData && C1_LOW_TO_HIGH( m_byCTLB ) ) ||
|
||||
( !byData && C1_HIGH_TO_LOW( m_byCTLB ) ) )
|
||||
{
|
||||
// mark the IRQ
|
||||
SET_IRQ1( m_byCTLB );
|
||||
|
||||
// update externals
|
||||
UpdateInterrupts();
|
||||
|
||||
// CB2 is configured as output and in read strobe mode and cleared by a CA1 transition
|
||||
if ( C2_OUTPUT( m_byCTLB ) && C2_STROBE_MODE( m_byCTLB ) && STROBE_C1_RESET( m_byCTLB ) )
|
||||
{
|
||||
// the IRQ1 flag must have also been cleared
|
||||
if ( !IRQ1( m_byCTLB ) )
|
||||
{
|
||||
// call the CB2 output function
|
||||
if ( !m_byOCB2 )
|
||||
PIA_W_CALLBACK( m_stOutCB2, 1 );
|
||||
|
||||
// clear CB2
|
||||
m_byOCB2 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set the new value for CA1
|
||||
m_byCB1 = byData;
|
||||
|
||||
}
|
||||
|
||||
void C6821::SetCB2(BYTE byData)
|
||||
{
|
||||
byData = byData ? 1 : 0;
|
||||
|
||||
// CA2 is in input mode
|
||||
if ( C2_INPUT( m_byCTLB ) )
|
||||
{
|
||||
// the new state has caused a transition
|
||||
if ( m_byICB2 ^ byData )
|
||||
{
|
||||
// handle the active transition
|
||||
if ( ( byData && C2_LOW_TO_HIGH( m_byCTLB ) ) ||
|
||||
( !byData && C2_HIGH_TO_LOW( m_byCTLB ) ) )
|
||||
{
|
||||
// mark the IRQ
|
||||
SET_IRQ2( m_byCTLB );
|
||||
|
||||
// update externals
|
||||
UpdateInterrupts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set the new value for CA2
|
||||
m_byICB2 = byData;
|
||||
}
|
||||
|
||||
void C6821::SetPA(BYTE byData)
|
||||
{
|
||||
m_byIA = byData;
|
||||
}
|
||||
|
||||
void C6821::SetPB(BYTE byData)
|
||||
{
|
||||
m_byIB = byData;
|
||||
}
|
||||
|
||||
BYTE C6821::GetPA()
|
||||
{
|
||||
return m_byOA & m_byDDRA;
|
||||
}
|
||||
|
||||
BYTE C6821::GetPB()
|
||||
{
|
||||
return m_byOB & m_byDDRB;
|
||||
}
|
68
source/6821.h
Normal file
68
source/6821.h
Normal file
@ -0,0 +1,68 @@
|
||||
// Motorola MC6821 PIA
|
||||
|
||||
typedef void (*mem_write_handler) (void* objFrom, void* objTo, int nAddr, BYTE byData);
|
||||
|
||||
typedef struct _STWriteHandler
|
||||
{
|
||||
void* objTo;
|
||||
mem_write_handler func;
|
||||
} STWriteHandler;
|
||||
|
||||
//
|
||||
|
||||
#define PIA_DDRA 0
|
||||
#define PIA_CTLA 1
|
||||
#define PIA_DDRB 2
|
||||
#define PIA_CTLB 3
|
||||
|
||||
class C6821
|
||||
{
|
||||
public:
|
||||
C6821();
|
||||
virtual ~C6821();
|
||||
|
||||
BYTE GetPB();
|
||||
BYTE GetPA();
|
||||
void SetPB(BYTE byData);
|
||||
void SetPA(BYTE byData);
|
||||
void SetCA1( BYTE byData );
|
||||
void SetCA2( BYTE byData );
|
||||
void SetCB1( BYTE byData );
|
||||
void SetCB2( BYTE byData );
|
||||
void Reset();
|
||||
BYTE Read( BYTE byRS );
|
||||
void Write( BYTE byRS, BYTE byData );
|
||||
|
||||
void UpdateInterrupts();
|
||||
|
||||
void SetListenerA( void *objTo, mem_write_handler func );
|
||||
void SetListenerB( void *objTo, mem_write_handler func );
|
||||
void SetListenerCA2( void *objTo, mem_write_handler func );
|
||||
void SetListenerCB2( void *objTo, mem_write_handler func );
|
||||
|
||||
protected:
|
||||
BYTE m_byIA;
|
||||
BYTE m_byCA1;
|
||||
BYTE m_byICA2;
|
||||
BYTE m_byOA;
|
||||
BYTE m_byOCA2;
|
||||
BYTE m_byDDRA;
|
||||
BYTE m_byCTLA;
|
||||
BYTE m_byIRQAState;
|
||||
|
||||
BYTE m_byIB;
|
||||
BYTE m_byCB1;
|
||||
BYTE m_byICB2;
|
||||
BYTE m_byOB;
|
||||
BYTE m_byOCB2;
|
||||
BYTE m_byDDRB;
|
||||
BYTE m_byCTLB;
|
||||
BYTE m_byIRQBState;
|
||||
|
||||
STWriteHandler m_stOutA;
|
||||
STWriteHandler m_stOutB;
|
||||
STWriteHandler m_stOutCA2;
|
||||
STWriteHandler m_stOutCB2;
|
||||
STWriteHandler m_stOutIRQA;
|
||||
STWriteHandler m_stOutIRQB;
|
||||
};
|
@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#include "StdAfx.h"
|
||||
#pragma hdrstop
|
||||
#include "MouseInterface.h"
|
||||
|
||||
char VERSIONSTRING[] = "xx.yy.zz.ww";
|
||||
|
||||
@ -64,7 +65,10 @@ DWORD g_dwCyclesThisFrame = 0;
|
||||
FILE* g_fh = NULL;
|
||||
bool g_bDisableDirectSound = false;
|
||||
|
||||
CSuperSerialCard sg_SSC;
|
||||
CSuperSerialCard sg_SSC;
|
||||
CMouseInterface sg_Mouse;
|
||||
|
||||
UINT g_Slot4 = CT_Mockingboard; // CT_Mockingboard or CT_MouseInterface
|
||||
|
||||
//===========================================================================
|
||||
|
||||
@ -95,8 +99,12 @@ void ContinueExecution()
|
||||
|
||||
//
|
||||
|
||||
bool bScrollLock_FullSpeed = g_uScrollLockToggle
|
||||
? g_bScrollLock_FullSpeed
|
||||
: (GetKeyState(VK_SCROLL) < 0);
|
||||
|
||||
g_bFullSpeed = ( (g_dwSpeed == SPEED_MAX) ||
|
||||
(GetKeyState(VK_SCROLL) < 0) ||
|
||||
bScrollLock_FullSpeed ||
|
||||
(DiskIsSpinning() && enhancedisk && !Spkr_IsActive() && !MB_IsActive()) );
|
||||
|
||||
if(g_bFullSpeed)
|
||||
@ -198,7 +206,7 @@ void ContinueExecution()
|
||||
pageflipping--;
|
||||
}
|
||||
|
||||
MB_EndOfFrame();
|
||||
MB_EndOfVideoFrame();
|
||||
}
|
||||
|
||||
//
|
||||
@ -390,6 +398,10 @@ void LoadConfiguration ()
|
||||
|
||||
DWORD dwTmp;
|
||||
|
||||
if(LOAD(TEXT(REGVALUE_MOUSE_IN_SLOT4), &dwTmp))
|
||||
g_uMouseInSlot4 = dwTmp;
|
||||
g_Slot4 = g_uMouseInSlot4 ? CT_MouseInterface : CT_Mockingboard;
|
||||
|
||||
if(LOAD(TEXT(REGVALUE_SPKR_VOLUME), &dwTmp))
|
||||
SpkrSetVolume(dwTmp, PSP_GetVolumeMax());
|
||||
|
||||
@ -416,6 +428,9 @@ void LoadConfiguration ()
|
||||
if(LOAD(TEXT(REGVALUE_PDL_YTRIM), &dwTmp))
|
||||
JoySetTrim((short)dwTmp, false);
|
||||
|
||||
if(LOAD(TEXT(REGVALUE_SCROLLLOCK_TOGGLE), &dwTmp))
|
||||
g_uScrollLockToggle = dwTmp;
|
||||
|
||||
//
|
||||
|
||||
char szFilename[MAX_PATH] = {0};
|
||||
@ -706,7 +721,9 @@ int APIENTRY WinMain (HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
|
||||
|
||||
// ENTER THE MAIN MESSAGE LOOP
|
||||
EnterMessageLoop();
|
||||
|
||||
MB_Reset();
|
||||
sg_Mouse.Uninitialize(); // Maybe restarting due to switching slot-4 card from mouse to MB
|
||||
}
|
||||
while (restart);
|
||||
|
||||
|
@ -33,4 +33,6 @@ extern DWORD g_dwCyclesThisFrame;
|
||||
extern FILE* g_fh; // Filehandle for log file
|
||||
extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (so no MB support)
|
||||
|
||||
extern UINT g_Slot4; // Mockingboard or Mouse in slot4
|
||||
|
||||
void SetCurrentCLK6502();
|
||||
|
201
source/CPU.cpp
201
source/CPU.cpp
@ -86,6 +86,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#include "StdAfx.h"
|
||||
#pragma hdrstop
|
||||
#include "MouseInterface.h"
|
||||
|
||||
#define AF_SIGN 0x80
|
||||
#define AF_OVERFLOW 0x40
|
||||
@ -112,7 +113,11 @@ unsigned __int64 g_nCumulativeCycles = 0;
|
||||
static ULONG g_nCyclesSubmitted; // Number of cycles submitted to CpuExecute()
|
||||
static ULONG g_nCyclesExecuted;
|
||||
|
||||
static signed long g_uInternalExecutedCycles;
|
||||
//static signed long g_uInternalExecutedCycles;
|
||||
// TODO: Use IRQ_CHECK_TIMEOUT=128 when running at full-speed else with IRQ_CHECK_TIMEOUT=1
|
||||
// - What about when running benchmark?
|
||||
static const int IRQ_CHECK_TIMEOUT = 128;
|
||||
static signed int g_nIrqCheckTimeout = IRQ_CHECK_TIMEOUT;
|
||||
|
||||
//
|
||||
|
||||
@ -143,7 +148,7 @@ static volatile BOOL g_bNmiFlank = FALSE; // Positive going flank on NMI line
|
||||
| (flagz ? AF_ZERO : 0) \
|
||||
| AF_RESERVED | AF_BREAK;
|
||||
// CYC(a): This can be optimised, as only certain opcodes will affect uExtraCycles
|
||||
#define CYC(a) uExecutedCycles += (a)+uExtraCycles; MB_UpdateCycles((a)+uExtraCycles);
|
||||
#define CYC(a) uExecutedCycles += (a)+uExtraCycles; g_nIrqCheckTimeout -= (a)+uExtraCycles;
|
||||
#define POP (*(mem+((regs.sp >= 0x1FF) ? (regs.sp = 0x100) : ++regs.sp)))
|
||||
#define PUSH(a) *(mem+regs.sp--) = (a); \
|
||||
if (regs.sp < 0x100) \
|
||||
@ -227,6 +232,10 @@ static volatile BOOL g_bNmiFlank = FALSE; // Positive going flank on NMI line
|
||||
else \
|
||||
addr = *(LPWORD)(mem+base);
|
||||
#define REL addr = (signed char)*(mem+regs.pc++);
|
||||
|
||||
// Optimiation note:
|
||||
// . Opcodes that generate zero-page addresses can't be accessing $C000..$CFFF
|
||||
// so they could be paired with special READZP/WRITEZP macros (instead of READ/WRITE)
|
||||
#define ZPG addr = *(mem+regs.pc++);
|
||||
#define ZPGX addr = ((*(mem+regs.pc++))+regs.x) & 0xFF;
|
||||
#define ZPGY addr = ((*(mem+regs.pc++))+regs.y) & 0xFF;
|
||||
@ -783,7 +792,7 @@ UINT g_nMean = 0;
|
||||
UINT g_nMin = 0xFFFFFFFF;
|
||||
UINT g_nMax = 0;
|
||||
|
||||
static inline void DoIrqProfiling(DWORD uCycles)
|
||||
static __forceinline void DoIrqProfiling(DWORD uCycles)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if(regs.ps & AF_INTERRUPT)
|
||||
@ -814,8 +823,75 @@ static inline void DoIrqProfiling(DWORD uCycles)
|
||||
|
||||
//===========================================================================
|
||||
|
||||
static __forceinline int Fetch(BYTE& iOpcode, ULONG uExecutedCycles)
|
||||
{
|
||||
//g_uInternalExecutedCycles = uExecutedCycles;
|
||||
|
||||
// iOpcode = *(mem+regs.pc);
|
||||
iOpcode = ((regs.pc & 0xF000) == 0xC000)
|
||||
? IORead[(regs.pc>>4) & 0xFF](regs.pc,regs.pc,0,0,uExecutedCycles) // Fetch opcode from I/O memory, but params are still from mem[]
|
||||
: *(mem+regs.pc);
|
||||
|
||||
if (CheckDebugBreak( iOpcode ))
|
||||
return 0;
|
||||
|
||||
regs.pc++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
//#define ENABLE_NMI_SUPPORT // Not used - so don't enable
|
||||
static __forceinline void NMI(ULONG& uExecutedCycles, UINT& uExtraCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz)
|
||||
{
|
||||
#ifdef ENABLE_NMI_SUPPORT
|
||||
if(g_bNmiFlank)
|
||||
{
|
||||
// NMI signals are only serviced once
|
||||
g_bNmiFlank = FALSE;
|
||||
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
|
||||
PUSH(regs.pc >> 8)
|
||||
PUSH(regs.pc & 0xFF)
|
||||
EF_TO_AF
|
||||
PUSH(regs.ps & ~AF_BREAK)
|
||||
regs.ps = regs.ps | AF_INTERRUPT & ~AF_DECIMAL;
|
||||
regs.pc = * (WORD*) (mem+0xFFFA);
|
||||
CYC(7)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static __forceinline void IRQ(ULONG& uExecutedCycles, UINT& uExtraCycles, BOOL& flagc, BOOL& flagn, BOOL& flagv, BOOL& flagz)
|
||||
{
|
||||
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 + uExecutedCycles;
|
||||
PUSH(regs.pc >> 8)
|
||||
PUSH(regs.pc & 0xFF)
|
||||
EF_TO_AF
|
||||
PUSH(regs.ps & ~AF_BREAK)
|
||||
regs.ps = regs.ps | AF_INTERRUPT & ~AF_DECIMAL;
|
||||
regs.pc = * (WORD*) (mem+0xFFFE);
|
||||
CYC(7)
|
||||
}
|
||||
}
|
||||
|
||||
static __forceinline void CheckInterruptSources(ULONG uExecutedCycles)
|
||||
{
|
||||
if (g_nIrqCheckTimeout < 0)
|
||||
{
|
||||
MB_UpdateCycles(uExecutedCycles);
|
||||
sg_Mouse.SetVBlank(VideoGetVbl(uExecutedCycles));
|
||||
g_nIrqCheckTimeout = IRQ_CHECK_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
static DWORD Cpu65C02 (DWORD uTotalCycles)
|
||||
{
|
||||
// Optimisation:
|
||||
// . Copy the global /regs/ vars to stack-based local vars
|
||||
// (Oliver Schmidt says this gives a performance gain, see email - The real deal: "1.10.5")
|
||||
WORD addr;
|
||||
BOOL flagc; // must always be 0 or 1, no other values allowed
|
||||
BOOL flagn; // must always be 0 or 0x80.
|
||||
@ -825,26 +901,19 @@ static DWORD Cpu65C02 (DWORD uTotalCycles)
|
||||
WORD temp2;
|
||||
WORD val;
|
||||
AF_TO_EF
|
||||
DWORD uExecutedCycles = 0;
|
||||
ULONG uExecutedCycles = 0;
|
||||
BOOL bSlowerOnPagecross; // Set if opcode writes to memory (eg. ASL, STA)
|
||||
WORD base;
|
||||
bool bBreakOnInvalid = false;
|
||||
bool bBreakOnInvalid = false;
|
||||
|
||||
do
|
||||
{
|
||||
g_uInternalExecutedCycles = uExecutedCycles;
|
||||
USHORT uExtraCycles = 0;
|
||||
UINT uExtraCycles = 0;
|
||||
BYTE iOpcode;
|
||||
|
||||
// BYTE iOpcode = *(mem+regs.pc);
|
||||
BYTE iOpcode = ((regs.pc & 0xF000) == 0xC000)
|
||||
? IORead[(regs.pc>>4) & 0xFF](regs.pc,regs.pc,0,0,uExecutedCycles) // Fetch opcode from I/O memory, but params are still from mem[]
|
||||
: *(mem+regs.pc);
|
||||
|
||||
if (CheckDebugBreak( iOpcode ))
|
||||
if (!Fetch(iOpcode, uExecutedCycles))
|
||||
break;
|
||||
|
||||
regs.pc++;
|
||||
|
||||
switch (iOpcode)
|
||||
{
|
||||
case 0x00: BRK CYC(7) break;
|
||||
@ -1105,32 +1174,10 @@ static DWORD Cpu65C02 (DWORD uTotalCycles)
|
||||
case 0xFF: INV NOP CYC(2) break;
|
||||
}
|
||||
|
||||
if(g_bNmiFlank)
|
||||
{
|
||||
// NMI signals are only serviced once
|
||||
g_bNmiFlank = FALSE;
|
||||
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
|
||||
PUSH(regs.pc >> 8)
|
||||
PUSH(regs.pc & 0xFF)
|
||||
EF_TO_AF
|
||||
PUSH(regs.ps & ~AF_BREAK)
|
||||
regs.ps = regs.ps | AF_INTERRUPT & ~AF_DECIMAL;
|
||||
regs.pc = * (WORD*) (mem+0xFFFA);
|
||||
CYC(7)
|
||||
}
|
||||
|
||||
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 + uExecutedCycles;
|
||||
PUSH(regs.pc >> 8)
|
||||
PUSH(regs.pc & 0xFF)
|
||||
EF_TO_AF
|
||||
PUSH(regs.ps & ~AF_BREAK)
|
||||
regs.ps = regs.ps | AF_INTERRUPT & ~AF_DECIMAL;
|
||||
regs.pc = * (WORD*) (mem+0xFFFE);
|
||||
CYC(7)
|
||||
}
|
||||
CheckInterruptSources(uExecutedCycles);
|
||||
NMI(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
|
||||
IRQ(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
|
||||
|
||||
if (bBreakOnInvalid)
|
||||
break;
|
||||
@ -1154,26 +1201,19 @@ static DWORD Cpu6502 (DWORD uTotalCycles)
|
||||
WORD temp2;
|
||||
WORD val;
|
||||
AF_TO_EF
|
||||
DWORD uExecutedCycles = 0;
|
||||
ULONG uExecutedCycles = 0;
|
||||
BOOL bSlowerOnPagecross; // Set if opcode writes to memory (eg. ASL, STA)
|
||||
WORD base;
|
||||
bool bBreakOnInvalid = false;
|
||||
|
||||
do
|
||||
{
|
||||
g_uInternalExecutedCycles = uExecutedCycles;
|
||||
USHORT uExtraCycles = 0;
|
||||
UINT uExtraCycles = 0;
|
||||
BYTE iOpcode;
|
||||
|
||||
// BYTE iOpcode = *(mem+regs.pc);
|
||||
BYTE iOpcode = ((regs.pc & 0xF000) == 0xC000)
|
||||
? IORead[(regs.pc>>4) & 0xFF](regs.pc,regs.pc,0,0,uExecutedCycles)
|
||||
: *(mem+regs.pc);
|
||||
|
||||
if (CheckDebugBreak( iOpcode ))
|
||||
if (!Fetch(iOpcode, uExecutedCycles))
|
||||
break;
|
||||
|
||||
regs.pc++;
|
||||
|
||||
switch (iOpcode)
|
||||
{
|
||||
case 0x00: BRK CYC(7) break;
|
||||
@ -1434,32 +1474,9 @@ static DWORD Cpu6502 (DWORD uTotalCycles)
|
||||
case 0xFF: INV ABSX INS CYC(7) break;
|
||||
}
|
||||
|
||||
if(g_bNmiFlank && !regs.bJammed)
|
||||
{
|
||||
// NMI signals are only serviced once
|
||||
g_bNmiFlank = FALSE;
|
||||
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
|
||||
PUSH(regs.pc >> 8)
|
||||
PUSH(regs.pc & 0xFF)
|
||||
EF_TO_AF
|
||||
PUSH(regs.ps & ~AF_BREAK)
|
||||
regs.ps = regs.ps | AF_INTERRUPT;
|
||||
regs.pc = * (WORD*) (mem+0xFFFA);
|
||||
CYC(7)
|
||||
}
|
||||
|
||||
if(g_bmIRQ && !(regs.ps & AF_INTERRUPT) && !regs.bJammed)
|
||||
{
|
||||
// IRQ signals are deasserted when a specific r/w operation is done on device
|
||||
g_nCycleIrqStart = g_nCumulativeCycles + uExecutedCycles;
|
||||
PUSH(regs.pc >> 8)
|
||||
PUSH(regs.pc & 0xFF)
|
||||
EF_TO_AF
|
||||
PUSH(regs.ps & ~AF_BREAK)
|
||||
regs.ps = regs.ps | AF_INTERRUPT;
|
||||
regs.pc = * (WORD*) (mem+0xFFFE);
|
||||
CYC(7)
|
||||
}
|
||||
CheckInterruptSources(uExecutedCycles);
|
||||
NMI(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
|
||||
IRQ(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
|
||||
|
||||
if (bBreakOnInvalid)
|
||||
break;
|
||||
@ -1502,10 +1519,11 @@ void CpuDestroy ()
|
||||
// g_nCyclesExecuted
|
||||
// g_nCumulativeCycles
|
||||
//
|
||||
void CpuCalcCycles(ULONG nCyclesExecuted)
|
||||
void CpuCalcCycles(ULONG nExecutedCycles)
|
||||
{
|
||||
// Calc # of cycles executed since this func was last called
|
||||
ULONG nCycles = nCyclesExecuted - g_nCyclesExecuted;
|
||||
ULONG nCycles = nExecutedCycles - g_nCyclesExecuted;
|
||||
_ASSERT( (LONG)nCycles >= 0 );
|
||||
|
||||
g_nCyclesExecuted += nCycles;
|
||||
g_nCumulativeCycles += nCycles;
|
||||
@ -1513,11 +1531,26 @@ void CpuCalcCycles(ULONG nCyclesExecuted)
|
||||
|
||||
//===========================================================================
|
||||
|
||||
ULONG CpuGetCyclesThisFrame()
|
||||
// Old method with g_uInternalExecutedCycles runs faster!
|
||||
// Old vs New
|
||||
// - 68.0,69.0MHz vs 66.7, 67.2MHz (with check for VBL IRQ every opcode)
|
||||
// - 89.6,88.9MHz vs 87.2, 87.9MHz (without check for VBL IRQ)
|
||||
// - 75.9, 78.5MHz (with check for VBL IRQ every 128 cycles)
|
||||
// - 137.9,135.6MHz (with check for VBL IRQ & MB_Update every 128 cycles)
|
||||
|
||||
#if 0 // TODO: Measure perf increase by using this new method
|
||||
ULONG CpuGetCyclesThisFrame(ULONG) // Old func using g_uInternalExecutedCycles
|
||||
{
|
||||
CpuCalcCycles(g_uInternalExecutedCycles);
|
||||
return g_dwCyclesThisFrame + g_nCyclesExecuted;
|
||||
}
|
||||
#else
|
||||
ULONG CpuGetCyclesThisFrame(ULONG nExecutedCycles)
|
||||
{
|
||||
CpuCalcCycles(nExecutedCycles);
|
||||
return g_dwCyclesThisFrame + g_nCyclesExecuted;
|
||||
}
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
|
||||
@ -1528,11 +1561,19 @@ DWORD CpuExecute (DWORD uCycles)
|
||||
g_nCyclesSubmitted = uCycles;
|
||||
g_nCyclesExecuted = 0;
|
||||
|
||||
//
|
||||
|
||||
MB_StartOfCpuExecute();
|
||||
|
||||
if (uCycles == 0) // Do single step
|
||||
uExecutedCycles = InternalCpuExecute(0);
|
||||
else // Do multi-opcode emulation
|
||||
uExecutedCycles = InternalCpuExecute(uCycles);
|
||||
|
||||
MB_UpdateCycles(uExecutedCycles); // Update 6522s (NB. Do this before updating g_nCumulativeCycles below)
|
||||
|
||||
//
|
||||
|
||||
UINT nRemainingCycles = uExecutedCycles - g_nCyclesExecuted;
|
||||
g_nCumulativeCycles += nRemainingCycles;
|
||||
|
||||
|
@ -14,9 +14,9 @@ extern regsrec regs;
|
||||
extern unsigned __int64 g_nCumulativeCycles;
|
||||
|
||||
void CpuDestroy ();
|
||||
void CpuCalcCycles(ULONG nCyclesLeft);
|
||||
void CpuCalcCycles(ULONG nExecutedCycles);
|
||||
DWORD CpuExecute (DWORD);
|
||||
ULONG CpuGetCyclesThisFrame();
|
||||
ULONG CpuGetCyclesThisFrame(ULONG nExecutedCycles);
|
||||
void CpuInitialize ();
|
||||
void CpuSetupBenchmark ();
|
||||
void CpuIrqReset();
|
||||
|
@ -80,6 +80,8 @@ enum AppMode_e
|
||||
#define REGVALUE_HDD_IMAGE2 "Harddisk Image 2"
|
||||
#define REGVALUE_PDL_XTRIM "PDL X-Trim"
|
||||
#define REGVALUE_PDL_YTRIM "PDL Y-Trim"
|
||||
#define REGVALUE_SCROLLLOCK_TOGGLE "ScrollLock Toggle"
|
||||
#define REGVALUE_MOUSE_IN_SLOT4 "Mouse in slot 4"
|
||||
|
||||
// Preferences
|
||||
#define REGVALUE_PREF_START_DIR TEXT("Starting Directory")
|
||||
@ -95,7 +97,7 @@ typedef BYTE (__stdcall *iofunction)(WORD nPC, WORD nAddr, BYTE nWriteFlag, BYTE
|
||||
|
||||
typedef struct _IMAGE__ { int unused; } *HIMAGE;
|
||||
|
||||
enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC};
|
||||
enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE};
|
||||
|
||||
//
|
||||
|
||||
@ -114,4 +116,7 @@ enum eApple2Type {
|
||||
A2TYPE_APPLE2EEHANCED,
|
||||
// A2TYPE_APPLE2C=APPLE2C_MASK, // Placeholder
|
||||
A2TYPE_MAX
|
||||
};
|
||||
};
|
||||
|
||||
enum eBUTTON {BUTTON0=0, BUTTON1};
|
||||
enum eBUTTONSTATE {BUTTON_UP=0, BUTTON_DOWN};
|
||||
|
@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#include "StdAfx.h"
|
||||
#pragma hdrstop
|
||||
#include "MouseInterface.h"
|
||||
#include "..\resource\resource.h"
|
||||
|
||||
#define ENABLE_MENU 0
|
||||
@ -90,6 +91,8 @@ void SetFullScreenMode ();
|
||||
void SetNormalMode ();
|
||||
void SetUsingCursor (BOOL);
|
||||
|
||||
bool g_bScrollLock_FullSpeed = false;
|
||||
|
||||
//===========================================================================
|
||||
void CreateGdiObjects () {
|
||||
ZeroMemory(buttonbitmap,BUTTONS*sizeof(HBITMAP));
|
||||
@ -609,7 +612,9 @@ LRESULT CALLBACK FrameWndProc (
|
||||
SoundCore_SetFade(FADE_IN);
|
||||
}
|
||||
else if (wparam == VK_CAPITAL)
|
||||
{
|
||||
KeybToggleCapsLock();
|
||||
}
|
||||
else if (wparam == VK_PAUSE)
|
||||
{
|
||||
SetUsingCursor(0);
|
||||
@ -632,6 +637,10 @@ LRESULT CALLBACK FrameWndProc (
|
||||
VideoRedrawScreen();
|
||||
g_bResetTiming = true;
|
||||
}
|
||||
else if ((wparam == VK_SCROLL) && g_uScrollLockToggle)
|
||||
{
|
||||
g_bScrollLock_FullSpeed = !g_bScrollLock_FullSpeed;
|
||||
}
|
||||
else if ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_LOGO) || (g_nAppMode == MODE_STEPPING))
|
||||
{
|
||||
// Note about Alt Gr (Right-Alt):
|
||||
@ -654,37 +663,53 @@ LRESULT CALLBACK FrameWndProc (
|
||||
break;
|
||||
|
||||
case WM_KEYUP:
|
||||
if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1)) {
|
||||
buttondown = -1;
|
||||
if (fullscreen)
|
||||
EraseButton(wparam-VK_F1);
|
||||
else
|
||||
DrawButton((HDC)0,wparam-VK_F1);
|
||||
ProcessButtonClick(wparam-VK_F1);
|
||||
}
|
||||
else
|
||||
JoyProcessKey((int)wparam,((lparam & 0x01000000) != 0),0,0);
|
||||
break;
|
||||
if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1))
|
||||
{
|
||||
buttondown = -1;
|
||||
if (fullscreen)
|
||||
EraseButton(wparam-VK_F1);
|
||||
else
|
||||
DrawButton((HDC)0,wparam-VK_F1);
|
||||
ProcessButtonClick(wparam-VK_F1);
|
||||
}
|
||||
else
|
||||
{
|
||||
JoyProcessKey((int)wparam,((lparam & 0x01000000) != 0),0,0);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
if (buttondown == -1) {
|
||||
if (buttondown == -1)
|
||||
{
|
||||
int x = LOWORD(lparam);
|
||||
int y = HIWORD(lparam);
|
||||
if ((x >= buttonx) &&
|
||||
(y >= buttony) &&
|
||||
(y <= buttony+BUTTONS*BUTTONCY)) {
|
||||
(y <= buttony+BUTTONS*BUTTONCY))
|
||||
{
|
||||
buttonactive = buttondown = (y-buttony-1)/BUTTONCY;
|
||||
DrawButton((HDC)0,buttonactive);
|
||||
SetCapture(window);
|
||||
}
|
||||
else if (usingcursor)
|
||||
{
|
||||
if (wparam & (MK_CONTROL | MK_SHIFT))
|
||||
{
|
||||
SetUsingCursor(0);
|
||||
}
|
||||
else
|
||||
JoySetButton(0,1);
|
||||
else if ((x < buttonx) && JoyUsingMouse() &&
|
||||
((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_STEPPING)))
|
||||
{
|
||||
if (sg_Mouse.Active())
|
||||
sg_Mouse.SetButton(BUTTON0, BUTTON_DOWN);
|
||||
else
|
||||
JoySetButton(BUTTON0, BUTTON_DOWN);
|
||||
}
|
||||
}
|
||||
else if ( ((x < buttonx) && JoyUsingMouse() && ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_STEPPING))) ||
|
||||
(sg_Mouse.Active()) )
|
||||
{
|
||||
SetUsingCursor(1);
|
||||
}
|
||||
DebuggerMouseClick( x, y );
|
||||
}
|
||||
RelayEvent(WM_LBUTTONDOWN,wparam,lparam);
|
||||
@ -704,7 +729,12 @@ LRESULT CALLBACK FrameWndProc (
|
||||
buttonactive = -1;
|
||||
}
|
||||
else if (usingcursor)
|
||||
JoySetButton(0,0);
|
||||
{
|
||||
if (sg_Mouse.Active())
|
||||
sg_Mouse.SetButton(BUTTON0, BUTTON_UP);
|
||||
else
|
||||
JoySetButton(BUTTON0, BUTTON_UP);
|
||||
}
|
||||
RelayEvent(WM_LBUTTONUP,wparam,lparam);
|
||||
break;
|
||||
|
||||
@ -730,10 +760,13 @@ LRESULT CALLBACK FrameWndProc (
|
||||
if (buttonover != -1)
|
||||
DrawButton((HDC)0,buttonover);
|
||||
}
|
||||
else if (usingcursor) {
|
||||
else if (usingcursor)
|
||||
{
|
||||
DrawCrosshairs(x,y);
|
||||
JoySetPosition(x-viewportx-2,VIEWPORTCX-4,
|
||||
y-viewporty-2,VIEWPORTCY-4);
|
||||
if (sg_Mouse.Active())
|
||||
sg_Mouse.SetPosition(x-viewportx-2, VIEWPORTCX-4, y-viewporty-2, VIEWPORTCY-4);
|
||||
else
|
||||
JoySetPosition(x-viewportx-2, VIEWPORTCX-4, y-viewporty-2, VIEWPORTCY-4);
|
||||
}
|
||||
RelayEvent(WM_MOUSEMOVE,wparam,lparam);
|
||||
break;
|
||||
@ -832,7 +865,10 @@ LRESULT CALLBACK FrameWndProc (
|
||||
}
|
||||
if (usingcursor)
|
||||
{
|
||||
JoySetButton(1,(message == WM_RBUTTONDOWN));
|
||||
if (sg_Mouse.Active())
|
||||
sg_Mouse.SetButton(BUTTON1, (message == WM_RBUTTONDOWN) ? BUTTON_DOWN : BUTTON_UP);
|
||||
else
|
||||
JoySetButton(BUTTON1, (message == WM_RBUTTONDOWN) ? BUTTON_DOWN : BUTTON_UP);
|
||||
}
|
||||
RelayEvent(message,wparam,lparam);
|
||||
break;
|
||||
|
@ -25,3 +25,5 @@ LRESULT CALLBACK FrameWndProc (
|
||||
UINT message,
|
||||
WPARAM wparam,
|
||||
LPARAM lparam );
|
||||
|
||||
extern bool g_bScrollLock_FullSpeed;
|
||||
|
@ -217,7 +217,6 @@ static LPCTSTR HD_DiskGetName (int nDrive)
|
||||
static BYTE __stdcall HD_IO_EMUL (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||
|
||||
static const DWORD HDDRVR_SIZE = 0x100;
|
||||
static LPBYTE lpMemC000 = NULL;
|
||||
|
||||
bool HD_CardIsEnabled()
|
||||
{
|
||||
@ -231,13 +230,14 @@ void HD_SetEnabled(bool bEnabled)
|
||||
|
||||
g_bHD_Enabled = bEnabled;
|
||||
|
||||
if(lpMemC000 == NULL) // This will be NULL when called after loading value from Registry
|
||||
LPBYTE pCxRomPeripheral = MemGetCxRomPeripheral();
|
||||
if(pCxRomPeripheral == NULL) // This will be NULL when called after loading value from Registry
|
||||
return;
|
||||
|
||||
if(g_bHD_Enabled)
|
||||
HD_Load_Rom(lpMemC000, g_uSlot);
|
||||
HD_Load_Rom(pCxRomPeripheral, g_uSlot);
|
||||
else
|
||||
memset(lpMemC000 + g_uSlot*256, 0, HDDRVR_SIZE);
|
||||
memset(pCxRomPeripheral + g_uSlot*256, 0, HDDRVR_SIZE);
|
||||
|
||||
RegisterIoHandler(g_uSlot, HD_IO_EMUL, HD_IO_EMUL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
@ -249,8 +249,6 @@ LPCTSTR HD_GetFullName (int nDrive)
|
||||
|
||||
VOID HD_Load_Rom(LPBYTE pCxRomPeripheral, UINT uSlot)
|
||||
{
|
||||
lpMemC000 = pCxRomPeripheral; // Keep a copy for HD_SetEnabled()
|
||||
|
||||
if(!g_bHD_Enabled)
|
||||
return;
|
||||
|
||||
|
@ -39,6 +39,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#include "StdAfx.h"
|
||||
#pragma hdrstop
|
||||
#include "MouseInterface.h"
|
||||
|
||||
#define BUTTONTIME 5000
|
||||
|
||||
@ -365,7 +366,7 @@ BOOL JoyProcessKey (int virtkey, BOOL extended, BOOL down, BOOL autorep)
|
||||
|
||||
//===========================================================================
|
||||
|
||||
BYTE __stdcall JoyReadButton (WORD, WORD address, BYTE, BYTE, ULONG)
|
||||
BYTE __stdcall JoyReadButton (WORD, WORD address, BYTE, BYTE, ULONG nCyclesLeft)
|
||||
{
|
||||
address &= 0xFF;
|
||||
|
||||
@ -397,7 +398,7 @@ BYTE __stdcall JoyReadButton (WORD, WORD address, BYTE, BYTE, ULONG)
|
||||
break;
|
||||
|
||||
}
|
||||
return MemReadFloatingBus(pressed);
|
||||
return MemReadFloatingBus(pressed, nCyclesLeft);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
@ -433,7 +434,7 @@ BYTE __stdcall JoyReadPosition (WORD programcounter, WORD address, BYTE, BYTE, U
|
||||
|
||||
BOOL nPdlCntrActive = g_nCumulativeCycles <= (g_nJoyCntrResetCycle + (unsigned __int64) ((double)nPdlPos * PDL_CNTR_INTERVAL));
|
||||
|
||||
return MemReadFloatingBus(nPdlCntrActive);
|
||||
return MemReadFloatingBus(nPdlCntrActive, nCyclesLeft);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
@ -455,13 +456,13 @@ BYTE __stdcall JoyResetPosition (WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft)
|
||||
if(joyinfo[joytype[1]].device == DEVICE_JOYSTICK)
|
||||
CheckJoystick1();
|
||||
|
||||
return MemReadFloatingBus();
|
||||
return MemReadFloatingBus(nCyclesLeft);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
// Called when mouse is being used as a joystick && mouse button changes
|
||||
void JoySetButton (int number, BOOL down)
|
||||
void JoySetButton (eBUTTON number, eBUTTONSTATE down)
|
||||
{
|
||||
if (number > 1) // Sanity check on mouse button #
|
||||
return;
|
||||
@ -473,7 +474,7 @@ void JoySetButton (int number, BOOL down)
|
||||
// If it is 2nd joystick that is being emulated with mouse, then re-map button #
|
||||
if(joyinfo[joytype[1]].device == DEVICE_MOUSE)
|
||||
{
|
||||
number = 1; // 2nd joystick controls Apple button #1
|
||||
number = BUTTON1; // 2nd joystick controls Apple button #1
|
||||
}
|
||||
|
||||
setbutton[number] = down;
|
||||
@ -507,6 +508,15 @@ BOOL JoySetEmulationType (HWND window, DWORD newtype, int nJoystickNumber)
|
||||
else if ((joyinfo[newtype].device == DEVICE_MOUSE) &&
|
||||
(joyinfo[joytype[nJoystickNumber]].device != DEVICE_MOUSE))
|
||||
{
|
||||
if (sg_Mouse.Active())
|
||||
{
|
||||
MessageBox(window,
|
||||
TEXT("Mouse interface card is enabled - unable to use mouse for joystick emulation."),
|
||||
TEXT("Configuration"),
|
||||
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
|
||||
return 0;
|
||||
}
|
||||
|
||||
MessageBox(window,
|
||||
TEXT("To begin emulating a joystick with your mouse, move ")
|
||||
TEXT("the mouse cursor over the emulated screen of a running ")
|
||||
|
@ -7,7 +7,7 @@ extern DWORD joytype[2];
|
||||
void JoyInitialize ();
|
||||
BOOL JoyProcessKey (int,BOOL,BOOL,BOOL);
|
||||
void JoyReset ();
|
||||
void JoySetButton (int,BOOL);
|
||||
void JoySetButton (eBUTTON,eBUTTONSTATE);
|
||||
BOOL JoySetEmulationType (HWND,DWORD,int);
|
||||
void JoySetPosition (int,int,int,int);
|
||||
void JoyUpdatePosition ();
|
||||
|
@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
#include "StdAfx.h"
|
||||
#pragma hdrstop
|
||||
#include "MouseInterface.h"
|
||||
#include "..\resource\resource.h"
|
||||
|
||||
#define MF_80STORE 0x00000001
|
||||
@ -362,15 +363,15 @@ static UINT g_uPeripheralRomSlot = 0;
|
||||
|
||||
//=============================================================================
|
||||
|
||||
BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
|
||||
BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft)
|
||||
{
|
||||
if (!write)
|
||||
return MemReadFloatingBus();
|
||||
return MemReadFloatingBus(nCyclesLeft);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
|
||||
BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft)
|
||||
{
|
||||
// Apple//e ROM:
|
||||
// . PC=FA6F: LDA $C058 (SETAN0)
|
||||
@ -387,7 +388,7 @@ BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYT
|
||||
// - Reset when 6502 accesses $CFFF
|
||||
// . Enable2 = I/O STROBE' (6502 accesses [$C800..$CFFF])
|
||||
|
||||
BYTE __stdcall IORead_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
|
||||
BYTE __stdcall IORead_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft)
|
||||
{
|
||||
if (address == 0xCFFF)
|
||||
{
|
||||
@ -483,12 +484,12 @@ BYTE __stdcall IORead_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE v
|
||||
}
|
||||
|
||||
if ((g_eExpansionRomType == eExpRomNull) && (address >= 0xC800))
|
||||
return IO_Null(programcounter, address, write, value, nCycles);
|
||||
return IO_Null(programcounter, address, write, value, nCyclesLeft);
|
||||
else
|
||||
return mem[address];
|
||||
}
|
||||
|
||||
BYTE __stdcall IOWrite_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
|
||||
BYTE __stdcall IOWrite_Cxxx(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -865,6 +866,13 @@ LPBYTE MemGetMainPtr (WORD offset)
|
||||
|
||||
//===========================================================================
|
||||
|
||||
LPBYTE MemGetCxRomPeripheral()
|
||||
{
|
||||
return pCxRomPeripheral;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
void MemPreInitialize ()
|
||||
{
|
||||
// Init the I/O handlers
|
||||
@ -989,10 +997,12 @@ void MemInitialize()
|
||||
const UINT uSlot = 0;
|
||||
RegisterIoHandler(uSlot, MemSetPaging, MemSetPaging, NULL, NULL, NULL, NULL);
|
||||
|
||||
PrintLoadRom(pCxRomPeripheral, 1); // $C100 : Parallel printer f/w
|
||||
sg_SSC.CommInitialize(pCxRomPeripheral, 2); // $C200 : SSC
|
||||
DiskLoadRom(pCxRomPeripheral, 6); // $C600 : Disk][ f/w
|
||||
HD_Load_Rom(pCxRomPeripheral, 7); // $C700 : HDD f/w
|
||||
PrintLoadRom(pCxRomPeripheral, 1); // $C100 : Parallel printer f/w
|
||||
sg_SSC.CommInitialize(pCxRomPeripheral, 2); // $C200 : SSC
|
||||
if (g_Slot4 == CT_MouseInterface)
|
||||
sg_Mouse.Initialize(pCxRomPeripheral, 4); // $C400 : Mouse f/w
|
||||
DiskLoadRom(pCxRomPeripheral, 6); // $C600 : Disk][ f/w
|
||||
HD_Load_Rom(pCxRomPeripheral, 7); // $C700 : HDD f/w
|
||||
|
||||
MemReset();
|
||||
}
|
||||
@ -1069,16 +1079,16 @@ BYTE MemReturnRandomData (BYTE highbit)
|
||||
|
||||
//===========================================================================
|
||||
|
||||
BYTE MemReadFloatingBus()
|
||||
BYTE MemReadFloatingBus(const ULONG uExecutedCycles)
|
||||
{
|
||||
return*(LPBYTE)(mem + VideoGetScannerAddress());
|
||||
return*(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles));
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
BYTE MemReadFloatingBus(BYTE const highbit)
|
||||
BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles)
|
||||
{
|
||||
BYTE r = *(LPBYTE)(mem + VideoGetScannerAddress());
|
||||
BYTE r = *(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles));
|
||||
return (r & ~0x80) | ((highbit) ? 0x80 : 0);
|
||||
}
|
||||
|
||||
@ -1103,7 +1113,7 @@ BYTE MemReadFloatingBus(BYTE const highbit)
|
||||
//}
|
||||
|
||||
//===========================================================================
|
||||
BYTE __stdcall MemSetPaging (WORD programcounter, WORD address, BYTE write, BYTE value, ULONG)
|
||||
BYTE __stdcall MemSetPaging (WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCyclesLeft)
|
||||
{
|
||||
address &= 0xFF;
|
||||
DWORD lastmemmode = memmode;
|
||||
@ -1166,13 +1176,13 @@ BYTE __stdcall MemSetPaging (WORD programcounter, WORD address, BYTE write, BYTE
|
||||
if ((address >= 4) && (address <= 5) &&
|
||||
((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D)) {
|
||||
modechanging = 1;
|
||||
return write ? 0 : MemReadFloatingBus(1);
|
||||
return write ? 0 : MemReadFloatingBus(1, nCyclesLeft);
|
||||
}
|
||||
if ((address >= 0x80) && (address <= 0x8F) && (programcounter < 0xC000) &&
|
||||
(((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0048D) ||
|
||||
((*(LPDWORD)(mem+programcounter) & 0x00FFFEFF) == 0x00C0028D))) {
|
||||
modechanging = 1;
|
||||
return write ? 0 : MemReadFloatingBus(1);
|
||||
return write ? 0 : MemReadFloatingBus(1, nCyclesLeft);
|
||||
}
|
||||
|
||||
// IF THE MEMORY PAGING MODE HAS CHANGED, UPDATE OUR MEMORY IMAGES AND
|
||||
@ -1216,9 +1226,9 @@ BYTE __stdcall MemSetPaging (WORD programcounter, WORD address, BYTE write, BYTE
|
||||
}
|
||||
|
||||
if ((address <= 1) || ((address >= 0x54) && (address <= 0x57)))
|
||||
return VideoSetMode(programcounter,address,write,value,0);
|
||||
return VideoSetMode(programcounter,address,write,value,nCyclesLeft);
|
||||
|
||||
return write ? 0 : MemReadFloatingBus();
|
||||
return write ? 0 : MemReadFloatingBus(nCyclesLeft);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -26,10 +26,11 @@ bool MemGet80Store();
|
||||
bool MemCheckSLOTCXROM();
|
||||
LPBYTE MemGetAuxPtr (WORD);
|
||||
LPBYTE MemGetMainPtr (WORD);
|
||||
LPBYTE MemGetCxRomPeripheral();
|
||||
void MemPreInitialize ();
|
||||
void MemInitialize ();
|
||||
BYTE MemReadFloatingBus();
|
||||
BYTE MemReadFloatingBus(BYTE highbit);
|
||||
BYTE MemReadFloatingBus(const ULONG uExecutedCycles);
|
||||
BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles);
|
||||
void MemReset ();
|
||||
void MemResetPaging ();
|
||||
BYTE MemReturnRandomData (BYTE highbit);
|
||||
|
@ -145,6 +145,7 @@ static SY6522_AY8910 g_MB[NUM_AY8910];
|
||||
// Timer vars
|
||||
static ULONG g_n6522TimerPeriod = 0;
|
||||
static USHORT g_nMBTimerDevice = 0; // SY6522 device# which is generating timer IRQ
|
||||
static UINT64 g_uLastCumulativeCycles = 0;
|
||||
|
||||
// SSI263 vars:
|
||||
static USHORT g_nSSI263Device = 0; // SSI263 device# which is generating phoneme-complete IRQ
|
||||
@ -1307,8 +1308,11 @@ void MB_Initialize()
|
||||
|
||||
//
|
||||
|
||||
const UINT uSlot4 = 4;
|
||||
RegisterIoHandler(uSlot4, PhasorIO, PhasorIO, MB_Read, MB_Write, NULL, NULL);
|
||||
if (g_Slot4 == CT_Mockingboard)
|
||||
{
|
||||
const UINT uSlot4 = 4;
|
||||
RegisterIoHandler(uSlot4, PhasorIO, PhasorIO, MB_Read, MB_Write, NULL, NULL);
|
||||
}
|
||||
|
||||
const UINT uSlot5 = 5;
|
||||
RegisterIoHandler(uSlot5, PhasorIO, PhasorIO, MB_Read, MB_Write, NULL, NULL);
|
||||
@ -1354,7 +1358,7 @@ void MB_Reset()
|
||||
|
||||
static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft)
|
||||
{
|
||||
CpuCalcCycles(nCyclesLeft);
|
||||
MB_UpdateCycles(nCyclesLeft);
|
||||
|
||||
if(!IS_APPLE2 && !MemCheckSLOTCXROM())
|
||||
return mem[nAddr];
|
||||
@ -1404,7 +1408,7 @@ static BYTE __stdcall MB_Read(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULO
|
||||
|
||||
static BYTE __stdcall MB_Write(WORD PC, WORD nAddr, BYTE bWrite, BYTE nValue, ULONG nCyclesLeft)
|
||||
{
|
||||
CpuCalcCycles(nCyclesLeft);
|
||||
MB_UpdateCycles(nCyclesLeft);
|
||||
|
||||
if(!IS_APPLE2 && !MemCheckSLOTCXROM())
|
||||
return 0;
|
||||
@ -1502,8 +1506,14 @@ void MB_Demute()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Called by CpuExecute() before doing CPU emulation
|
||||
void MB_StartOfCpuExecute()
|
||||
{
|
||||
g_uLastCumulativeCycles = g_nCumulativeCycles;
|
||||
}
|
||||
|
||||
// Called by ContinueExecution() at the end of every video frame
|
||||
void MB_EndOfFrame()
|
||||
void MB_EndOfVideoFrame()
|
||||
{
|
||||
if(g_SoundcardType == SC_NONE)
|
||||
return;
|
||||
@ -1514,13 +1524,20 @@ void MB_EndOfFrame()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Called by InternalCpuExecute() after every opcode
|
||||
// OLD: Called by CpuExecute() & CpuCalcCycles()
|
||||
void MB_UpdateCycles(USHORT nClocks)
|
||||
// Called by InternalCpuExecute() after every N opcodes
|
||||
// OLD: Called by InternalCpuExecute() after every opcode
|
||||
// OLD: void MB_UpdateCycles(USHORT nClocks)
|
||||
void MB_UpdateCycles(ULONG uExecutedCycles)
|
||||
{
|
||||
if(g_SoundcardType == SC_NONE)
|
||||
return;
|
||||
|
||||
CpuCalcCycles(uExecutedCycles);
|
||||
UINT64 uCycles = g_nCumulativeCycles - g_uLastCumulativeCycles;
|
||||
g_uLastCumulativeCycles = g_nCumulativeCycles;
|
||||
_ASSERT(uCycles < 0x10000);
|
||||
USHORT nClocks = (USHORT) uCycles;
|
||||
|
||||
for(int i=0; i<NUM_SY6522; i++)
|
||||
{
|
||||
SY6522_AY8910* pMB = &g_MB[i];
|
||||
|
@ -9,9 +9,10 @@ void MB_Destroy();
|
||||
void MB_Reset();
|
||||
void MB_Mute();
|
||||
void MB_Demute();
|
||||
void MB_EndOfFrame();
|
||||
void MB_StartOfCpuExecute();
|
||||
void MB_EndOfVideoFrame();
|
||||
void MB_CheckIRQ();
|
||||
void MB_UpdateCycles(USHORT nClocks);
|
||||
void MB_UpdateCycles(ULONG uExecutedCycles);
|
||||
eSOUNDCARDTYPE MB_GetSoundcardType();
|
||||
void MB_SetSoundcardType(eSOUNDCARDTYPE NewSoundcardType);
|
||||
double MB_GetFramePeriod();
|
||||
|
431
source/MouseInterface.cpp
Normal file
431
source/MouseInterface.cpp
Normal file
@ -0,0 +1,431 @@
|
||||
// Based on Apple in PC's mousecard.cpp
|
||||
// - Permission given by Kyle Kim to reuse in AppleWin
|
||||
|
||||
#include "stdafx.h"
|
||||
#pragma hdrstop
|
||||
#include "..\resource\resource.h"
|
||||
#include "MouseInterface.h"
|
||||
|
||||
// Sets mouse mode
|
||||
#define MOUSE_SET 0x00
|
||||
// Reads mouse position
|
||||
#define MOUSE_READ 0x10
|
||||
// Services mouse interrupt
|
||||
#define MOUSE_SERV 0x20
|
||||
// Clears mouse positions to 0 (for delta mode)
|
||||
#define MOUSE_CLEAR 0x30
|
||||
// Sets mouse position to a user-defined pos
|
||||
#define MOUSE_POS 0x40
|
||||
// Resets mouse clamps to default values
|
||||
// Sets mouse position to 0,0
|
||||
#define MOUSE_INIT 0x50
|
||||
// Sets mouse bounds in a window
|
||||
#define MOUSE_CLAMP 0x60
|
||||
// Sets mouse to upper-left corner of clamp win
|
||||
#define MOUSE_HOME 0x70
|
||||
|
||||
// Set VBL Timing : 0x90 is 60Hz, 0x91 is 50Hz
|
||||
#define MOUSE_TIME 0x90
|
||||
|
||||
#define BIT0 0x01
|
||||
#define BIT1 0x02
|
||||
#define BIT2 0x04
|
||||
#define BIT3 0x08
|
||||
#define BIT4 0x10
|
||||
#define BIT5 0x20
|
||||
#define BIT6 0x40
|
||||
#define BIT7 0x80
|
||||
|
||||
WRITE_HANDLER( M6821_Listener_B )
|
||||
{
|
||||
((CMouseInterface*)objTo)->On6821_B( byData );
|
||||
}
|
||||
|
||||
WRITE_HANDLER( M6821_Listener_A )
|
||||
{
|
||||
((CMouseInterface*)objTo)->On6821_A( byData );
|
||||
}
|
||||
|
||||
//CALLBACK_HANDLER( MouseHandler )
|
||||
//{
|
||||
// ((CMouseInterface*)objTo)->OnMouseEvent();
|
||||
//}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
CMouseInterface::CMouseInterface() :
|
||||
m_pSlotRom(NULL)
|
||||
{
|
||||
m_6821.SetListenerB( this, M6821_Listener_B );
|
||||
m_6821.SetListenerA( this, M6821_Listener_A );
|
||||
// g_cDIMouse.SetMouseListener( this, MouseHandler );
|
||||
m_by6821A = 0;
|
||||
m_by6821B = 0x40; // Set PB6
|
||||
m_6821.SetPB(m_by6821B);
|
||||
m_bVBL = FALSE;
|
||||
|
||||
//
|
||||
|
||||
m_iX = 0;
|
||||
m_iMinX = 0;
|
||||
m_iMaxX = 1023;
|
||||
m_iRangeX = 0;
|
||||
|
||||
m_iY = 0;
|
||||
m_iMinY = 0;
|
||||
m_iMaxY = 1023;
|
||||
m_iRangeY = 0;
|
||||
|
||||
m_bButtons[0] = m_bButtons[1] = FALSE;
|
||||
|
||||
//
|
||||
|
||||
Reset();
|
||||
memset( m_byBuff, 0, sizeof( m_byBuff ) );
|
||||
m_bActive = false;
|
||||
}
|
||||
|
||||
CMouseInterface::~CMouseInterface()
|
||||
{
|
||||
delete [] m_pSlotRom;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
void CMouseInterface::Initialize(LPBYTE pCxRomPeripheral, UINT uSlot)
|
||||
{
|
||||
const UINT FW_SIZE = 2*1024;
|
||||
|
||||
HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_MOUSEINTERFACE_FW), "FIRMWARE");
|
||||
if(hResInfo == NULL)
|
||||
return;
|
||||
|
||||
DWORD dwResSize = SizeofResource(NULL, hResInfo);
|
||||
if(dwResSize != FW_SIZE)
|
||||
return;
|
||||
|
||||
HGLOBAL hResData = LoadResource(NULL, hResInfo);
|
||||
if(hResData == NULL)
|
||||
return;
|
||||
|
||||
BYTE* pData = (BYTE*) LockResource(hResData); // NB. Don't need to unlock resource
|
||||
if(pData == NULL)
|
||||
return;
|
||||
|
||||
m_uSlot = uSlot;
|
||||
|
||||
if (m_pSlotRom == NULL)
|
||||
{
|
||||
m_pSlotRom = new BYTE [FW_SIZE];
|
||||
|
||||
if (m_pSlotRom)
|
||||
memcpy(m_pSlotRom, pData, FW_SIZE);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
SetSlotRom();
|
||||
RegisterIoHandler(uSlot, &CMouseInterface::IORead, &CMouseInterface::IOWrite, NULL, NULL, this, NULL);
|
||||
m_bActive = true;
|
||||
}
|
||||
|
||||
void CMouseInterface::SetSlotRom()
|
||||
{
|
||||
LPBYTE pCxRomPeripheral = MemGetCxRomPeripheral();
|
||||
if (pCxRomPeripheral == NULL)
|
||||
return;
|
||||
|
||||
UINT uOffset = (m_by6821B << 7) & 0x0700;
|
||||
memcpy(pCxRomPeripheral+m_uSlot*256, m_pSlotRom+uOffset, 256);
|
||||
if (mem)
|
||||
memcpy(mem+0xC000+m_uSlot*256, m_pSlotRom+uOffset, 256);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
BYTE __stdcall CMouseInterface::IORead(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft)
|
||||
{
|
||||
UINT uSlot = ((uAddr & 0xff) >> 4) - 8;
|
||||
CMouseInterface* pMouseIF = (CMouseInterface*) MemGetSlotParameters(uSlot);
|
||||
|
||||
BYTE byRS;
|
||||
byRS = uAddr & 3;
|
||||
return pMouseIF->m_6821.Read( byRS );
|
||||
}
|
||||
|
||||
BYTE __stdcall CMouseInterface::IOWrite(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft)
|
||||
{
|
||||
UINT uSlot = ((uAddr & 0xff) >> 4) - 8;
|
||||
CMouseInterface* pMouseIF = (CMouseInterface*) MemGetSlotParameters(uSlot);
|
||||
|
||||
BYTE byRS;
|
||||
byRS = uAddr & 3;
|
||||
pMouseIF->m_6821.Write( byRS, uValue );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
void CMouseInterface::On6821_A(BYTE byData)
|
||||
{
|
||||
m_by6821A = byData;
|
||||
}
|
||||
|
||||
void CMouseInterface::On6821_B(BYTE byData)
|
||||
{
|
||||
BYTE byDiff = ( m_by6821B ^ byData ) & 0x3E;
|
||||
|
||||
if ( byDiff )
|
||||
{
|
||||
m_by6821B &= ~0x3E;
|
||||
m_by6821B |= byData & 0x3E;
|
||||
if ( byDiff & BIT5 ) // Write to 0285 chip
|
||||
{
|
||||
if ( byData & BIT5 )
|
||||
m_by6821B |= BIT7; // OK, I'm ready to read from MC6821
|
||||
else // Clock Activate for read
|
||||
{
|
||||
m_byBuff[m_nBuffPos++] = m_by6821A;
|
||||
if ( m_nBuffPos == 1 )
|
||||
OnCommand();
|
||||
if ( m_nBuffPos == m_nDataLen || m_nBuffPos > 7 )
|
||||
{
|
||||
OnWrite(); // Have written all, Commit the command.
|
||||
m_nBuffPos = 0;
|
||||
}
|
||||
m_by6821B &= ~BIT7; // for next reading
|
||||
m_6821.SetPB( m_by6821B );
|
||||
}
|
||||
|
||||
}
|
||||
if ( byDiff & BIT4 ) // Read from 0285 chip ?
|
||||
{
|
||||
if ( byData & BIT4 )
|
||||
m_by6821B &= ~BIT6; // OK, I'll prepare next value
|
||||
else // Clock Activate for write
|
||||
{
|
||||
if ( m_nBuffPos ) // if m_nBuffPos is 0, something goes wrong!
|
||||
m_nBuffPos++;
|
||||
if ( m_nBuffPos == m_nDataLen || m_nBuffPos > 7 )
|
||||
m_nBuffPos = 0; // Have read all, ready for next command.
|
||||
else
|
||||
m_6821.SetPA( m_byBuff[m_nBuffPos] );
|
||||
m_by6821B |= BIT6; // for next writing
|
||||
}
|
||||
}
|
||||
m_6821.SetPB( m_by6821B );
|
||||
|
||||
//
|
||||
|
||||
SetSlotRom(); // Update Cn00 ROM page
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CMouseInterface::OnCommand()
|
||||
{
|
||||
//char szDbg[256];
|
||||
switch( m_byBuff[0] & 0xF0 )
|
||||
{
|
||||
case MOUSE_SET:
|
||||
m_nDataLen = 1;
|
||||
m_byMode = m_byBuff[0] & 0x0F;
|
||||
break;
|
||||
case MOUSE_READ: // Read
|
||||
m_nDataLen = 6;
|
||||
m_byState &= 0x20;
|
||||
m_nX = m_iX;
|
||||
m_nY = m_iY;
|
||||
if ( m_bBtn0 ) m_byState |= 0x40; // Previous Button 0
|
||||
if ( m_bBtn1 ) m_byState |= 0x01; // Previous Button 1
|
||||
m_bBtn0 = m_bButtons[0];
|
||||
m_bBtn1 = m_bButtons[1];
|
||||
if ( m_bBtn0 ) m_byState |= 0x80; // Current Button 0
|
||||
if ( m_bBtn1 ) m_byState |= 0x10; // Current Button 1
|
||||
m_byBuff[1] = m_nX & 0xFF;
|
||||
m_byBuff[2] = ( m_nX >> 8 ) & 0xFF;
|
||||
m_byBuff[3] = m_nY & 0xFF;
|
||||
m_byBuff[4] = ( m_nY >> 8 ) & 0xFF;
|
||||
m_byBuff[5] = m_byState; // button 0/1 interrupt status
|
||||
m_byState &= ~0x20;
|
||||
//sprintf(szDbg, "[MOUSE-READ] IRQ=0x%02X X=(0x%02X-0x%02X) Y=(0x%02X-0x%02X) \n", m_byBuff[5], m_byBuff[1], m_byBuff[2], m_byBuff[3], m_byBuff[4]); OutputDebugString(szDbg);
|
||||
break;
|
||||
case MOUSE_SERV:
|
||||
m_nDataLen = 2;
|
||||
m_byBuff[1] = m_byState & ~0x20; // reason of interrupt
|
||||
CpuIrqDeassert(IS_MOUSE);
|
||||
//sprintf(szDbg, "[MOUSE-SERV] IRQ=0x%02X\n", m_byBuff[1]); OutputDebugString(szDbg);
|
||||
break;
|
||||
case MOUSE_CLEAR:
|
||||
Reset();
|
||||
m_nDataLen = 1;
|
||||
break;
|
||||
case MOUSE_POS:
|
||||
m_nDataLen = 5;
|
||||
break;
|
||||
case MOUSE_INIT:
|
||||
m_nDataLen = 3;
|
||||
m_byBuff[1] = 0xFF; // I don't know what it is
|
||||
break;
|
||||
case MOUSE_CLAMP:
|
||||
m_nDataLen = 5;
|
||||
break;
|
||||
case MOUSE_HOME:
|
||||
m_nDataLen = 1;
|
||||
SetPosition( 0, 0 );
|
||||
break;
|
||||
case MOUSE_TIME: // 0x90
|
||||
switch( m_byBuff[0] & 0x0C )
|
||||
{
|
||||
case 0x00: m_nDataLen = 1; break; // write cmd ( #$90 is DATATIME 60Hz, #$91 is 50Hz )
|
||||
case 0x04: m_nDataLen = 3; break; // write cmd, $0478, $04F8
|
||||
case 0x08: m_nDataLen = 2; break; // write cmd, $0578
|
||||
case 0x0C: m_nDataLen = 4; break; // write cmd, $0478, $04F8, $0578
|
||||
}
|
||||
break;
|
||||
case 0xA0:
|
||||
m_nDataLen = 2;
|
||||
break;
|
||||
case 0xB0:
|
||||
case 0xC0:
|
||||
m_nDataLen = 1;
|
||||
break;
|
||||
default:
|
||||
m_nDataLen = 1;
|
||||
//TRACE( "CMD : UNKNOWN CMD : #$%02X\n", m_byBuff[0] );
|
||||
//_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
m_6821.SetPA( m_byBuff[1] );
|
||||
}
|
||||
|
||||
void CMouseInterface::OnWrite()
|
||||
{
|
||||
int nMin, nMax;
|
||||
switch( m_byBuff[0] & 0xF0 )
|
||||
{
|
||||
case MOUSE_CLAMP:
|
||||
nMin = ( m_byBuff[3] << 8 ) | m_byBuff[1];
|
||||
nMax = ( m_byBuff[4] << 8 ) | m_byBuff[2];
|
||||
if ( m_byBuff[0] & 1 ) // Clamp Y
|
||||
ClampY( nMin, nMax );
|
||||
else // Clamp X
|
||||
ClampX( nMin, nMax );
|
||||
break;
|
||||
case MOUSE_POS:
|
||||
m_nX = ( m_byBuff[2] << 8 ) | m_byBuff[1];
|
||||
m_nY = ( m_byBuff[4] << 8 ) | m_byBuff[3];
|
||||
SetPosition( m_nX, m_nY );
|
||||
break;
|
||||
case MOUSE_INIT:
|
||||
m_nX = 0;
|
||||
m_nY = 0;
|
||||
ClampX( 0, 1023 );
|
||||
ClampY( 0, 1023 );
|
||||
SetPosition( 0, 0 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CMouseInterface::OnMouseEvent()
|
||||
{
|
||||
int byState = 0;
|
||||
|
||||
if ( !( m_byMode & 1 ) ) // Mouse Off
|
||||
return;
|
||||
|
||||
BOOL bBtn0 = m_bButtons[0];
|
||||
BOOL bBtn1 = m_bButtons[1];
|
||||
if ( m_nX != m_iX || m_nY != m_iY )
|
||||
byState |= 0x22; // X/Y moved since last READMOUSE | Movement interrupt
|
||||
if ( m_bBtn0 != bBtn0 || m_bBtn1 != bBtn1 )
|
||||
byState |= 0x04; // Button 0/1 interrupt
|
||||
if ( m_bVBL )
|
||||
byState |= 0x08;
|
||||
byState &= m_byMode & 0x2E;
|
||||
|
||||
if ( byState & 0x0E )
|
||||
{
|
||||
//char szDbg[256];
|
||||
//sprintf(szDbg, "[MOUSE] 0x%02X, %04d(%04d), %04d(%04d), %d\n", byState, m_iX, m_nX, m_iY, m_nY, bBtn0); OutputDebugString(szDbg);
|
||||
m_byState |= byState;
|
||||
CpuIrqAssert(IS_MOUSE);
|
||||
}
|
||||
}
|
||||
|
||||
void CMouseInterface::SetVBlank(bool bVBL)
|
||||
{
|
||||
if ( m_bVBL != bVBL )
|
||||
{
|
||||
m_bVBL = bVBL;
|
||||
if ( m_bVBL ) // Rising edge
|
||||
OnMouseEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void CMouseInterface::Reset()
|
||||
{
|
||||
m_nBuffPos = 0;
|
||||
m_nDataLen = 1;
|
||||
|
||||
m_byMode = 0;
|
||||
m_byState = 0;
|
||||
m_nX = 0;
|
||||
m_nY = 0;
|
||||
m_bBtn0 = 0;
|
||||
m_bBtn1 = 0;
|
||||
ClampX( 0, 1023 );
|
||||
ClampY( 0, 1023 );
|
||||
SetPosition( 0, 0 );
|
||||
|
||||
// CpuIrqDeassert(IS_MOUSE);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
void CMouseInterface::ClampX(int iMinX, int iMaxX)
|
||||
{
|
||||
if ( iMinX < 0 || iMinX > iMaxX )
|
||||
return;
|
||||
m_iMaxX = iMaxX;
|
||||
m_iMinX = iMinX;
|
||||
if ( m_iX > m_iMaxX ) m_iX = m_iMaxX; else if ( m_iX < m_iMinX ) m_iX = m_iMinX;
|
||||
}
|
||||
|
||||
void CMouseInterface::ClampY(int iMinY, int iMaxY)
|
||||
{
|
||||
if ( iMinY < 0 || iMinY > iMaxY )
|
||||
return;
|
||||
m_iMaxY = iMaxY;
|
||||
m_iMinY = iMinY;
|
||||
if ( m_iY > m_iMaxY ) m_iY = m_iMaxY; else if ( m_iY < m_iMinX ) m_iY = m_iMinY;
|
||||
}
|
||||
|
||||
void CMouseInterface::SetPosition(int xvalue, int yvalue)
|
||||
{
|
||||
if ((m_iRangeX == 0) || (m_iRangeY == 0))
|
||||
{
|
||||
m_iX = m_iMinX;
|
||||
m_iY = m_iMinY;
|
||||
return;
|
||||
}
|
||||
|
||||
m_iX = (UINT) ((xvalue*m_iMaxX) / m_iRangeX);
|
||||
m_iY = (UINT) ((yvalue*m_iMaxY) / m_iRangeY);
|
||||
}
|
||||
|
||||
void CMouseInterface::SetPosition(int xvalue, int xrange, int yvalue, int yrange)
|
||||
{
|
||||
m_iRangeX = (UINT) xrange;
|
||||
m_iRangeY = (UINT) yrange;
|
||||
|
||||
SetPosition(xvalue, yvalue);
|
||||
OnMouseEvent();
|
||||
}
|
||||
|
||||
void CMouseInterface::SetButton(eBUTTON Button, eBUTTONSTATE State)
|
||||
{
|
||||
m_bButtons[Button]= (State == BUTTON_DOWN) ? TRUE : FALSE;
|
||||
OnMouseEvent();
|
||||
}
|
79
source/MouseInterface.h
Normal file
79
source/MouseInterface.h
Normal file
@ -0,0 +1,79 @@
|
||||
#include "6821.h"
|
||||
#include "Common.h"
|
||||
|
||||
#define WRITE_HANDLER(func) void func( void* objFrom, void* objTo, int nAddr, BYTE byData )
|
||||
#define CALLBACK_HANDLER(func) void func( void* objFrom, void* objTo, LPARAM lParam )
|
||||
|
||||
extern class CMouseInterface sg_Mouse;
|
||||
|
||||
class CMouseInterface
|
||||
{
|
||||
public:
|
||||
CMouseInterface();
|
||||
virtual ~CMouseInterface();
|
||||
|
||||
void Initialize(LPBYTE pCxRomPeripheral, UINT uSlot);
|
||||
void Uninitialize(){ m_bActive = false; }
|
||||
void SetSlotRom();
|
||||
static BYTE __stdcall IORead(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft);
|
||||
static BYTE __stdcall IOWrite(WORD PC, WORD uAddr, BYTE bWrite, BYTE uValue, ULONG nCyclesLeft);
|
||||
|
||||
void SetPosition(int xvalue, int xrange, int yvalue, int yrange);
|
||||
void SetButton(eBUTTON Button, eBUTTONSTATE State);
|
||||
bool Active() { return m_bActive; }
|
||||
void SetVBlank(bool bVBL);
|
||||
|
||||
protected:
|
||||
void On6821_A(BYTE byData);
|
||||
void On6821_B(BYTE byData);
|
||||
void OnCommand();
|
||||
void OnWrite();
|
||||
void OnMouseEvent();
|
||||
void Reset();
|
||||
|
||||
friend WRITE_HANDLER( M6821_Listener_A );
|
||||
friend WRITE_HANDLER( M6821_Listener_B );
|
||||
//friend CALLBACK_HANDLER( MouseHandler );
|
||||
|
||||
void SetPosition(int xvalue, int yvalue);
|
||||
void ClampX(int iMinX, int iMaxX);
|
||||
void ClampY(int iMinY, int iMaxY);
|
||||
|
||||
|
||||
C6821 m_6821;
|
||||
|
||||
int m_nDataLen;
|
||||
BYTE m_byMode;
|
||||
|
||||
BYTE m_by6821B;
|
||||
BYTE m_by6821A;
|
||||
BYTE m_byBuff[8]; // m_byBuff[0] is mode byte
|
||||
int m_nBuffPos;
|
||||
|
||||
BYTE m_byState;
|
||||
int m_nX;
|
||||
int m_nY;
|
||||
BOOL m_bBtn0;
|
||||
BOOL m_bBtn1;
|
||||
|
||||
bool m_bVBL;
|
||||
|
||||
//
|
||||
|
||||
UINT m_iX;
|
||||
UINT m_iRangeX;
|
||||
UINT m_iMinX;
|
||||
UINT m_iMaxX;
|
||||
UINT m_iY;
|
||||
UINT m_iRangeY;
|
||||
UINT m_iMinY;
|
||||
UINT m_iMaxY;
|
||||
|
||||
BOOL m_bButtons[2];
|
||||
|
||||
//
|
||||
|
||||
bool m_bActive;
|
||||
LPBYTE m_pSlotRom;
|
||||
UINT m_uSlot;
|
||||
};
|
@ -101,6 +101,9 @@ enum {PG_CONFIG=0, PG_INPUT, PG_SOUND, PG_SAVESTATE, PG_DISK, PG_NUM_SHEETS};
|
||||
|
||||
UINT g_nLastPage = PG_CONFIG;
|
||||
|
||||
UINT g_uScrollLockToggle = 0;
|
||||
UINT g_uMouseInSlot4 = 0;
|
||||
|
||||
//===========================================================================
|
||||
|
||||
static void FillComboBox (HWND window, int controlid, LPCTSTR choices, int currentchoice)
|
||||
@ -224,15 +227,17 @@ static void ConfigDlg_OK(HWND window, BOOL afterclose)
|
||||
if (NewApple2Type != g_Apple2Type)
|
||||
{
|
||||
if (MessageBox(window,
|
||||
TEXT(
|
||||
"You have changed the emulated computer "
|
||||
"type. This change will not take effect "
|
||||
"until the next time you restart the "
|
||||
"emulator.\n\n"
|
||||
"Would you like to restart the emulator now?"),
|
||||
TEXT("Configuration"),
|
||||
MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND) == IDYES)
|
||||
TEXT(
|
||||
"You have changed the emulated computer "
|
||||
"type. This change will not take effect "
|
||||
"until the next time you restart the "
|
||||
"emulator.\n\n"
|
||||
"Would you like to restart the emulator now?"),
|
||||
TEXT("Configuration"),
|
||||
MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND) == IDYES)
|
||||
{
|
||||
afterclose = WM_USER_RESTART;
|
||||
}
|
||||
}
|
||||
|
||||
if (videotype != newvidtype)
|
||||
@ -257,6 +262,7 @@ static void ConfigDlg_OK(HWND window, BOOL afterclose)
|
||||
SAVE(TEXT("Custom Speed") ,IsDlgButtonChecked(window,IDC_CUSTOM_SPEED));
|
||||
SAVE(TEXT("Emulation Speed") ,g_dwSpeed);
|
||||
SAVE(TEXT("Video Emulation") ,videotype);
|
||||
SAVE(TEXT(REGVALUE_MOUSE_IN_SLOT4),g_uMouseInSlot4);
|
||||
|
||||
//
|
||||
|
||||
@ -332,6 +338,31 @@ static BOOL CALLBACK ConfigDlgProc (HWND window,
|
||||
VideoChooseColor();
|
||||
break;
|
||||
|
||||
case IDC_MOUSE_IN_SLOT4:
|
||||
UINT uNewState = IsDlgButtonChecked(window, IDC_MOUSE_IN_SLOT4) ? 1 : 0;
|
||||
LPCSTR pMsg = uNewState ?
|
||||
TEXT("The emulator needs to restart as the slot configuration has changed.\n")
|
||||
TEXT("Also Mockingboard/Phasor cards won't be available in slot 4.\n\n")
|
||||
TEXT("Would you like to restart the emulator now?")
|
||||
:
|
||||
TEXT("The emulator needs to restart as the slot configuration has changed.\n")
|
||||
TEXT("(Mockingboard/Phasor cards will now be available in slot 4.)\n\n")
|
||||
TEXT("Would you like to restart the emulator now?");
|
||||
if (MessageBox(window,
|
||||
pMsg,
|
||||
TEXT("Configuration"),
|
||||
MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND) == IDYES)
|
||||
{
|
||||
g_uMouseInSlot4 = uNewState;
|
||||
afterclose = WM_USER_RESTART;
|
||||
PropSheet_PressButton(GetParent(window), PSBTN_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckDlgButton(window, IDC_MOUSE_IN_SLOT4, g_uMouseInSlot4 ? BST_CHECKED : BST_UNCHECKED);
|
||||
}
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case IDC_RECALIBRATE:
|
||||
RegSaveValue(TEXT(""),TEXT("RunningOnOS"),0,0);
|
||||
@ -384,6 +415,8 @@ static BOOL CALLBACK ConfigDlgProc (HWND window,
|
||||
EnableTrackbar(window, custom);
|
||||
}
|
||||
|
||||
CheckDlgButton(window, IDC_MOUSE_IN_SLOT4, g_uMouseInSlot4 ? BST_CHECKED : BST_UNCHECKED);
|
||||
|
||||
afterclose = 0;
|
||||
break;
|
||||
}
|
||||
@ -444,6 +477,7 @@ static void InputDlg_OK(HWND window, BOOL afterclose)
|
||||
SAVE(TEXT("Joystick 1 Emulation"),joytype[1]);
|
||||
SAVE(TEXT(REGVALUE_PDL_XTRIM),JoyGetTrim(true));
|
||||
SAVE(TEXT(REGVALUE_PDL_YTRIM),JoyGetTrim(false));
|
||||
SAVE(TEXT(REGVALUE_SCROLLLOCK_TOGGLE),g_uScrollLockToggle);
|
||||
// SAVE(TEXT(REGVALUE_KEYB_BUFFER_ENABLE),KeybGetBufferMode() ? 1 : 0);
|
||||
|
||||
//
|
||||
@ -527,11 +561,14 @@ static BOOL CALLBACK InputDlgProc (HWND window,
|
||||
InitJoystickChoices(window, JN_JOYSTICK0, IDC_JOYSTICK0); // Re-init joy0 list
|
||||
}
|
||||
break;
|
||||
// case IDC_KEYB_BUFFER_ENABLE:
|
||||
// break;
|
||||
case IDC_SCROLLLOCK_TOGGLE:
|
||||
g_uScrollLockToggle = IsDlgButtonChecked(window, IDC_SCROLLLOCK_TOGGLE) ? 1 : 0;
|
||||
break;
|
||||
case IDC_PASTE_FROM_CLIPBOARD:
|
||||
ClipboardInitiatePaste();
|
||||
break;
|
||||
// case IDC_KEYB_BUFFER_ENABLE:
|
||||
// break;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -548,6 +585,7 @@ static BOOL CALLBACK InputDlgProc (HWND window,
|
||||
SendDlgItemMessage(window, IDC_SPIN_XTRIM, UDM_SETPOS, 0, MAKELONG(JoyGetTrim(true),0));
|
||||
SendDlgItemMessage(window, IDC_SPIN_YTRIM, UDM_SETPOS, 0, MAKELONG(JoyGetTrim(false),0));
|
||||
|
||||
CheckDlgButton(window, IDC_SCROLLLOCK_TOGGLE, g_uScrollLockToggle ? BST_CHECKED : BST_UNCHECKED);
|
||||
// CheckDlgButton(window, IDC_KEYB_BUFFER_ENABLE, KeybGetBufferMode() ? BST_CHECKED : BST_UNCHECKED);
|
||||
}
|
||||
}
|
||||
@ -675,6 +713,11 @@ static BOOL CALLBACK SoundDlgProc (HWND window,
|
||||
|
||||
CheckRadioButton(window, IDC_MB_ENABLE, IDC_SOUNDCARD_DISABLE, nID);
|
||||
|
||||
if (g_uMouseInSlot4)
|
||||
{
|
||||
EnableWindow(GetDlgItem(window, IDC_PHASOR_ENABLE), FALSE);
|
||||
}
|
||||
|
||||
afterclose = 0;
|
||||
}
|
||||
}
|
||||
@ -734,7 +777,18 @@ static int SaveStateSelectImage(HWND hWindow, TCHAR* pszTitle, bool bSave)
|
||||
TCHAR szDirectory[MAX_PATH] = TEXT("");
|
||||
TCHAR szFilename[MAX_PATH];
|
||||
|
||||
strcpy(szFilename, Snapshot_GetFilename());
|
||||
// Attempt to use drive1's image name as the name for the .aws file
|
||||
LPCTSTR pDiskName0 = DiskGetName(0);
|
||||
if (pDiskName0 && pDiskName0[0])
|
||||
{
|
||||
strcpy(szFilename, pDiskName0);
|
||||
strcpy(&szFilename[strlen(pDiskName0)], ".aws");
|
||||
// NB. OK'ing this property sheet will call Snapshot_SetFilename() with this new filename
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(szFilename, Snapshot_GetFilename());
|
||||
}
|
||||
|
||||
RegLoadString(TEXT("Preferences"),REGVALUE_PREF_START_DIR,1,szDirectory,MAX_PATH);
|
||||
|
||||
|
@ -6,3 +6,6 @@ bool PSP_SaveStateSelectImage(HWND hWindow, bool bSave);
|
||||
void ui_tfe_settings_dialog(HWND hwnd);
|
||||
void * get_tfe_interface(void);
|
||||
void get_tfe_enabled(int *tfe_enabled);
|
||||
|
||||
extern UINT g_uScrollLockToggle;
|
||||
extern UINT g_uMouseInSlot4;
|
||||
|
@ -87,10 +87,6 @@ CSuperSerialCard::CSuperSerialCard()
|
||||
memset(&m_o, 0, sizeof(m_o));
|
||||
}
|
||||
|
||||
CSuperSerialCard::~CSuperSerialCard()
|
||||
{
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
// TODO: Serial Comms - UI Property Sheet Page:
|
||||
|
@ -23,7 +23,7 @@ class CSuperSerialCard
|
||||
{
|
||||
public:
|
||||
CSuperSerialCard();
|
||||
~CSuperSerialCard();
|
||||
virtual ~CSuperSerialCard() {}
|
||||
|
||||
void CommInitialize(LPBYTE pCxRomPeripheral, UINT uSlot);
|
||||
void CommReset();
|
||||
|
@ -492,7 +492,7 @@ BYTE __stdcall SpkrToggle (WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft)
|
||||
|
||||
}
|
||||
|
||||
return MemReadFloatingBus();
|
||||
return MemReadFloatingBus(nCyclesLeft);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@ -802,7 +802,7 @@ static ULONG Spkr_SubmitWaveBuffer_FullSpeed(short* pSpeakerBuffer, ULONG nNumSa
|
||||
|
||||
static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
|
||||
{
|
||||
char szDbg[200];
|
||||
//char szDbg[200];
|
||||
nDbgSpkrCnt++;
|
||||
|
||||
if(!SpeakerVoice.bActive)
|
||||
@ -838,7 +838,7 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
|
||||
|
||||
dwByteOffset = dwCurrentPlayCursor + (g_dwDSSpkrBufferSize/8)*3; // Ideal: 0.375 is between 0.25 & 0.50 full
|
||||
dwByteOffset %= g_dwDSSpkrBufferSize;
|
||||
sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X [REINIT]\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset); OutputDebugString(szDbg);
|
||||
//sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X [REINIT]\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset); OutputDebugString(szDbg);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -849,7 +849,7 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
|
||||
// |-----PxxxxxW-----|
|
||||
if((dwByteOffset > dwCurrentPlayCursor) && (dwByteOffset < dwCurrentWriteCursor))
|
||||
{
|
||||
sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg);
|
||||
//sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg);
|
||||
dwByteOffset = dwCurrentWriteCursor;
|
||||
nNumSamplesError = 0;
|
||||
bBufferError = true;
|
||||
@ -860,7 +860,7 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
|
||||
// |xxW----------Pxxx|
|
||||
if((dwByteOffset > dwCurrentPlayCursor) || (dwByteOffset < dwCurrentWriteCursor))
|
||||
{
|
||||
sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg);
|
||||
//sprintf(szDbg, "[Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples); OutputDebugString(szDbg);
|
||||
dwByteOffset = dwCurrentWriteCursor;
|
||||
nNumSamplesError = 0;
|
||||
bBufferError = true;
|
||||
|
@ -147,6 +147,7 @@ enum SS_CARDTYPE
|
||||
CT_GenericPrinter,
|
||||
CT_GenericHDD, // Hard disk
|
||||
CT_GenericClock,
|
||||
CT_MouseInterface,
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1570,11 +1570,11 @@ void VideoBenchmark () {
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
BYTE __stdcall VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG)
|
||||
BYTE __stdcall VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG nCyclesLeft)
|
||||
{
|
||||
address &= 0xFF;
|
||||
if (address == 0x7F)
|
||||
return MemReadFloatingBus(SW_DHIRES != 0);
|
||||
return MemReadFloatingBus(SW_DHIRES != 0, nCyclesLeft);
|
||||
else {
|
||||
BOOL result = 0;
|
||||
switch (address) {
|
||||
@ -1601,7 +1601,7 @@ void VideoCheckPage (BOOL force) {
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
BYTE __stdcall VideoCheckVbl (WORD, WORD, BYTE, BYTE, ULONG)
|
||||
BYTE __stdcall VideoCheckVbl (WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft)
|
||||
{
|
||||
/*
|
||||
// Drol expects = 80
|
||||
@ -1644,7 +1644,7 @@ BYTE __stdcall VideoCheckVbl (WORD, WORD, BYTE, BYTE, ULONG)
|
||||
*/
|
||||
|
||||
bool bVblBar;
|
||||
VideoGetScannerAddress(&bVblBar);
|
||||
VideoGetScannerAddress(&bVblBar, nCyclesLeft);
|
||||
BYTE r = KeybGetKeycode();
|
||||
return (r & ~0x80) | ((bVblBar) ? 0x80 : 0);
|
||||
}
|
||||
@ -2042,7 +2042,7 @@ void VideoResetState () {
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
BYTE __stdcall VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG)
|
||||
BYTE __stdcall VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG nCyclesLeft)
|
||||
{
|
||||
address &= 0xFF;
|
||||
DWORD oldpage2 = SW_PAGE2;
|
||||
@ -2097,7 +2097,7 @@ BYTE __stdcall VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG)
|
||||
}
|
||||
lastpageflip = emulmsec;
|
||||
}
|
||||
return MemReadFloatingBus();
|
||||
return MemReadFloatingBus(nCyclesLeft);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
@ -2160,11 +2160,11 @@ DWORD VideoSetSnapshot(SS_IO_Video* pSS)
|
||||
|
||||
//===========================================================================
|
||||
|
||||
WORD VideoGetScannerAddress(bool* pbVblBar_OUT)
|
||||
WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles)
|
||||
{
|
||||
// get video scanner position
|
||||
//
|
||||
int nCycles = CpuGetCyclesThisFrame();
|
||||
int nCycles = CpuGetCyclesThisFrame(uExecutedCycles);
|
||||
|
||||
// machine state switches
|
||||
//
|
||||
@ -2270,3 +2270,39 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT)
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
||||
// Derived from VideoGetScannerAddress()
|
||||
bool VideoGetVbl(const DWORD uExecutedCycles)
|
||||
{
|
||||
// get video scanner position
|
||||
//
|
||||
int nCycles = CpuGetCyclesThisFrame(uExecutedCycles);
|
||||
|
||||
// calculate video parameters according to display standard
|
||||
//
|
||||
int nScanLines = bVideoScannerNTSC ? kNTSCScanLines : kPALScanLines;
|
||||
|
||||
// calculate vertical scanning state
|
||||
//
|
||||
int nVLine = nCycles / kHClocks; // which vertical scanning line
|
||||
int nVState = kVLine0State + nVLine; // V state bits
|
||||
if ((nVLine >= kVPresetLine)) // check for previous vertical state preset
|
||||
{
|
||||
nVState -= nScanLines; // compensate for preset
|
||||
}
|
||||
int v_3 = (nVState >> 6) & 1;
|
||||
int v_4 = (nVState >> 7) & 1;
|
||||
|
||||
// update VBL' state
|
||||
//
|
||||
if (v_4 & v_3) // VBL?
|
||||
{
|
||||
return false; // Y: VBL' is false
|
||||
}
|
||||
else
|
||||
{
|
||||
return true; // N: VBL' is true
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -63,7 +63,8 @@ void VideoRedrawScreen ();
|
||||
void VideoRefreshScreen ();
|
||||
void VideoReinitialize ();
|
||||
void VideoResetState ();
|
||||
WORD VideoGetScannerAddress(bool* pbVblBar_OUT = NULL);
|
||||
WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles);
|
||||
bool VideoGetVbl(DWORD uExecutedCycles);
|
||||
void VideoUpdateVbl (DWORD dwCyclesThisFrame);
|
||||
void VideoUpdateFlash();
|
||||
bool VideoGetSW80COL();
|
||||
|
Loading…
x
Reference in New Issue
Block a user