*** empty log message ***
|
@ -0,0 +1,386 @@
|
||||||
|
<?xml version="1.0" encoding="Windows-1252"?>
|
||||||
|
<VisualStudioProject
|
||||||
|
ProjectType="Visual C++"
|
||||||
|
Version="7.10"
|
||||||
|
Name="AppleWin"
|
||||||
|
ProjectGUID="{C4C93CFD-5B6C-41C5-BF90-17119186120F}"
|
||||||
|
SccProjectName="APPLEWIN"
|
||||||
|
SccLocalPath=".">
|
||||||
|
<Platforms>
|
||||||
|
<Platform
|
||||||
|
Name="Win32"/>
|
||||||
|
</Platforms>
|
||||||
|
<Configurations>
|
||||||
|
<Configuration
|
||||||
|
Name="Release|Win32"
|
||||||
|
OutputDirectory=".\Release"
|
||||||
|
IntermediateDirectory=".\Release"
|
||||||
|
ConfigurationType="1"
|
||||||
|
UseOfMFC="0"
|
||||||
|
ATLMinimizesCRunTimeLibraryUsage="FALSE">
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
AdditionalOptions="/Zm200 "
|
||||||
|
Optimization="2"
|
||||||
|
InlineFunctionExpansion="2"
|
||||||
|
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
|
||||||
|
StringPooling="TRUE"
|
||||||
|
RuntimeLibrary="4"
|
||||||
|
EnableFunctionLevelLinking="TRUE"
|
||||||
|
UsePrecompiledHeader="2"
|
||||||
|
PrecompiledHeaderFile=".\Release/Applewin.pch"
|
||||||
|
AssemblerListingLocation=".\Release/"
|
||||||
|
ObjectFile=".\Release/"
|
||||||
|
ProgramDataBaseFileName=".\Release/"
|
||||||
|
WarningLevel="3"
|
||||||
|
SuppressStartupBanner="TRUE"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLinkerTool"
|
||||||
|
AdditionalDependencies="htmlhelp.lib comctl32.lib ddraw.lib winmm.lib dsound.lib dxguid.lib version.lib strmiids.lib"
|
||||||
|
OutputFile=".\Release/Applewin.exe"
|
||||||
|
LinkIncremental="1"
|
||||||
|
SuppressStartupBanner="TRUE"
|
||||||
|
ProgramDatabaseFile=".\Release/Applewin.pdb"
|
||||||
|
SubSystem="2"
|
||||||
|
TargetMachine="1"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
PreprocessorDefinitions="NDEBUG"
|
||||||
|
MkTypLibCompatible="TRUE"
|
||||||
|
SuppressStartupBanner="TRUE"
|
||||||
|
TargetEnvironment="1"
|
||||||
|
TypeLibraryName=".\Release/Applewin.tlb"
|
||||||
|
HeaderFileName=""/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
PreprocessorDefinitions="NDEBUG"
|
||||||
|
Culture="1033"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebDeploymentTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedWrapperGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||||
|
</Configuration>
|
||||||
|
<Configuration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
OutputDirectory=".\Debug"
|
||||||
|
IntermediateDirectory=".\Debug"
|
||||||
|
ConfigurationType="1"
|
||||||
|
UseOfMFC="0"
|
||||||
|
ATLMinimizesCRunTimeLibraryUsage="FALSE">
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
AdditionalOptions="/Zm200 "
|
||||||
|
Optimization="0"
|
||||||
|
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"
|
||||||
|
RuntimeLibrary="5"
|
||||||
|
UsePrecompiledHeader="2"
|
||||||
|
PrecompiledHeaderFile=".\Debug/Applewin.pch"
|
||||||
|
AssemblerListingLocation=".\Debug/"
|
||||||
|
ObjectFile=".\Debug/"
|
||||||
|
ProgramDataBaseFileName=".\Debug/"
|
||||||
|
BrowseInformation="1"
|
||||||
|
WarningLevel="3"
|
||||||
|
SuppressStartupBanner="TRUE"
|
||||||
|
DebugInformationFormat="3"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCCustomBuildTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCLinkerTool"
|
||||||
|
AdditionalDependencies="htmlhelp.lib comctl32.lib ddraw.lib winmm.lib dsound.lib dxguid.lib version.lib strmiids.lib"
|
||||||
|
OutputFile=".\Debug/Applewin.exe"
|
||||||
|
LinkIncremental="1"
|
||||||
|
SuppressStartupBanner="TRUE"
|
||||||
|
GenerateDebugInformation="TRUE"
|
||||||
|
ProgramDatabaseFile=".\Debug/Applewin.pdb"
|
||||||
|
SubSystem="2"
|
||||||
|
TargetMachine="1"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCMIDLTool"
|
||||||
|
PreprocessorDefinitions="_DEBUG"
|
||||||
|
MkTypLibCompatible="TRUE"
|
||||||
|
SuppressStartupBanner="TRUE"
|
||||||
|
TargetEnvironment="1"
|
||||||
|
TypeLibraryName=".\Debug/Applewin.tlb"
|
||||||
|
HeaderFileName=""/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPostBuildEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreBuildEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCPreLinkEventTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
PreprocessorDefinitions="_DEBUG"
|
||||||
|
Culture="1033"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebServiceProxyGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCXMLDataGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCWebDeploymentTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCManagedWrapperGeneratorTool"/>
|
||||||
|
<Tool
|
||||||
|
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||||
|
</Configuration>
|
||||||
|
</Configurations>
|
||||||
|
<References>
|
||||||
|
</References>
|
||||||
|
<Files>
|
||||||
|
<Filter
|
||||||
|
Name="Source"
|
||||||
|
Filter=".cpp">
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Applewin.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Applewin.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\AY8910.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\AY8910.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\CPU.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\CPU.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Debug.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Debug.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Disk.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Disk.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\DiskImage.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\DiskImage.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Frame.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Frame.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Harddisk.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Harddisk.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Joystick.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Joystick.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Keyboard.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Keyboard.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Memory.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Memory.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Mockingboard.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Mockingboard.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\PropertySheetPage.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\PropertySheetPage.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Registry.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Registry.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Riff.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Riff.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\SaveState.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\SaveState.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\SerialComms.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\SerialComms.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\SoundCore.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\SoundCore.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Speaker.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Speaker.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Video.cpp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Video.h">
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Docs"
|
||||||
|
Filter="">
|
||||||
|
<File
|
||||||
|
RelativePath=".\docs\Bugs.txt">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\docs\CodingConventions.txt">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\docs\History.txt">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\docs\ToDo.txt">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\docs\Wishlist.txt">
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Resources"
|
||||||
|
Filter=".txt,.ico,.bmp,.rc">
|
||||||
|
<File
|
||||||
|
RelativePath=".\resource\Applewin.bmp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\APPLEWIN.ICO">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\APPLEWIN.RC">
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|Win32">
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
PreprocessorDefinitions=""
|
||||||
|
AdditionalIncludeDirectories="RESOURCE"/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|Win32">
|
||||||
|
<Tool
|
||||||
|
Name="VCResourceCompilerTool"
|
||||||
|
PreprocessorDefinitions=""
|
||||||
|
AdditionalIncludeDirectories="RESOURCE"/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\CAPSOFF.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\CAPSON.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\CHARSET4.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\COLOR.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\DEBUG.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\DISK.ICO">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\DISKOFF.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\DISKREAD.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\DISKWRIT.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\DRIVE1.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\DRIVE2.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="Resource\DriveSwap.bmp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="Resource\DRSWAP.bmp">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\FULLSCR.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="Resource\Hddrvr.bin">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\HELP.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\RUN.BMP">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="RESOURCE\SETUP.BMP">
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Common.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\resource\resource.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\SSI263Phonemes.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\StdAfx.h">
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\source\Structs.h">
|
||||||
|
</File>
|
||||||
|
</Files>
|
||||||
|
<Globals>
|
||||||
|
</Globals>
|
||||||
|
</VisualStudioProject>
|
|
@ -0,0 +1,340 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
|
@ -6,6 +6,8 @@
|
||||||
the Disk 1 and then start the emulator, it will get stuck shortly after accessing the disk drive
|
the Disk 1 and then start the emulator, it will get stuck shortly after accessing the disk drive
|
||||||
for a moment. But if, after selecting Disk 1, I start the debugger and then issue the "G" command,
|
for a moment. But if, after selecting Disk 1, I start the debugger and then issue the "G" command,
|
||||||
it runs just fine.
|
it runs just fine.
|
||||||
|
. Jumpan doesn't seem to respond correctly to the controller, it moves in one direction only.
|
||||||
|
I'm unsure if this is an emulation problem or bad disk image. [TC: Unconfirmed]
|
||||||
|
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,12 @@ Acknowledgements:
|
||||||
- SSI263 phoneme samples from Chris Foxwell (still missing phoneme #0!)
|
- SSI263 phoneme samples from Chris Foxwell (still missing phoneme #0!)
|
||||||
- Harddisk card: source module & f/w by Robert Hoem
|
- Harddisk card: source module & f/w by Robert Hoem
|
||||||
|
|
||||||
|
1.12.9.0 - 25 Feb 2006
|
||||||
|
----------------------
|
||||||
|
- Moved source to BerliOS & released under GPL
|
||||||
|
- Debugger v2.4.2.16:
|
||||||
|
+ Breakpoint on memory address added: BPM address[,length]
|
||||||
|
|
||||||
1.12.8.0 - 22 Feb 2006
|
1.12.8.0 - 22 Feb 2006
|
||||||
----------------------
|
----------------------
|
||||||
- *** Major re-write of debugger by Michael Pohoreski ***
|
- *** Major re-write of debugger by Michael Pohoreski ***
|
||||||
|
@ -30,7 +36,7 @@ Acknowledgements:
|
||||||
+ Syntax coloring, navigation, execution (eg. step-out), view memory as varying Ascii types
|
+ Syntax coloring, navigation, execution (eg. step-out), view memory as varying Ascii types
|
||||||
+ Symbol maintenance (main, user, source), source-level debugging, mini-calculator
|
+ Symbol maintenance (main, user, source), source-level debugging, mini-calculator
|
||||||
+ Breakpoints: conditional on register, profiling + much more
|
+ Breakpoints: conditional on register, profiling + much more
|
||||||
. See: http://www.tomcharlesworth.pwp.blueyonder.co.uk/Intro_To_New_Debugger.htm
|
. See: http://applewin.berlios.de/Intro_To_New_Debugger.htm
|
||||||
- Fixed speaker volume not being set correctly at start-up
|
- Fixed speaker volume not being set correctly at start-up
|
||||||
- Fixed emulation speed control (was only running at 1MHz)
|
- Fixed emulation speed control (was only running at 1MHz)
|
||||||
- Fixed internal ADC: was flagged as write to memory
|
- Fixed internal ADC: was flagged as write to memory
|
||||||
|
|
|
@ -8,6 +8,10 @@ Priority:
|
||||||
. DONE: Shift+Ins to paste from clipboard
|
. DONE: Shift+Ins to paste from clipboard
|
||||||
. DONE: Cmd-line switches for: d1, d2, full-screen
|
. DONE: Cmd-line switches for: d1, d2, full-screen
|
||||||
|
|
||||||
|
Post 1.12.8.0:
|
||||||
|
- I have multiple controllers and was wondering if a future version of the emulator
|
||||||
|
could support selecting the joystick you want to use in the emulator.
|
||||||
|
|
||||||
Post 1.12.7.0:
|
Post 1.12.7.0:
|
||||||
- Light-gun support (if pixel under mouse is set, then set $C061.b7 (Richard Jackson))
|
- Light-gun support (if pixel under mouse is set, then set $C061.b7 (Richard Jackson))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
a65 -b -l HDDRVR.A65 >hddrvr.lst
|
||||||
|
@del HDDRVR.BIN
|
||||||
|
rename 6502.bin HDDRVR.BIN
|
||||||
|
copy HDDRVR.BIN ..\Resource
|
|
@ -0,0 +1,178 @@
|
||||||
|
; AppleWin: Firmware for harddisk card
|
||||||
|
;
|
||||||
|
; Copyright (c) 2005 Robert Hoem. All rights reserved.
|
||||||
|
;
|
||||||
|
; Assemble with a65.exe (1.06)
|
||||||
|
;
|
||||||
|
; Modified by Tom Charlesworth:
|
||||||
|
; . Fixed so it can be assembled by a65 v1.06
|
||||||
|
; . TO DO: Make code relocatable
|
||||||
|
;
|
||||||
|
|
||||||
|
; constants
|
||||||
|
hd_execute = $c0f0
|
||||||
|
hd_error = $c0f1
|
||||||
|
hd_command = $c0f2
|
||||||
|
hd_unitnum = $c0f3
|
||||||
|
hd_memblock = $c0f4
|
||||||
|
hd_diskblock = $c0f6
|
||||||
|
hd_nextbyte = $c0f8
|
||||||
|
|
||||||
|
command = $42
|
||||||
|
unitnum = $43
|
||||||
|
memblock = $44
|
||||||
|
diskblock = $46
|
||||||
|
|
||||||
|
slot6 = $c600
|
||||||
|
OS = $0801
|
||||||
|
|
||||||
|
; The Autoboot rom will call this.
|
||||||
|
; This is also the entry point for such things as IN#7 and PR#7
|
||||||
|
|
||||||
|
;; code
|
||||||
|
*= $c700 ; org $c700
|
||||||
|
|
||||||
|
start
|
||||||
|
|
||||||
|
; Autoboot and ProDos look at the following few opcodes to detect block devices
|
||||||
|
lda #$20
|
||||||
|
lda #$00
|
||||||
|
lda #$03
|
||||||
|
lda #$3C
|
||||||
|
|
||||||
|
; Lets check to see if there's an image ready
|
||||||
|
lda #$00
|
||||||
|
sta hd_command
|
||||||
|
|
||||||
|
; Slot 7, disk 1
|
||||||
|
lda #$70 ; Slot# << 4
|
||||||
|
sta hd_unitnum
|
||||||
|
lda hd_execute
|
||||||
|
|
||||||
|
; error capturing code. Applewin is picky
|
||||||
|
; about code assigning data to registers and
|
||||||
|
; memory. The safest method is via I/O port
|
||||||
|
pha
|
||||||
|
lda hd_error
|
||||||
|
clc
|
||||||
|
cmp #1
|
||||||
|
bne noerr0
|
||||||
|
sec
|
||||||
|
noerr0
|
||||||
|
pla
|
||||||
|
bcc hdboot
|
||||||
|
|
||||||
|
; no image ready, boot diskette image instead
|
||||||
|
jmp slot6
|
||||||
|
|
||||||
|
; image ready. Lets boot from it.
|
||||||
|
; we want to load block 1 from s7,d1 to $800 then jump there
|
||||||
|
hdboot
|
||||||
|
lda #$70 ; Slot# << 4
|
||||||
|
sta unitnum
|
||||||
|
lda #$0
|
||||||
|
sta memblock
|
||||||
|
sta diskblock
|
||||||
|
sta diskblock+1
|
||||||
|
lda #$8
|
||||||
|
sta memblock+1
|
||||||
|
lda #$1
|
||||||
|
sta command
|
||||||
|
jsr cmdproc
|
||||||
|
bcc goload
|
||||||
|
jmp slot6
|
||||||
|
goload
|
||||||
|
|
||||||
|
; X=device
|
||||||
|
ldx #$70 ; Slot# << 4
|
||||||
|
jmp OS
|
||||||
|
|
||||||
|
; entry point for Prodos' block driver
|
||||||
|
; simple really. Copy the command from $42..$47
|
||||||
|
; to our I/O ports then execute command
|
||||||
|
cmdproc
|
||||||
|
clc
|
||||||
|
lda $42
|
||||||
|
sta hd_command
|
||||||
|
lda $43
|
||||||
|
sta hd_unitnum
|
||||||
|
lda $44
|
||||||
|
sta hd_memblock
|
||||||
|
lda $45
|
||||||
|
sta hd_memblock+1
|
||||||
|
lda $46
|
||||||
|
sta hd_diskblock
|
||||||
|
lda $47
|
||||||
|
sta hd_diskblock+1
|
||||||
|
lda hd_execute
|
||||||
|
|
||||||
|
; check for error
|
||||||
|
pha
|
||||||
|
lda command
|
||||||
|
cmp #1
|
||||||
|
bne skipSread
|
||||||
|
jsr sread
|
||||||
|
skipSread
|
||||||
|
lda hd_error
|
||||||
|
clc
|
||||||
|
cmp #1
|
||||||
|
bne noerr2
|
||||||
|
sec
|
||||||
|
noerr2
|
||||||
|
pla
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
; if there's no error, then lets read the block into memory
|
||||||
|
; because Applewin is picky about memory management, here's what I did:
|
||||||
|
; on read, hd_nextbyte = buffer[0], therefore we'll read that byte 256 times (in which
|
||||||
|
; the emulated code increments the buffer by 1 on each read) to (memblock),y
|
||||||
|
; increment memblock+1 and read the secod 256 bytes via hd_nextbyte.
|
||||||
|
;
|
||||||
|
; if I could figure out how to consistantly get applewin to update it's memory regions all
|
||||||
|
; this code can be moved into the emulation code (although, this is how I'd build the hardware
|
||||||
|
; anyway...)
|
||||||
|
|
||||||
|
sread
|
||||||
|
tya
|
||||||
|
pha
|
||||||
|
ldy #0
|
||||||
|
loop1
|
||||||
|
lda hd_nextbyte
|
||||||
|
sta (memblock),y
|
||||||
|
iny
|
||||||
|
bne loop1
|
||||||
|
inc memblock+1
|
||||||
|
ldy #0
|
||||||
|
loop2
|
||||||
|
lda hd_nextbyte
|
||||||
|
sta (memblock),y
|
||||||
|
iny
|
||||||
|
bne loop2
|
||||||
|
pla
|
||||||
|
tay
|
||||||
|
rts
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
; $CsFE = status bits (BAP p7-14)
|
||||||
|
; 7 = medium is removable
|
||||||
|
; 6 = device is interruptable
|
||||||
|
; 5-4 = number of volumes (0..3 means 1..4)
|
||||||
|
; 3 = device supports Format call
|
||||||
|
; 2 = device can be written to
|
||||||
|
; 1 = device can be read from (must be 1)
|
||||||
|
; 0 = device status can be read (must be 1)
|
||||||
|
|
||||||
|
; $C7 = Removable, Interruptable, #Volumes=1, Supports write/read/status
|
||||||
|
; $D7 = Removable, Interruptable, #Volumes=2, Supports write/read/status
|
||||||
|
|
||||||
|
|
||||||
|
; datablock. This starts near the end of the firmware (at offset $FC)
|
||||||
|
;; data
|
||||||
|
*= $c7fc ; org $c7fc
|
||||||
|
.word $7fff ; how many blocks are on the device.
|
||||||
|
.byte $D7 ; specifics about the device (number of drives, read/write/format capability, etc)
|
||||||
|
.byte <cmdproc ; entry point offset for Prodos
|
||||||
|
|
||||||
|
.end
|
After Width: | Height: | Size: 3.2 KiB |
After Width: | Height: | Size: 211 KiB |
|
@ -0,0 +1,302 @@
|
||||||
|
// Microsoft Visual C++ generated resource script.
|
||||||
|
//
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
#define APSTUDIO_READONLY_SYMBOLS
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Generated from the TEXTINCLUDE 2 resource.
|
||||||
|
//
|
||||||
|
#include "winres.h"
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
#undef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// English (U.S.) resources
|
||||||
|
|
||||||
|
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||||
|
#ifdef _WIN32
|
||||||
|
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
|
#pragma code_page(1252)
|
||||||
|
#endif //_WIN32
|
||||||
|
|
||||||
|
#ifdef APSTUDIO_INVOKED
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// TEXTINCLUDE
|
||||||
|
//
|
||||||
|
|
||||||
|
1 TEXTINCLUDE
|
||||||
|
BEGIN
|
||||||
|
"resource.h\0"
|
||||||
|
END
|
||||||
|
|
||||||
|
2 TEXTINCLUDE
|
||||||
|
BEGIN
|
||||||
|
"#include ""winres.h""\r\n"
|
||||||
|
"\0"
|
||||||
|
END
|
||||||
|
|
||||||
|
3 TEXTINCLUDE
|
||||||
|
BEGIN
|
||||||
|
"\r\n"
|
||||||
|
"\0"
|
||||||
|
END
|
||||||
|
|
||||||
|
#endif // APSTUDIO_INVOKED
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Bitmap
|
||||||
|
//
|
||||||
|
|
||||||
|
FULLSCR_BUTTON BITMAP "FULLSCR.BMP"
|
||||||
|
RUN_BUTTON BITMAP "RUN.BMP"
|
||||||
|
DEBUG_BUTTON BITMAP "DEBUG.BMP"
|
||||||
|
DRIVE1_BUTTON BITMAP "DRIVE1.BMP"
|
||||||
|
DRIVE2_BUTTON BITMAP "DRIVE2.BMP"
|
||||||
|
SETUP_BUTTON BITMAP "SETUP.BMP"
|
||||||
|
CHARSET40 BITMAP "CHARSET4.BMP"
|
||||||
|
DISKOFF_BITMAP BITMAP "DISKOFF.BMP"
|
||||||
|
DISKREAD_BITMAP BITMAP "DISKREAD.BMP"
|
||||||
|
DISKWRITE_BITMAP BITMAP "DISKWRIT.BMP"
|
||||||
|
CAPSOFF_BITMAP BITMAP "CAPSOFF.BMP"
|
||||||
|
CAPSON_BITMAP BITMAP "CAPSON.BMP"
|
||||||
|
HELP_BUTTON BITMAP "HELP.BMP"
|
||||||
|
DRIVESWAP_BUTTON BITMAP "DRIVESWAP.BMP"
|
||||||
|
IDB_APPLEWIN BITMAP "Applewin.bmp"
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Dialog
|
||||||
|
//
|
||||||
|
|
||||||
|
IDD_PROPPAGE_CONFIG DIALOG 0, 0, 210, 221
|
||||||
|
STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION |
|
||||||
|
WS_SYSMENU
|
||||||
|
CAPTION "Configuration"
|
||||||
|
FONT 8, "MS Sans Serif"
|
||||||
|
BEGIN
|
||||||
|
GROUPBOX "Emulation Speed Control",IDC_STATIC,5,115,200,85
|
||||||
|
CONTROL "Use &Authentic Machine Speed",IDC_AUTHENTIC_SPEED,
|
||||||
|
"Button",BS_AUTORADIOBUTTON,15,126,115,10
|
||||||
|
CONTROL "Select C&ustom Speed (in MHz)",IDC_CUSTOM_SPEED,"Button",
|
||||||
|
BS_AUTORADIOBUTTON,15,138,115,10
|
||||||
|
CONTROL "Generic2",IDC_SLIDER_CPU_SPEED,"msctls_trackbar32",
|
||||||
|
TBS_AUTOTICKS | WS_TABSTOP,25,149,160,15
|
||||||
|
CTEXT "0.5",IDC_0_5_MHz,23,165,20,10
|
||||||
|
CTEXT "1.0",IDC_1_0_MHz,59,165,20,10
|
||||||
|
CTEXT "2.0",IDC_2_0_MHz,96,165,20,10
|
||||||
|
RTEXT "Fastest",IDC_MAX_MHz,150,165,29,10
|
||||||
|
PUSHBUTTON "&Benchmark Emulator",IDC_BENCHMARK,15,179,85,15
|
||||||
|
LTEXT "&Computer:",IDC_STATIC,5,13,40,8
|
||||||
|
COMBOBOX IDC_COMPUTER,45,11,100,100,CBS_DROPDOWNLIST | WS_VSCROLL |
|
||||||
|
WS_TABSTOP
|
||||||
|
LTEXT "&Video:",IDC_STATIC,5,36,40,8
|
||||||
|
COMBOBOX IDC_VIDEOTYPE,45,34,100,100,CBS_DROPDOWNLIST |
|
||||||
|
WS_VSCROLL | WS_TABSTOP
|
||||||
|
LTEXT "S&erial Port:",IDC_STATIC,5,50,40,8
|
||||||
|
COMBOBOX IDC_SERIALPORT,45,48,100,100,CBS_DROPDOWNLIST |
|
||||||
|
WS_VSCROLL | WS_TABSTOP
|
||||||
|
PUSHBUTTON "Monochrome Color...",IDC_MONOCOLOR,15,90,80,14
|
||||||
|
END
|
||||||
|
|
||||||
|
IDD_PROPPAGE_INPUT DIALOGEX 0, 0, 210, 221
|
||||||
|
STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION |
|
||||||
|
WS_SYSMENU
|
||||||
|
CAPTION "Input"
|
||||||
|
FONT 8, "MS Sans Serif", 0, 0, 0x0
|
||||||
|
BEGIN
|
||||||
|
PUSHBUTTON "Paste from clipboard",IDC_PASTE_FROM_CLIPBOARD,5,163,75,
|
||||||
|
14
|
||||||
|
GROUPBOX "Joystick Control",IDC_STATIC,5,20,200,80
|
||||||
|
LTEXT "&Joystick1:",IDC_STATIC,12,33,40,8
|
||||||
|
COMBOBOX IDC_JOYSTICK0,52,31,100,100,CBS_DROPDOWNLIST |
|
||||||
|
WS_VSCROLL | WS_TABSTOP
|
||||||
|
LTEXT "&Joystick2:",IDC_STATIC,12,48,40,8
|
||||||
|
COMBOBOX IDC_JOYSTICK1,52,46,100,100,CBS_DROPDOWNLIST |
|
||||||
|
WS_VSCROLL | WS_TABSTOP
|
||||||
|
LTEXT "X-trim:",IDC_STATIC,13,72,28,8
|
||||||
|
CTEXT "0",IDC_STATIC,36,66,24,20,SS_CENTERIMAGE
|
||||||
|
CONTROL "Spin1",IDC_SPIN_XTRIM,"msctls_updown32",UDS_SETBUDDYINT |
|
||||||
|
UDS_ALIGNLEFT | UDS_AUTOBUDDY,59,69,10,14
|
||||||
|
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
|
||||||
|
LTEXT "(Shift+Insert during emulation)",IDC_STATIC,89,166,94,8
|
||||||
|
END
|
||||||
|
|
||||||
|
IDD_PROPPAGE_SOUND DIALOGEX 0, 0, 210, 221
|
||||||
|
STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION |
|
||||||
|
WS_SYSMENU
|
||||||
|
CAPTION "Sound"
|
||||||
|
FONT 8, "MS Sans Serif", 0, 0, 0x0
|
||||||
|
BEGIN
|
||||||
|
LTEXT "&Sound:",IDC_STATIC,5,29,40,8
|
||||||
|
COMBOBOX IDC_SOUNDTYPE,45,27,100,100,CBS_DROPDOWNLIST |
|
||||||
|
WS_VSCROLL | WS_TABSTOP
|
||||||
|
GROUPBOX "Volume Control",IDC_STATIC,5,55,100,89
|
||||||
|
CONTROL "Slider1",IDC_SPKR_VOLUME,"msctls_trackbar32",
|
||||||
|
TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP,13,78,
|
||||||
|
28,60
|
||||||
|
LTEXT "Speaker:",IDC_STATIC,11,70,31,8
|
||||||
|
GROUPBOX "Mockingboard/Phasor Control",IDC_STATIC,6,153,197,61
|
||||||
|
LTEXT "Mockingboard:",IDC_STATIC,49,70,51,8
|
||||||
|
CONTROL "Slider1",IDC_MB_VOLUME,"msctls_trackbar32",
|
||||||
|
TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP,59,78,
|
||||||
|
25,60
|
||||||
|
CONTROL "Enable Mockingboards (in slots 4 && 5)",IDC_MB_ENABLE,
|
||||||
|
"Button",BS_AUTORADIOBUTTON | BS_NOTIFY,10,167,142,8
|
||||||
|
CONTROL "Enable Phasor (in slot 4)",IDC_PHASOR_ENABLE,"Button",
|
||||||
|
BS_AUTORADIOBUTTON | BS_NOTIFY,10,180,92,10
|
||||||
|
CONTROL "Disable soundcards",IDC_SOUNDCARD_DISABLE,"Button",
|
||||||
|
BS_AUTORADIOBUTTON | BS_NOTIFY,10,194,78,10
|
||||||
|
END
|
||||||
|
|
||||||
|
IDD_PROPPAGE_SAVESTATE DIALOG 0, 0, 210, 221
|
||||||
|
STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION |
|
||||||
|
WS_SYSMENU
|
||||||
|
CAPTION "Save State"
|
||||||
|
FONT 8, "MS Sans Serif"
|
||||||
|
BEGIN
|
||||||
|
LTEXT "Save State file name:",IDC_STATIC,5,29,74,8
|
||||||
|
GROUPBOX "Save State Control",IDC_STATIC,5,74,200,73
|
||||||
|
CONTROL "Save State on exit",IDC_SAVESTATE_ON_EXIT,"Button",
|
||||||
|
BS_AUTOCHECKBOX | WS_TABSTOP,16,85,74,10
|
||||||
|
PUSHBUTTON "Save State",IDC_SAVESTATE,16,102,85,15
|
||||||
|
PUSHBUTTON "Load State",IDC_LOADSTATE,16,124,85,15
|
||||||
|
EDITTEXT IDC_SAVESTATE_FILENAME,5,40,143,12,ES_AUTOHSCROLL
|
||||||
|
LTEXT "(F11 during emulation)",IDC_STATIC,110,105,74,8
|
||||||
|
LTEXT "(F12 during emulation)",IDC_STATIC,110,127,90,8
|
||||||
|
PUSHBUTTON "Browse...",IDC_SAVESTATE_BROWSE,154,39,50,14
|
||||||
|
END
|
||||||
|
|
||||||
|
IDD_PROPPAGE_DISK DIALOGEX 0, 0, 210, 221
|
||||||
|
STYLE DS_SETFONT | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION |
|
||||||
|
WS_SYSMENU
|
||||||
|
CAPTION "Disk"
|
||||||
|
FONT 8, "MS Sans Serif", 0, 0, 0x0
|
||||||
|
BEGIN
|
||||||
|
LTEXT "&Disk access speed:",IDC_STATIC,7,34,64,8
|
||||||
|
COMBOBOX IDC_DISKTYPE,85,33,100,100,CBS_DROPDOWNLIST | WS_VSCROLL |
|
||||||
|
WS_TABSTOP
|
||||||
|
PUSHBUTTON "Select HDD1",IDC_HDD1,5,142,70,14
|
||||||
|
PUSHBUTTON "Select HDD2",IDC_HDD2,5,162,70,14
|
||||||
|
PUSHBUTTON "Select Disk1",IDC_DISK1,5,53,70,14
|
||||||
|
PUSHBUTTON "Select Disk2",IDC_DISK2,5,74,70,14
|
||||||
|
EDITTEXT IDC_EDIT_DISK1,85,54,115,12,ES_AUTOHSCROLL | ES_READONLY
|
||||||
|
EDITTEXT IDC_EDIT_DISK2,85,74,115,12,ES_AUTOHSCROLL | ES_READONLY
|
||||||
|
EDITTEXT IDC_EDIT_HDD1,85,143,115,12,ES_AUTOHSCROLL | ES_READONLY
|
||||||
|
EDITTEXT IDC_EDIT_HDD2,85,163,115,12,ES_AUTOHSCROLL | ES_READONLY
|
||||||
|
CONTROL "Enable harddisk in slot 7",IDC_HDD_ENABLE,"Button",
|
||||||
|
BS_AUTOCHECKBOX | WS_TABSTOP,5,126,120,10
|
||||||
|
GROUPBOX "Floppy Controller",IDC_STATIC,2,21,206,73
|
||||||
|
GROUPBOX "Harddisk Controller",IDC_STATIC,2,113,205,71
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Icon
|
||||||
|
//
|
||||||
|
|
||||||
|
// Icon with lowest ID value placed first to ensure application icon
|
||||||
|
// remains consistent on all systems.
|
||||||
|
APPLEWIN_ICON ICON "APPLEWIN.ICO"
|
||||||
|
DISK_ICON ICON "DISK.ICO"
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Version
|
||||||
|
//
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION 1,12,9,0
|
||||||
|
PRODUCTVERSION 1,12,9,0
|
||||||
|
FILEFLAGSMASK 0x3fL
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS 0x1L
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS 0x40004L
|
||||||
|
FILETYPE 0x1L
|
||||||
|
FILESUBTYPE 0x0L
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "04090000"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Comments", "http://www.tomcharlesworth.pwp.blueyonder.co.uk/applewin/"
|
||||||
|
VALUE "CompanyName", "Michael O'Brien, Oliver Schmidt, Tom Charlesworth"
|
||||||
|
VALUE "FileDescription", "Apple //e Emulator for Windows"
|
||||||
|
VALUE "FileVersion", "1, 12, 9, 0"
|
||||||
|
VALUE "InternalName", "APPLEWIN"
|
||||||
|
VALUE "LegalCopyright", "© 1994-2006 Michael O'Brien, Oliver Schmidt, Tom Charlesworth"
|
||||||
|
VALUE "OriginalFilename", "APPLEWIN.EXE"
|
||||||
|
VALUE "ProductName", "Apple //e Emulator"
|
||||||
|
VALUE "ProductVersion", "1, 12, 9, 0"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 0
|
||||||
|
END
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Accelerator
|
||||||
|
//
|
||||||
|
|
||||||
|
IDR_ACCELERATOR1 ACCELERATORS
|
||||||
|
BEGIN
|
||||||
|
"/", IDM_ABOUT, ASCII, ALT, NOINVERT
|
||||||
|
"?", IDM_ABOUT, ASCII, ALT, NOINVERT
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Data
|
||||||
|
//
|
||||||
|
|
||||||
|
IDR_HDDRVR RCDATA "Hddrvr.bin"
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Menu
|
||||||
|
//
|
||||||
|
|
||||||
|
IDR_MENU1 MENU
|
||||||
|
BEGIN
|
||||||
|
POPUP "&File"
|
||||||
|
BEGIN
|
||||||
|
MENUITEM "E&xit", IDM_EXIT
|
||||||
|
END
|
||||||
|
POPUP "Help"
|
||||||
|
BEGIN
|
||||||
|
MENUITEM "&Help", IDM_HELP
|
||||||
|
MENUITEM "&About", IDM_ABOUT
|
||||||
|
END
|
||||||
|
END
|
||||||
|
|
||||||
|
#endif // English (U.S.) resources
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef APSTUDIO_INVOKED
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Generated from the TEXTINCLUDE 3 resource.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
#endif // not APSTUDIO_INVOKED
|
||||||
|
|
After Width: | Height: | Size: 262 B |
After Width: | Height: | Size: 262 B |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 190 B |
After Width: | Height: | Size: 190 B |
After Width: | Height: | Size: 190 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,67 @@
|
||||||
|
//{{NO_DEPENDENCIES}}
|
||||||
|
// Microsoft Visual C++ generated include file.
|
||||||
|
// Used by Applewin.rc
|
||||||
|
//
|
||||||
|
#define IDC_COMPUTER 101
|
||||||
|
#define IDC_JOYSTICK0 102
|
||||||
|
#define IDC_SOUNDTYPE 103
|
||||||
|
#define IDC_SERIALPORT 104
|
||||||
|
#define IDR_MENU1 104
|
||||||
|
#define IDR_ACCELERATOR1 105
|
||||||
|
#define IDC_VIDEOTYPE 105
|
||||||
|
#define IDD_PROPPAGE_INPUT 106
|
||||||
|
#define IDC_AUTHENTIC_SPEED 106
|
||||||
|
#define IDD_PROPPAGE_CONFIG 107
|
||||||
|
#define IDC_CUSTOM_SPEED 107
|
||||||
|
#define IDC_SLIDER_CPU_SPEED 108
|
||||||
|
#define IDD_PROPPAGE_SOUND 108
|
||||||
|
#define IDC_DISKTYPE 109
|
||||||
|
#define IDD_PROPPAGE_SAVESTATE 109
|
||||||
|
#define IDC_JOYSTICK1 110
|
||||||
|
#define IDD_PROPPAGE_DISK 110
|
||||||
|
#define IDC_BENCHMARK 111
|
||||||
|
#define IDC_LOADSTATE 112
|
||||||
|
#define IDR_HDDRVR 115
|
||||||
|
#define IDC_0_5_MHz 121
|
||||||
|
#define IDB_APPLEWIN 121
|
||||||
|
#define IDC_1_0_MHz 122
|
||||||
|
#define IDC_2_0_MHz 123
|
||||||
|
#define IDC_MAX_MHz 124
|
||||||
|
#define IDC_MB_ENABLE 130
|
||||||
|
#define IDC_KEYB_BUFFER_ENABLE 1005
|
||||||
|
#define IDC_SAVESTATE 1006
|
||||||
|
#define IDC_SAVESTATE_ON_EXIT 1007
|
||||||
|
#define IDC_SAVESTATE_FILENAME 1008
|
||||||
|
#define IDC_SPKR_VOLUME 1009
|
||||||
|
#define IDC_MB_VOLUME 1010
|
||||||
|
#define IDC_SAVESTATE_BROWSE 1011
|
||||||
|
#define IDC_MONOCOLOR 1012
|
||||||
|
#define IDC_HDD1 1013
|
||||||
|
#define IDC_HDD2 1014
|
||||||
|
#define IDC_DISK1 1015
|
||||||
|
#define IDC_DISK2 1016
|
||||||
|
#define IDC_EDIT_DISK1 1017
|
||||||
|
#define IDC_EDIT_DISK2 1018
|
||||||
|
#define IDC_PASTE_FROM_CLIPBOARD 1018
|
||||||
|
#define IDC_EDIT_HDD1 1019
|
||||||
|
#define IDC_EDIT_HDD2 1020
|
||||||
|
#define IDC_HDD_ENABLE 1021
|
||||||
|
#define IDC_SPIN_XTRIM 1026
|
||||||
|
#define IDC_SPIN_YTRIM 1027
|
||||||
|
#define IDC_PHASOR_ENABLE 1029
|
||||||
|
#define IDC_SOUNDCARD_DISABLE 1030
|
||||||
|
#define IDM_EXIT 40001
|
||||||
|
#define IDM_HELP 40002
|
||||||
|
#define IDM_ABOUT 40003
|
||||||
|
|
||||||
|
// Next default values for new objects
|
||||||
|
//
|
||||||
|
#ifdef APSTUDIO_INVOKED
|
||||||
|
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
#define _APS_NO_MFC 1
|
||||||
|
#define _APS_NEXT_RESOURCE_VALUE 122
|
||||||
|
#define _APS_NEXT_COMMAND_VALUE 40004
|
||||||
|
#define _APS_NEXT_CONTROL_VALUE 1031
|
||||||
|
#define _APS_NEXT_SYMED_VALUE 101
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,751 @@
|
||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
ay8910.c
|
||||||
|
|
||||||
|
|
||||||
|
Emulation of the AY-3-8910 / YM2149 sound chip.
|
||||||
|
|
||||||
|
Based on various code snippets by Ville Hallik, Michael Cuddy,
|
||||||
|
Tatsuyuki Satoh, Fabrice Frances, Nicola Salmoria.
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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 <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <crtdbg.h>
|
||||||
|
#include "ay8910.h"
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
// typedefs & dummy funcs to allow MAME code to compile:
|
||||||
|
|
||||||
|
typedef UINT8 (*mem_read_handler)(UINT32);
|
||||||
|
typedef void (*mem_write_handler)(UINT32, UINT8);
|
||||||
|
|
||||||
|
static void logerror(char* psz, ...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned short activecpu_get_pc()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define MAX_OUTPUT 0x7fff
|
||||||
|
|
||||||
|
// See AY8910_set_clock() for definition of STEP
|
||||||
|
#define STEP 0x8000
|
||||||
|
|
||||||
|
|
||||||
|
static int num = 0, ym_num = 0;
|
||||||
|
|
||||||
|
struct AY8910
|
||||||
|
{
|
||||||
|
int Channel;
|
||||||
|
int SampleRate;
|
||||||
|
mem_read_handler PortAread;
|
||||||
|
mem_read_handler PortBread;
|
||||||
|
mem_write_handler PortAwrite;
|
||||||
|
mem_write_handler PortBwrite;
|
||||||
|
int register_latch;
|
||||||
|
unsigned char Regs[16];
|
||||||
|
int lastEnable;
|
||||||
|
unsigned int UpdateStep;
|
||||||
|
int PeriodA,PeriodB,PeriodC,PeriodN,PeriodE;
|
||||||
|
int CountA,CountB,CountC,CountN,CountE;
|
||||||
|
unsigned int VolA,VolB,VolC,VolE;
|
||||||
|
unsigned char EnvelopeA,EnvelopeB,EnvelopeC;
|
||||||
|
unsigned char OutputA,OutputB,OutputC,OutputN;
|
||||||
|
signed char CountEnv;
|
||||||
|
unsigned char Hold,Alternate,Attack,Holding;
|
||||||
|
int RNG;
|
||||||
|
unsigned int VolTable[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* register id's */
|
||||||
|
#define AY_AFINE (0)
|
||||||
|
#define AY_ACOARSE (1)
|
||||||
|
#define AY_BFINE (2)
|
||||||
|
#define AY_BCOARSE (3)
|
||||||
|
#define AY_CFINE (4)
|
||||||
|
#define AY_CCOARSE (5)
|
||||||
|
#define AY_NOISEPER (6)
|
||||||
|
#define AY_ENABLE (7)
|
||||||
|
#define AY_AVOL (8)
|
||||||
|
#define AY_BVOL (9)
|
||||||
|
#define AY_CVOL (10)
|
||||||
|
#define AY_EFINE (11)
|
||||||
|
#define AY_ECOARSE (12)
|
||||||
|
#define AY_ESHAPE (13)
|
||||||
|
|
||||||
|
#define AY_PORTA (14)
|
||||||
|
#define AY_PORTB (15)
|
||||||
|
|
||||||
|
|
||||||
|
static struct AY8910 AYPSG[MAX_8910]; /* array of PSG's */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _AYWriteReg(int n, int r, int v)
|
||||||
|
{
|
||||||
|
struct AY8910 *PSG = &AYPSG[n];
|
||||||
|
int old;
|
||||||
|
|
||||||
|
|
||||||
|
PSG->Regs[r] = v;
|
||||||
|
|
||||||
|
//#define LOG_AY8910
|
||||||
|
#ifdef LOG_AY8910
|
||||||
|
extern FILE* g_fh; // Filehandle for log file
|
||||||
|
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
|
||||||
|
|
||||||
|
/* A note about the period of tones, noise and envelope: for speed reasons,*/
|
||||||
|
/* we count down from the period to 0, but careful studies of the chip */
|
||||||
|
/* output prove that it instead counts up from 0 until the counter becomes */
|
||||||
|
/* greater or equal to the period. This is an important difference when the*/
|
||||||
|
/* program is rapidly changing the period to modulate the sound. */
|
||||||
|
/* To compensate for the difference, when the period is changed we adjust */
|
||||||
|
/* our internal counter. */
|
||||||
|
/* Also, note that period = 0 is the same as period = 1. This is mentioned */
|
||||||
|
/* in the YM2203 data sheets. However, this does NOT apply to the Envelope */
|
||||||
|
/* period. In that case, period = 0 is half as period = 1. */
|
||||||
|
switch( r )
|
||||||
|
{
|
||||||
|
case AY_AFINE:
|
||||||
|
case AY_ACOARSE:
|
||||||
|
PSG->Regs[AY_ACOARSE] &= 0x0f;
|
||||||
|
old = PSG->PeriodA;
|
||||||
|
PSG->PeriodA = (PSG->Regs[AY_AFINE] + 256 * PSG->Regs[AY_ACOARSE]) * PSG->UpdateStep;
|
||||||
|
if (PSG->PeriodA == 0) PSG->PeriodA = PSG->UpdateStep;
|
||||||
|
PSG->CountA += PSG->PeriodA - old;
|
||||||
|
if (PSG->CountA <= 0) PSG->CountA = 1;
|
||||||
|
break;
|
||||||
|
case AY_BFINE:
|
||||||
|
case AY_BCOARSE:
|
||||||
|
PSG->Regs[AY_BCOARSE] &= 0x0f;
|
||||||
|
old = PSG->PeriodB;
|
||||||
|
PSG->PeriodB = (PSG->Regs[AY_BFINE] + 256 * PSG->Regs[AY_BCOARSE]) * PSG->UpdateStep;
|
||||||
|
if (PSG->PeriodB == 0) PSG->PeriodB = PSG->UpdateStep;
|
||||||
|
PSG->CountB += PSG->PeriodB - old;
|
||||||
|
if (PSG->CountB <= 0) PSG->CountB = 1;
|
||||||
|
break;
|
||||||
|
case AY_CFINE:
|
||||||
|
case AY_CCOARSE:
|
||||||
|
PSG->Regs[AY_CCOARSE] &= 0x0f;
|
||||||
|
old = PSG->PeriodC;
|
||||||
|
PSG->PeriodC = (PSG->Regs[AY_CFINE] + 256 * PSG->Regs[AY_CCOARSE]) * PSG->UpdateStep;
|
||||||
|
if (PSG->PeriodC == 0) PSG->PeriodC = PSG->UpdateStep;
|
||||||
|
PSG->CountC += PSG->PeriodC - old;
|
||||||
|
if (PSG->CountC <= 0) PSG->CountC = 1;
|
||||||
|
break;
|
||||||
|
case AY_NOISEPER:
|
||||||
|
PSG->Regs[AY_NOISEPER] &= 0x1f;
|
||||||
|
old = PSG->PeriodN;
|
||||||
|
PSG->PeriodN = PSG->Regs[AY_NOISEPER] * PSG->UpdateStep;
|
||||||
|
if (PSG->PeriodN == 0) PSG->PeriodN = PSG->UpdateStep;
|
||||||
|
PSG->CountN += PSG->PeriodN - old;
|
||||||
|
if (PSG->CountN <= 0) PSG->CountN = 1;
|
||||||
|
break;
|
||||||
|
case AY_ENABLE:
|
||||||
|
if ((PSG->lastEnable == -1) ||
|
||||||
|
((PSG->lastEnable & 0x40) != (PSG->Regs[AY_ENABLE] & 0x40)))
|
||||||
|
{
|
||||||
|
/* write out 0xff if port set to input */
|
||||||
|
if (PSG->PortAwrite)
|
||||||
|
(*PSG->PortAwrite)(0, (UINT8) ((PSG->Regs[AY_ENABLE] & 0x40) ? PSG->Regs[AY_PORTA] : 0xff)); // [TC: UINT8 cast]
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((PSG->lastEnable == -1) ||
|
||||||
|
((PSG->lastEnable & 0x80) != (PSG->Regs[AY_ENABLE] & 0x80)))
|
||||||
|
{
|
||||||
|
/* write out 0xff if port set to input */
|
||||||
|
if (PSG->PortBwrite)
|
||||||
|
(*PSG->PortBwrite)(0, (UINT8) ((PSG->Regs[AY_ENABLE] & 0x80) ? PSG->Regs[AY_PORTB] : 0xff)); // [TC: UINT8 cast]
|
||||||
|
}
|
||||||
|
|
||||||
|
PSG->lastEnable = PSG->Regs[AY_ENABLE];
|
||||||
|
break;
|
||||||
|
case AY_AVOL:
|
||||||
|
PSG->Regs[AY_AVOL] &= 0x1f;
|
||||||
|
PSG->EnvelopeA = PSG->Regs[AY_AVOL] & 0x10;
|
||||||
|
PSG->VolA = PSG->EnvelopeA ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_AVOL] ? PSG->Regs[AY_AVOL]*2+1 : 0];
|
||||||
|
break;
|
||||||
|
case AY_BVOL:
|
||||||
|
PSG->Regs[AY_BVOL] &= 0x1f;
|
||||||
|
PSG->EnvelopeB = PSG->Regs[AY_BVOL] & 0x10;
|
||||||
|
PSG->VolB = PSG->EnvelopeB ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_BVOL] ? PSG->Regs[AY_BVOL]*2+1 : 0];
|
||||||
|
break;
|
||||||
|
case AY_CVOL:
|
||||||
|
PSG->Regs[AY_CVOL] &= 0x1f;
|
||||||
|
PSG->EnvelopeC = PSG->Regs[AY_CVOL] & 0x10;
|
||||||
|
PSG->VolC = PSG->EnvelopeC ? PSG->VolE : PSG->VolTable[PSG->Regs[AY_CVOL] ? PSG->Regs[AY_CVOL]*2+1 : 0];
|
||||||
|
break;
|
||||||
|
case AY_EFINE:
|
||||||
|
case AY_ECOARSE:
|
||||||
|
// _ASSERT((PSG->Regs[AY_EFINE] == 0) && (PSG->Regs[AY_ECOARSE] == 0));
|
||||||
|
old = PSG->PeriodE;
|
||||||
|
PSG->PeriodE = ((PSG->Regs[AY_EFINE] + 256 * PSG->Regs[AY_ECOARSE])) * PSG->UpdateStep;
|
||||||
|
if (PSG->PeriodE == 0) PSG->PeriodE = PSG->UpdateStep / 2;
|
||||||
|
PSG->CountE += PSG->PeriodE - old;
|
||||||
|
if (PSG->CountE <= 0) PSG->CountE = 1;
|
||||||
|
break;
|
||||||
|
case AY_ESHAPE:
|
||||||
|
// _ASSERT(PSG->Regs[AY_ESHAPE] == 0);
|
||||||
|
/* envelope shapes:
|
||||||
|
C AtAlH
|
||||||
|
0 0 x x \___
|
||||||
|
|
||||||
|
0 1 x x /___
|
||||||
|
|
||||||
|
1 0 0 0 \\\\
|
||||||
|
|
||||||
|
1 0 0 1 \___
|
||||||
|
|
||||||
|
1 0 1 0 \/\/
|
||||||
|
___
|
||||||
|
1 0 1 1 \
|
||||||
|
|
||||||
|
1 1 0 0 ////
|
||||||
|
___
|
||||||
|
1 1 0 1 /
|
||||||
|
|
||||||
|
1 1 1 0 /\/\
|
||||||
|
|
||||||
|
1 1 1 1 /___
|
||||||
|
|
||||||
|
The envelope counter on the AY-3-8910 has 16 steps. On the YM2149 it
|
||||||
|
has twice the steps, happening twice as fast. Since the end result is
|
||||||
|
just a smoother curve, we always use the YM2149 behaviour.
|
||||||
|
*/
|
||||||
|
PSG->Regs[AY_ESHAPE] &= 0x0f;
|
||||||
|
PSG->Attack = (PSG->Regs[AY_ESHAPE] & 0x04) ? 0x1f : 0x00;
|
||||||
|
if ((PSG->Regs[AY_ESHAPE] & 0x08) == 0)
|
||||||
|
{
|
||||||
|
/* if Continue = 0, map the shape to the equivalent one which has Continue = 1 */
|
||||||
|
PSG->Hold = 1;
|
||||||
|
PSG->Alternate = PSG->Attack;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PSG->Hold = PSG->Regs[AY_ESHAPE] & 0x01;
|
||||||
|
PSG->Alternate = PSG->Regs[AY_ESHAPE] & 0x02;
|
||||||
|
}
|
||||||
|
PSG->CountE = PSG->PeriodE;
|
||||||
|
PSG->CountEnv = 0x1f;
|
||||||
|
PSG->Holding = 0;
|
||||||
|
PSG->VolE = PSG->VolTable[PSG->CountEnv ^ PSG->Attack];
|
||||||
|
if (PSG->EnvelopeA) PSG->VolA = PSG->VolE;
|
||||||
|
if (PSG->EnvelopeB) PSG->VolB = PSG->VolE;
|
||||||
|
if (PSG->EnvelopeC) PSG->VolC = PSG->VolE;
|
||||||
|
break;
|
||||||
|
case AY_PORTA:
|
||||||
|
if (PSG->Regs[AY_ENABLE] & 0x40)
|
||||||
|
{
|
||||||
|
if (PSG->PortAwrite)
|
||||||
|
(*PSG->PortAwrite)(0, PSG->Regs[AY_PORTA]);
|
||||||
|
else
|
||||||
|
logerror("PC %04x: warning - write %02x to 8910 #%d Port A\n",activecpu_get_pc(),PSG->Regs[AY_PORTA],n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logerror("warning: write to 8910 #%d Port A set as input - ignored\n",n);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AY_PORTB:
|
||||||
|
if (PSG->Regs[AY_ENABLE] & 0x80)
|
||||||
|
{
|
||||||
|
if (PSG->PortBwrite)
|
||||||
|
(*PSG->PortBwrite)(0, PSG->Regs[AY_PORTB]);
|
||||||
|
else
|
||||||
|
logerror("PC %04x: warning - write %02x to 8910 #%d Port B\n",activecpu_get_pc(),PSG->Regs[AY_PORTB],n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logerror("warning: write to 8910 #%d Port B set as input - ignored\n",n);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// /length/ is the number of samples we require
|
||||||
|
// NB. This should be called at twice the 6522 IRQ rate or (eg) 60Hz if no IRQ.
|
||||||
|
void AY8910Update(int chip,INT16 **buffer,int length) // [TC: Removed static]
|
||||||
|
{
|
||||||
|
struct AY8910 *PSG = &AYPSG[chip];
|
||||||
|
INT16 *buf1,*buf2,*buf3;
|
||||||
|
int outn;
|
||||||
|
|
||||||
|
buf1 = buffer[0];
|
||||||
|
buf2 = buffer[1];
|
||||||
|
buf3 = buffer[2];
|
||||||
|
|
||||||
|
|
||||||
|
/* The 8910 has three outputs, each output is the mix of one of the three */
|
||||||
|
/* tone generators and of the (single) noise generator. The two are mixed */
|
||||||
|
/* BEFORE going into the DAC. The formula to mix each channel is: */
|
||||||
|
/* (ToneOn | ToneDisable) & (NoiseOn | NoiseDisable). */
|
||||||
|
/* Note that this means that if both tone and noise are disabled, the output */
|
||||||
|
/* is 1, not 0, and can be modulated changing the volume. */
|
||||||
|
|
||||||
|
|
||||||
|
/* If the channels are disabled, set their output to 1, and increase the */
|
||||||
|
/* counter, if necessary, so they will not be inverted during this update. */
|
||||||
|
/* Setting the output to 1 is necessary because a disabled channel is locked */
|
||||||
|
/* into the ON state (see above); and it has no effect if the volume is 0. */
|
||||||
|
/* If the volume is 0, increase the counter, but don't touch the output. */
|
||||||
|
if (PSG->Regs[AY_ENABLE] & 0x01)
|
||||||
|
{
|
||||||
|
if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP;
|
||||||
|
PSG->OutputA = 1;
|
||||||
|
}
|
||||||
|
else if (PSG->Regs[AY_AVOL] == 0)
|
||||||
|
{
|
||||||
|
/* note that I do count += length, NOT count = length + 1. You might think */
|
||||||
|
/* it's the same since the volume is 0, but doing the latter could cause */
|
||||||
|
/* interferencies when the program is rapidly modulating the volume. */
|
||||||
|
if (PSG->CountA <= length*STEP) PSG->CountA += length*STEP;
|
||||||
|
}
|
||||||
|
if (PSG->Regs[AY_ENABLE] & 0x02)
|
||||||
|
{
|
||||||
|
if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP;
|
||||||
|
PSG->OutputB = 1;
|
||||||
|
}
|
||||||
|
else if (PSG->Regs[AY_BVOL] == 0)
|
||||||
|
{
|
||||||
|
if (PSG->CountB <= length*STEP) PSG->CountB += length*STEP;
|
||||||
|
}
|
||||||
|
if (PSG->Regs[AY_ENABLE] & 0x04)
|
||||||
|
{
|
||||||
|
if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP;
|
||||||
|
PSG->OutputC = 1;
|
||||||
|
}
|
||||||
|
else if (PSG->Regs[AY_CVOL] == 0)
|
||||||
|
{
|
||||||
|
if (PSG->CountC <= length*STEP) PSG->CountC += length*STEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for the noise channel we must not touch OutputN - it's also not necessary */
|
||||||
|
/* since we use outn. */
|
||||||
|
if ((PSG->Regs[AY_ENABLE] & 0x38) == 0x38) /* all off */
|
||||||
|
if (PSG->CountN <= length*STEP) PSG->CountN += length*STEP;
|
||||||
|
|
||||||
|
outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]);
|
||||||
|
|
||||||
|
|
||||||
|
/* buffering loop */
|
||||||
|
while (length)
|
||||||
|
{
|
||||||
|
int vola,volb,volc;
|
||||||
|
int left;
|
||||||
|
|
||||||
|
|
||||||
|
/* vola, volb and volc keep track of how long each square wave stays */
|
||||||
|
/* in the 1 position during the sample period. */
|
||||||
|
vola = volb = volc = 0;
|
||||||
|
|
||||||
|
left = STEP;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
int nextevent;
|
||||||
|
|
||||||
|
|
||||||
|
if (PSG->CountN < left) nextevent = PSG->CountN;
|
||||||
|
else nextevent = left;
|
||||||
|
|
||||||
|
if (outn & 0x08)
|
||||||
|
{
|
||||||
|
if (PSG->OutputA) vola += PSG->CountA;
|
||||||
|
PSG->CountA -= nextevent;
|
||||||
|
/* PeriodA is the half period of the square wave. Here, in each */
|
||||||
|
/* loop I add PeriodA twice, so that at the end of the loop the */
|
||||||
|
/* square wave is in the same status (0 or 1) it was at the start. */
|
||||||
|
/* vola is also incremented by PeriodA, since the wave has been 1 */
|
||||||
|
/* exactly half of the time, regardless of the initial position. */
|
||||||
|
/* If we exit the loop in the middle, OutputA has to be inverted */
|
||||||
|
/* and vola incremented only if the exit status of the square */
|
||||||
|
/* wave is 1. */
|
||||||
|
while (PSG->CountA <= 0)
|
||||||
|
{
|
||||||
|
PSG->CountA += PSG->PeriodA;
|
||||||
|
if (PSG->CountA > 0)
|
||||||
|
{
|
||||||
|
PSG->OutputA ^= 1;
|
||||||
|
if (PSG->OutputA) vola += PSG->PeriodA;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PSG->CountA += PSG->PeriodA;
|
||||||
|
vola += PSG->PeriodA;
|
||||||
|
}
|
||||||
|
if (PSG->OutputA) vola -= PSG->CountA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PSG->CountA -= nextevent;
|
||||||
|
while (PSG->CountA <= 0)
|
||||||
|
{
|
||||||
|
PSG->CountA += PSG->PeriodA;
|
||||||
|
if (PSG->CountA > 0)
|
||||||
|
{
|
||||||
|
PSG->OutputA ^= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PSG->CountA += PSG->PeriodA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outn & 0x10)
|
||||||
|
{
|
||||||
|
if (PSG->OutputB) volb += PSG->CountB;
|
||||||
|
PSG->CountB -= nextevent;
|
||||||
|
while (PSG->CountB <= 0)
|
||||||
|
{
|
||||||
|
PSG->CountB += PSG->PeriodB;
|
||||||
|
if (PSG->CountB > 0)
|
||||||
|
{
|
||||||
|
PSG->OutputB ^= 1;
|
||||||
|
if (PSG->OutputB) volb += PSG->PeriodB;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PSG->CountB += PSG->PeriodB;
|
||||||
|
volb += PSG->PeriodB;
|
||||||
|
}
|
||||||
|
if (PSG->OutputB) volb -= PSG->CountB;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PSG->CountB -= nextevent;
|
||||||
|
while (PSG->CountB <= 0)
|
||||||
|
{
|
||||||
|
PSG->CountB += PSG->PeriodB;
|
||||||
|
if (PSG->CountB > 0)
|
||||||
|
{
|
||||||
|
PSG->OutputB ^= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PSG->CountB += PSG->PeriodB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outn & 0x20)
|
||||||
|
{
|
||||||
|
if (PSG->OutputC) volc += PSG->CountC;
|
||||||
|
PSG->CountC -= nextevent;
|
||||||
|
while (PSG->CountC <= 0)
|
||||||
|
{
|
||||||
|
PSG->CountC += PSG->PeriodC;
|
||||||
|
if (PSG->CountC > 0)
|
||||||
|
{
|
||||||
|
PSG->OutputC ^= 1;
|
||||||
|
if (PSG->OutputC) volc += PSG->PeriodC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PSG->CountC += PSG->PeriodC;
|
||||||
|
volc += PSG->PeriodC;
|
||||||
|
}
|
||||||
|
if (PSG->OutputC) volc -= PSG->CountC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PSG->CountC -= nextevent;
|
||||||
|
while (PSG->CountC <= 0)
|
||||||
|
{
|
||||||
|
PSG->CountC += PSG->PeriodC;
|
||||||
|
if (PSG->CountC > 0)
|
||||||
|
{
|
||||||
|
PSG->OutputC ^= 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PSG->CountC += PSG->PeriodC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PSG->CountN -= nextevent;
|
||||||
|
if (PSG->CountN <= 0)
|
||||||
|
{
|
||||||
|
/* Is noise output going to change? */
|
||||||
|
if ((PSG->RNG + 1) & 2) /* (bit0^bit1)? */
|
||||||
|
{
|
||||||
|
PSG->OutputN = ~PSG->OutputN;
|
||||||
|
outn = (PSG->OutputN | PSG->Regs[AY_ENABLE]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The Random Number Generator of the 8910 is a 17-bit shift */
|
||||||
|
/* register. The input to the shift register is bit0 XOR bit3 */
|
||||||
|
/* (bit0 is the output). This was verified on AY-3-8910 and YM2149 chips. */
|
||||||
|
|
||||||
|
/* The following is a fast way to compute bit17 = bit0^bit3. */
|
||||||
|
/* Instead of doing all the logic operations, we only check */
|
||||||
|
/* bit0, relying on the fact that after three shifts of the */
|
||||||
|
/* register, what now is bit3 will become bit0, and will */
|
||||||
|
/* invert, if necessary, bit14, which previously was bit17. */
|
||||||
|
if (PSG->RNG & 1) PSG->RNG ^= 0x24000; /* This version is called the "Galois configuration". */
|
||||||
|
PSG->RNG >>= 1;
|
||||||
|
PSG->CountN += PSG->PeriodN;
|
||||||
|
}
|
||||||
|
|
||||||
|
left -= nextevent;
|
||||||
|
} while (left > 0);
|
||||||
|
|
||||||
|
/* update envelope */
|
||||||
|
if (PSG->Holding == 0)
|
||||||
|
{
|
||||||
|
PSG->CountE -= STEP;
|
||||||
|
if (PSG->CountE <= 0)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
PSG->CountEnv--;
|
||||||
|
PSG->CountE += PSG->PeriodE;
|
||||||
|
} while (PSG->CountE <= 0);
|
||||||
|
|
||||||
|
/* check envelope current position */
|
||||||
|
if (PSG->CountEnv < 0)
|
||||||
|
{
|
||||||
|
if (PSG->Hold)
|
||||||
|
{
|
||||||
|
if (PSG->Alternate)
|
||||||
|
PSG->Attack ^= 0x1f;
|
||||||
|
PSG->Holding = 1;
|
||||||
|
PSG->CountEnv = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* if CountEnv has looped an odd number of times (usually 1), */
|
||||||
|
/* invert the output. */
|
||||||
|
if (PSG->Alternate && (PSG->CountEnv & 0x20))
|
||||||
|
PSG->Attack ^= 0x1f;
|
||||||
|
|
||||||
|
PSG->CountEnv &= 0x1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PSG->VolE = PSG->VolTable[PSG->CountEnv ^ PSG->Attack];
|
||||||
|
/* reload volume */
|
||||||
|
if (PSG->EnvelopeA) PSG->VolA = PSG->VolE;
|
||||||
|
if (PSG->EnvelopeB) PSG->VolB = PSG->VolE;
|
||||||
|
if (PSG->EnvelopeC) PSG->VolC = PSG->VolE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
*(buf1++) = (vola * PSG->VolA) / STEP;
|
||||||
|
*(buf2++) = (volb * PSG->VolB) / STEP;
|
||||||
|
*(buf3++) = (volc * PSG->VolC) / STEP;
|
||||||
|
#else
|
||||||
|
// Output PCM wave [-32768...32767] instead of MAME's voltage level [0...32767]
|
||||||
|
// - This allows for better s/w mixing
|
||||||
|
|
||||||
|
if(PSG->VolA)
|
||||||
|
{
|
||||||
|
if(vola)
|
||||||
|
*(buf1++) = (vola * PSG->VolA) / STEP;
|
||||||
|
else
|
||||||
|
*(buf1++) = - (int) PSG->VolA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(buf1++) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
if(PSG->VolB)
|
||||||
|
{
|
||||||
|
if(volb)
|
||||||
|
*(buf2++) = (volb * PSG->VolB) / STEP;
|
||||||
|
else
|
||||||
|
*(buf2++) = - (int) PSG->VolB;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(buf2++) = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
if(PSG->VolC)
|
||||||
|
{
|
||||||
|
if(volc)
|
||||||
|
*(buf3++) = (volc * PSG->VolC) / STEP;
|
||||||
|
else
|
||||||
|
*(buf3++) = - (int) PSG->VolC;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*(buf3++) = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void AY8910_set_clock(int chip,int clock)
|
||||||
|
{
|
||||||
|
struct AY8910 *PSG = &AYPSG[chip];
|
||||||
|
|
||||||
|
/* the step clock for the tone and noise generators is the chip clock */
|
||||||
|
/* divided by 8; for the envelope generator of the AY-3-8910, it is half */
|
||||||
|
/* that much (clock/16), but the envelope of the YM2149 goes twice as */
|
||||||
|
/* fast, therefore again clock/8. */
|
||||||
|
/* Here we calculate the number of steps which happen during one sample */
|
||||||
|
/* at the given sample rate. No. of events = sample rate / (clock/8). */
|
||||||
|
/* STEP is a multiplier used to turn the fraction into a fixed point */
|
||||||
|
/* number. */
|
||||||
|
PSG->UpdateStep = (unsigned int) (((double)STEP * PSG->SampleRate * 8 + clock/2) / clock); // [TC: unsigned int cast]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void build_mixer_table(int chip)
|
||||||
|
{
|
||||||
|
struct AY8910 *PSG = &AYPSG[chip];
|
||||||
|
int i;
|
||||||
|
double out;
|
||||||
|
|
||||||
|
|
||||||
|
/* calculate the volume->voltage conversion table */
|
||||||
|
/* The AY-3-8910 has 16 levels, in a logarithmic scale (3dB per step) */
|
||||||
|
/* The YM2149 still has 16 levels for the tone generators, but 32 for */
|
||||||
|
/* the envelope generator (1.5dB per step). */
|
||||||
|
out = MAX_OUTPUT;
|
||||||
|
for (i = 31;i > 0;i--)
|
||||||
|
{
|
||||||
|
PSG->VolTable[i] = (unsigned int) (out + 0.5); /* round to nearest */ // [TC: unsigned int cast]
|
||||||
|
|
||||||
|
out /= 1.188502227; /* = 10 ^ (1.5/20) = 1.5dB */
|
||||||
|
}
|
||||||
|
PSG->VolTable[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void ay8910_write_ym(int chip, int addr, int data)
|
||||||
|
{
|
||||||
|
struct AY8910 *PSG = &AYPSG[chip];
|
||||||
|
|
||||||
|
// if (addr & 1)
|
||||||
|
// { /* Data port */
|
||||||
|
// int r = PSG->register_latch;
|
||||||
|
int r = addr;
|
||||||
|
|
||||||
|
if (r > 15) return;
|
||||||
|
if (r < 14)
|
||||||
|
{
|
||||||
|
if (r == AY_ESHAPE || PSG->Regs[r] != data)
|
||||||
|
{
|
||||||
|
/* update the output buffer before changing the register */
|
||||||
|
// stream_update(PSG->Channel,0);
|
||||||
|
AY8910Update(chip, INT16 **buffer, int length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_AYWriteReg(PSG,r,data);
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
// { /* Register port */
|
||||||
|
// PSG->register_latch = data & 0x0f;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void AY8910_reset(int chip)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct AY8910 *PSG = &AYPSG[chip];
|
||||||
|
|
||||||
|
PSG->register_latch = 0;
|
||||||
|
PSG->RNG = 1;
|
||||||
|
PSG->OutputA = 0;
|
||||||
|
PSG->OutputB = 0;
|
||||||
|
PSG->OutputC = 0;
|
||||||
|
PSG->OutputN = 0xff;
|
||||||
|
PSG->lastEnable = -1; /* force a write */
|
||||||
|
for (i = 0;i < AY_PORTA;i++)
|
||||||
|
_AYWriteReg(chip,i,0); /* AYWriteReg() uses the timer system; we cannot */
|
||||||
|
/* call it at this time because the timer system */
|
||||||
|
/* has not been initialized. */
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
void AY8910_InitAll(int nClock, int nSampleRate)
|
||||||
|
{
|
||||||
|
for(int nChip=0; nChip<MAX_8910; nChip++)
|
||||||
|
{
|
||||||
|
struct AY8910 *PSG = &AYPSG[nChip];
|
||||||
|
|
||||||
|
memset(PSG,0,sizeof(struct AY8910));
|
||||||
|
PSG->SampleRate = nSampleRate;
|
||||||
|
|
||||||
|
PSG->PortAread = NULL;
|
||||||
|
PSG->PortBread = NULL;
|
||||||
|
PSG->PortAwrite = NULL;
|
||||||
|
PSG->PortBwrite = NULL;
|
||||||
|
|
||||||
|
AY8910_set_clock(nChip, nClock);
|
||||||
|
|
||||||
|
build_mixer_table(nChip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
void AY8910_InitClock(int nClock)
|
||||||
|
{
|
||||||
|
for(int nChip=0; nChip<MAX_8910; nChip++)
|
||||||
|
{
|
||||||
|
AY8910_set_clock(nChip, nClock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
BYTE* AY8910_GetRegsPtr(UINT nAyNum)
|
||||||
|
{
|
||||||
|
if(nAyNum >= MAX_8910)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &AYPSG[nAyNum].Regs[0];
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef AY8910_H
|
||||||
|
#define AY8910_H
|
||||||
|
|
||||||
|
#define MAX_8910 4
|
||||||
|
|
||||||
|
void _AYWriteReg(int n, int r, int v);
|
||||||
|
void AY8910_write_ym(int chip, int addr, int data);
|
||||||
|
void AY8910_reset(int chip);
|
||||||
|
void AY8910Update(int chip,INT16 **buffer,int length);
|
||||||
|
|
||||||
|
void AY8910_InitAll(int nClock, int nSampleRate);
|
||||||
|
void AY8910_InitClock(int nClock);
|
||||||
|
BYTE* AY8910_GetRegsPtr(UINT nAyNum);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,677 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, Michael O'Brien
|
||||||
|
Copyright (C) 1999-2001, Oliver Schmidt
|
||||||
|
Copyright (C) 2002-2005, Tom Charlesworth
|
||||||
|
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: main
|
||||||
|
*
|
||||||
|
* Author: Various
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
|
||||||
|
char VERSIONSTRING[] = "xx.yy.zz.ww";
|
||||||
|
|
||||||
|
BOOL apple2e = 1;
|
||||||
|
BOOL behind = 0; // Redundant
|
||||||
|
DWORD cumulativecycles = 0; // Wraps after ~1hr 9mins
|
||||||
|
DWORD cyclenum = 0; // Used by SpkrToggle() for non-wave sound
|
||||||
|
DWORD emulmsec = 0;
|
||||||
|
static DWORD emulmsec_frac = 0;
|
||||||
|
bool g_bFullSpeed = false;
|
||||||
|
HINSTANCE instance = (HINSTANCE)0;
|
||||||
|
static DWORD lastfastpaging = 0;
|
||||||
|
static DWORD lasttrimimages = 0;
|
||||||
|
int mode = MODE_LOGO;
|
||||||
|
static int lastmode = MODE_LOGO;
|
||||||
|
DWORD needsprecision = 0; // Redundant
|
||||||
|
TCHAR progdir[MAX_PATH] = TEXT("");
|
||||||
|
BOOL resettiming = 0; // Redundant
|
||||||
|
BOOL restart = 0;
|
||||||
|
|
||||||
|
DWORD g_dwSpeed = SPEED_NORMAL; // Affected by Config dialog's speed slider bar
|
||||||
|
double g_fCurrentCLK6502 = CLK_6502; // Affected by Config dialog's speed slider bar
|
||||||
|
static double g_fMHz = 1.0; // Affected by Config dialog's speed slider bar
|
||||||
|
|
||||||
|
int g_nCpuCyclesFeedback = 0;
|
||||||
|
FILE* g_fh = NULL;
|
||||||
|
bool g_bDisableDirectSound = false;
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
void CheckFastPaging ()
|
||||||
|
{
|
||||||
|
if ((pages >= 10) && CpuSupportsFastPaging())
|
||||||
|
{
|
||||||
|
lastfastpaging = cumulativecycles;
|
||||||
|
if (cpuemtype == CPU_COMPILING)
|
||||||
|
{
|
||||||
|
lasttrimimages = cumulativecycles;
|
||||||
|
MemSetFastPaging(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
#define DBG_CALC_FREQ 0
|
||||||
|
#if DBG_CALC_FREQ
|
||||||
|
const UINT MAX_CNT = 256;
|
||||||
|
double g_fDbg[MAX_CNT];
|
||||||
|
UINT g_nIdx = 0;
|
||||||
|
double g_fMeanPeriod,g_fMeanFreq;
|
||||||
|
ULONGLONG g_nPerfFreq = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ContinueExecution()
|
||||||
|
{
|
||||||
|
static DWORD dwCyclesThisFrame = 0;
|
||||||
|
static BOOL pageflipping = 0; //?
|
||||||
|
|
||||||
|
const double fUsecPerSec = 1.e6;
|
||||||
|
#if 1
|
||||||
|
const UINT nExecutionPeriodUsec = 1000; // 1.0ms
|
||||||
|
// const UINT nExecutionPeriodUsec = 100; // 0.1ms
|
||||||
|
const double fExecutionPeriodClks = g_fCurrentCLK6502 * ((double)nExecutionPeriodUsec / fUsecPerSec);
|
||||||
|
#else
|
||||||
|
const double fExecutionPeriodClks = 1800.0;
|
||||||
|
const UINT nExecutionPeriodUsec = (UINT) (fUsecPerSec * (fExecutionPeriodClks / g_fCurrentCLK6502));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
g_bFullSpeed = ( (g_dwSpeed == SPEED_MAX) ||
|
||||||
|
(GetKeyState(VK_SCROLL) < 0) ||
|
||||||
|
(DiskIsSpinning() && enhancedisk && !Spkr_IsActive() && !MB_IsActive()) );
|
||||||
|
|
||||||
|
if(g_bFullSpeed)
|
||||||
|
{
|
||||||
|
// Don't call Spkr_Mute() - will get speaker clicks
|
||||||
|
MB_Mute();
|
||||||
|
SysClk_StopTimer();
|
||||||
|
|
||||||
|
g_nCpuCyclesFeedback = 0; // For the case when this is a big -ve number
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Don't call Spkr_Demute()
|
||||||
|
MB_Demute();
|
||||||
|
SysClk_StartTimerUsec(nExecutionPeriodUsec);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
int nCyclesToExecute = (int) fExecutionPeriodClks + g_nCpuCyclesFeedback;
|
||||||
|
if(nCyclesToExecute < 0)
|
||||||
|
nCyclesToExecute = 0;
|
||||||
|
|
||||||
|
DWORD dwExecutedCycles = CpuExecute(nCyclesToExecute);
|
||||||
|
|
||||||
|
dwCyclesThisFrame += dwExecutedCycles;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
cyclenum = dwExecutedCycles;
|
||||||
|
|
||||||
|
CheckFastPaging();
|
||||||
|
DiskUpdatePosition(dwExecutedCycles);
|
||||||
|
JoyUpdatePosition();
|
||||||
|
VideoUpdateVbl(dwCyclesThisFrame);
|
||||||
|
|
||||||
|
SpkrUpdate(cyclenum);
|
||||||
|
CommUpdate(cyclenum);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
if (cpuemtype == CPU_FASTPAGING) //?
|
||||||
|
{
|
||||||
|
if ((!pages) && (cumulativecycles-lastfastpaging > 500000))
|
||||||
|
{
|
||||||
|
MemSetFastPaging(0);
|
||||||
|
}
|
||||||
|
else if (cumulativecycles-lasttrimimages > 500000)
|
||||||
|
{
|
||||||
|
MemTrimImages();
|
||||||
|
lasttrimimages = cumulativecycles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
const DWORD CLKS_PER_MS = (DWORD)g_fCurrentCLK6502 / 1000;
|
||||||
|
|
||||||
|
emulmsec_frac += dwExecutedCycles;
|
||||||
|
if(emulmsec_frac > CLKS_PER_MS)
|
||||||
|
{
|
||||||
|
emulmsec += emulmsec_frac / CLKS_PER_MS;
|
||||||
|
emulmsec_frac %= CLKS_PER_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
pages = 0; //?
|
||||||
|
|
||||||
|
//
|
||||||
|
// DETERMINE WHETHER THE SCREEN WAS UPDATED, THE DISK WAS SPINNING,
|
||||||
|
// OR THE KEYBOARD I/O PORTS WERE BEING EXCESSIVELY QUERIED THIS CLOCKTICK
|
||||||
|
VideoCheckPage(0);
|
||||||
|
BOOL screenupdated = VideoHasRefreshed();
|
||||||
|
BOOL systemidle = 0; //(KeybGetNumQueries() > (clockgran << 2)); // && (!ranfinegrain); // TO DO
|
||||||
|
|
||||||
|
if(screenupdated)
|
||||||
|
pageflipping = 3;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
if(dwCyclesThisFrame >= dwClksPerFrame)
|
||||||
|
{
|
||||||
|
dwCyclesThisFrame -= dwClksPerFrame;
|
||||||
|
|
||||||
|
if(mode != MODE_LOGO)
|
||||||
|
{
|
||||||
|
VideoUpdateFlash();
|
||||||
|
|
||||||
|
static BOOL anyupdates = 0;
|
||||||
|
static DWORD lastcycles = 0;
|
||||||
|
static BOOL lastupdates[2] = {0,0};
|
||||||
|
|
||||||
|
anyupdates |= screenupdated;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
lastcycles = cumulativecycles;
|
||||||
|
if ((!anyupdates) && (!lastupdates[0]) && (!lastupdates[1]) && VideoApparentlyDirty())
|
||||||
|
{
|
||||||
|
VideoCheckPage(1);
|
||||||
|
static DWORD lasttime = 0;
|
||||||
|
DWORD currtime = GetTickCount();
|
||||||
|
if ((!g_bFullSpeed) ||
|
||||||
|
(currtime-lasttime >= (DWORD)((graphicsmode || !systemidle) ? 100 : 25)))
|
||||||
|
{
|
||||||
|
VideoRefreshScreen();
|
||||||
|
lasttime = currtime;
|
||||||
|
}
|
||||||
|
screenupdated = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastupdates[1] = lastupdates[0];
|
||||||
|
lastupdates[0] = anyupdates;
|
||||||
|
anyupdates = 0;
|
||||||
|
|
||||||
|
if (pageflipping)
|
||||||
|
pageflipping--;
|
||||||
|
}
|
||||||
|
|
||||||
|
MB_EndOfFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
if(!g_bFullSpeed)
|
||||||
|
{
|
||||||
|
SysClk_WaitTimer();
|
||||||
|
|
||||||
|
#if DBG_CALC_FREQ
|
||||||
|
if(g_nPerfFreq)
|
||||||
|
{
|
||||||
|
QueryPerformanceCounter((LARGE_INTEGER*)&nTime1);
|
||||||
|
LONGLONG nTimeDiff = nTime1 - nTime0;
|
||||||
|
double fTime = (double)nTimeDiff / (double)(LONGLONG)g_nPerfFreq;
|
||||||
|
|
||||||
|
g_fDbg[g_nIdx] = fTime;
|
||||||
|
g_nIdx = (g_nIdx+1) & (MAX_CNT-1);
|
||||||
|
g_fMeanPeriod = 0.0;
|
||||||
|
for(UINT n=0; n<MAX_CNT; n++)
|
||||||
|
g_fMeanPeriod += g_fDbg[n];
|
||||||
|
g_fMeanPeriod /= (double)MAX_CNT;
|
||||||
|
g_fMeanFreq = 1.0 / g_fMeanPeriod;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
void SetCurrentCLK6502()
|
||||||
|
{
|
||||||
|
static DWORD dwPrevSpeed = (DWORD) -1;
|
||||||
|
|
||||||
|
if(dwPrevSpeed == g_dwSpeed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dwPrevSpeed = g_dwSpeed;
|
||||||
|
|
||||||
|
// SPEED_MIN = 0 = 0.50 MHz
|
||||||
|
// SPEED_NORMAL = 10 = 1.00 MHz
|
||||||
|
// 20 = 2.00 MHz
|
||||||
|
// SPEED_MAX-1 = 39 = 3.90 MHz
|
||||||
|
// SPEED_MAX = 40 = ???? MHz (run full-speed, /g_fCurrentCLK6502/ is ignored)
|
||||||
|
|
||||||
|
if(g_dwSpeed < SPEED_NORMAL)
|
||||||
|
g_fMHz = 0.5 + (double)g_dwSpeed * 0.05;
|
||||||
|
else
|
||||||
|
g_fMHz = (double)g_dwSpeed / 10.0;
|
||||||
|
|
||||||
|
g_fCurrentCLK6502 = CLK_6502 * g_fMHz;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Now re-init modules that are dependent on /g_fCurrentCLK6502/
|
||||||
|
//
|
||||||
|
|
||||||
|
SpkrReinitialize();
|
||||||
|
MB_Reinitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
LRESULT CALLBACK DlgProc (HWND window,
|
||||||
|
UINT message,
|
||||||
|
WPARAM wparam,
|
||||||
|
LPARAM lparam) {
|
||||||
|
if (message == WM_CREATE) {
|
||||||
|
RECT rect;
|
||||||
|
GetWindowRect(window,&rect);
|
||||||
|
SIZE size;
|
||||||
|
size.cx = rect.right-rect.left;
|
||||||
|
size.cy = rect.bottom-rect.top;
|
||||||
|
rect.left = (GetSystemMetrics(SM_CXSCREEN)-size.cx) >> 1;
|
||||||
|
rect.top = (GetSystemMetrics(SM_CYSCREEN)-size.cy) >> 1;
|
||||||
|
rect.right = rect.left+size.cx;
|
||||||
|
rect.bottom = rect.top +size.cy;
|
||||||
|
MoveWindow(window,
|
||||||
|
rect.left,
|
||||||
|
rect.top,
|
||||||
|
rect.right-rect.left,
|
||||||
|
rect.bottom-rect.top,
|
||||||
|
0);
|
||||||
|
ShowWindow(window,SW_SHOW);
|
||||||
|
}
|
||||||
|
return DefWindowProc(window,message,wparam,lparam);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void EnterMessageLoop () {
|
||||||
|
MSG message;
|
||||||
|
while (GetMessage(&message,0,0,0)) {
|
||||||
|
TranslateMessage(&message);
|
||||||
|
DispatchMessage(&message);
|
||||||
|
while ((mode == MODE_RUNNING) || (mode == MODE_STEPPING))
|
||||||
|
if (PeekMessage(&message,0,0,0,PM_REMOVE)) {
|
||||||
|
if (message.message == WM_QUIT)
|
||||||
|
return;
|
||||||
|
TranslateMessage(&message);
|
||||||
|
DispatchMessage(&message);
|
||||||
|
}
|
||||||
|
else if (mode == MODE_STEPPING)
|
||||||
|
DebugContinueStepping();
|
||||||
|
else {
|
||||||
|
ContinueExecution();
|
||||||
|
if (g_bFullSpeed)
|
||||||
|
ContinueExecution();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (PeekMessage(&message,0,0,0,PM_REMOVE)) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void GetProgramDirectory () {
|
||||||
|
GetModuleFileName((HINSTANCE)0,progdir,MAX_PATH);
|
||||||
|
progdir[MAX_PATH-1] = 0;
|
||||||
|
int loop = _tcslen(progdir);
|
||||||
|
while (loop--)
|
||||||
|
if ((progdir[loop] == TEXT('\\')) ||
|
||||||
|
(progdir[loop] == TEXT(':'))) {
|
||||||
|
progdir[loop+1] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void LoadConfiguration () {
|
||||||
|
LOAD(TEXT("Computer Emulation"),(DWORD *)&apple2e);
|
||||||
|
LOAD(TEXT("Joystick 0 Emulation"),&joytype[0]);
|
||||||
|
LOAD(TEXT("Joystick 1 Emulation"),&joytype[1]);
|
||||||
|
LOAD(TEXT("Sound Emulation") ,&soundtype);
|
||||||
|
LOAD(TEXT("Serial Port") ,&serialport);
|
||||||
|
LOAD(TEXT("Emulation Speed") ,&g_dwSpeed);
|
||||||
|
LOAD(TEXT("Enhance Disk Speed"),(DWORD *)&enhancedisk);
|
||||||
|
LOAD(TEXT("Video Emulation") ,&videotype);
|
||||||
|
LOAD(TEXT("Monochrome Color") ,&monochrome);
|
||||||
|
|
||||||
|
SetCurrentCLK6502();
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
DWORD dwTmp;
|
||||||
|
|
||||||
|
if(LOAD(TEXT(REGVALUE_SPKR_VOLUME), &dwTmp))
|
||||||
|
SpkrSetVolume(dwTmp, PSP_GetVolumeMax());
|
||||||
|
|
||||||
|
if(LOAD(TEXT(REGVALUE_MB_VOLUME), &dwTmp))
|
||||||
|
MB_SetVolume(dwTmp, PSP_GetVolumeMax());
|
||||||
|
|
||||||
|
if(LOAD(TEXT(REGVALUE_SOUNDCARD_TYPE), &dwTmp))
|
||||||
|
MB_SetSoundcardType((eSOUNDCARDTYPE)dwTmp);
|
||||||
|
|
||||||
|
if(LOAD(TEXT(REGVALUE_SAVE_STATE_ON_EXIT), &dwTmp))
|
||||||
|
g_bSaveStateOnExit = dwTmp ? true : false;
|
||||||
|
|
||||||
|
if(LOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp))
|
||||||
|
HD_SetEnabled(dwTmp ? true : false);
|
||||||
|
|
||||||
|
char szHDFilename[MAX_PATH] = {0};
|
||||||
|
if(RegLoadString(TEXT("Configuration"), TEXT(REGVALUE_HDD_IMAGE1), 1, szHDFilename, sizeof(szHDFilename)))
|
||||||
|
HD_InsertDisk2(0, szHDFilename);
|
||||||
|
if(RegLoadString(TEXT("Configuration"), TEXT(REGVALUE_HDD_IMAGE2), 1, szHDFilename, sizeof(szHDFilename)))
|
||||||
|
HD_InsertDisk2(1, szHDFilename);
|
||||||
|
|
||||||
|
if(LOAD(TEXT(REGVALUE_PDL_XTRIM), &dwTmp))
|
||||||
|
JoySetTrim((short)dwTmp, true);
|
||||||
|
if(LOAD(TEXT(REGVALUE_PDL_YTRIM), &dwTmp))
|
||||||
|
JoySetTrim((short)dwTmp, false);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
char szFilename[MAX_PATH] = {0};
|
||||||
|
|
||||||
|
RegLoadString(TEXT("Configuration"),TEXT(REGVALUE_SAVESTATE_FILENAME),1,szFilename,sizeof(szFilename));
|
||||||
|
Snapshot_SetFilename(szFilename); // If not in Registry than default will be used
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
TCHAR szDirectory[MAX_PATH] = TEXT("");
|
||||||
|
|
||||||
|
RegLoadString(TEXT("Preferences"),TEXT("Starting Directory"),1,szDirectory,MAX_PATH);
|
||||||
|
|
||||||
|
SetCurrentDirectory(szDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void RegisterExtensions () {
|
||||||
|
TCHAR command[MAX_PATH];
|
||||||
|
GetModuleFileName((HMODULE)0,command,MAX_PATH);
|
||||||
|
command[MAX_PATH-1] = 0;
|
||||||
|
TCHAR icon[MAX_PATH];
|
||||||
|
wsprintf(icon,TEXT("%s,1"),(LPCTSTR)command);
|
||||||
|
_tcscat(command,TEXT(" %1"));
|
||||||
|
RegSetValue(HKEY_CLASSES_ROOT,".bin",REG_SZ,"DiskImage",10);
|
||||||
|
RegSetValue(HKEY_CLASSES_ROOT,".do" ,REG_SZ,"DiskImage",10);
|
||||||
|
RegSetValue(HKEY_CLASSES_ROOT,".dsk",REG_SZ,"DiskImage",10);
|
||||||
|
RegSetValue(HKEY_CLASSES_ROOT,".nib",REG_SZ,"DiskImage",10);
|
||||||
|
RegSetValue(HKEY_CLASSES_ROOT,".po" ,REG_SZ,"DiskImage",10);
|
||||||
|
// 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,
|
||||||
|
"DiskImage",
|
||||||
|
REG_SZ,"Disk Image",21);
|
||||||
|
RegSetValue(HKEY_CLASSES_ROOT,
|
||||||
|
"DiskImage\\DefaultIcon",
|
||||||
|
REG_SZ,icon,_tcslen(icon)+1);
|
||||||
|
RegSetValue(HKEY_CLASSES_ROOT,
|
||||||
|
"DiskImage\\shell\\open\\command",
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
LPSTR GetNextArg(LPSTR lpCmdLine)
|
||||||
|
{
|
||||||
|
int bInQuotes = 0;
|
||||||
|
|
||||||
|
while(*lpCmdLine)
|
||||||
|
{
|
||||||
|
if(*lpCmdLine == '\"')
|
||||||
|
{
|
||||||
|
bInQuotes ^= 1;
|
||||||
|
if(!bInQuotes)
|
||||||
|
{
|
||||||
|
*lpCmdLine++ = 0x00; // Assume end-quote is end of this arg
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((*lpCmdLine == ' ') && !bInQuotes)
|
||||||
|
{
|
||||||
|
*lpCmdLine++ = 0x00;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpCmdLine++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lpCmdLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int DoDiskInsert(int nDrive, LPSTR szFileName)
|
||||||
|
{
|
||||||
|
DWORD dwAttributes = GetFileAttributes(szFileName);
|
||||||
|
if(dwAttributes == INVALID_FILE_ATTRIBUTES)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL bWriteProtected = (dwAttributes & FILE_ATTRIBUTE_READONLY) ? TRUE : FALSE;
|
||||||
|
|
||||||
|
return DiskInsert(nDrive, szFileName, bWriteProtected, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int APIENTRY WinMain (HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
|
||||||
|
{
|
||||||
|
bool bSetFullScreen = false;
|
||||||
|
bool bBoot = false;
|
||||||
|
LPSTR szImageName_drive1 = NULL;
|
||||||
|
LPSTR szImageName_drive2 = NULL;
|
||||||
|
|
||||||
|
while(*lpCmdLine)
|
||||||
|
{
|
||||||
|
LPSTR lpNextArg = GetNextArg(lpCmdLine);
|
||||||
|
|
||||||
|
if(strcmp(lpCmdLine, "-d1") == 0)
|
||||||
|
{
|
||||||
|
lpCmdLine = lpNextArg;
|
||||||
|
lpNextArg = GetNextArg(lpCmdLine);
|
||||||
|
szImageName_drive1 = lpCmdLine;
|
||||||
|
if(*szImageName_drive1 == '\"')
|
||||||
|
szImageName_drive1++;
|
||||||
|
}
|
||||||
|
else if(strcmp(lpCmdLine, "-d2") == 0)
|
||||||
|
{
|
||||||
|
lpCmdLine = lpNextArg;
|
||||||
|
lpNextArg = GetNextArg(lpCmdLine);
|
||||||
|
szImageName_drive2 = lpCmdLine;
|
||||||
|
if(*szImageName_drive2 == '\"')
|
||||||
|
szImageName_drive2++;
|
||||||
|
}
|
||||||
|
else if(strcmp(lpCmdLine, "-f") == 0)
|
||||||
|
{
|
||||||
|
bSetFullScreen = true;
|
||||||
|
}
|
||||||
|
else if((strcmp(lpCmdLine, "-l") == 0) && (g_fh == NULL))
|
||||||
|
{
|
||||||
|
g_fh = fopen("AppleWin.log", "a+t"); // Open log file (append & text mode)
|
||||||
|
CHAR aDateStr[80], aTimeStr[80];
|
||||||
|
GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, (LPTSTR)aDateStr, sizeof(aDateStr));
|
||||||
|
GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, (LPTSTR)aTimeStr, sizeof(aTimeStr));
|
||||||
|
fprintf(g_fh,"*** Logging started: %s %s\n",aDateStr,aTimeStr);
|
||||||
|
}
|
||||||
|
else if(strcmp(lpCmdLine, "-m") == 0)
|
||||||
|
{
|
||||||
|
g_bDisableDirectSound = true;
|
||||||
|
}
|
||||||
|
#ifdef RAMWORKS
|
||||||
|
else if(strcmp(lpCmdLine, "-r") == 0) // RamWorks size [1..127]
|
||||||
|
{
|
||||||
|
lpCmdLine = lpNextArg;
|
||||||
|
lpNextArg = GetNextArg(lpCmdLine);
|
||||||
|
g_uMaxExPages = atoi(lpCmdLine);
|
||||||
|
if (g_uMaxExPages > 127)
|
||||||
|
g_uMaxExPages = 128;
|
||||||
|
else if (g_uMaxExPages < 1)
|
||||||
|
g_uMaxExPages = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lpCmdLine = lpNextArg;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#ifdef RIFF_SPKR
|
||||||
|
RiffInitWriteFile("Spkr.wav", SPKR_SAMPLE_RATE, 1);
|
||||||
|
#endif
|
||||||
|
#ifdef RIFF_MB
|
||||||
|
RiffInitWriteFile("Mockingboard.wav", 44100, 2);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----
|
||||||
|
|
||||||
|
char szPath[_MAX_PATH];
|
||||||
|
|
||||||
|
if(0 == GetModuleFileName(NULL, szPath, sizeof(szPath)))
|
||||||
|
{
|
||||||
|
strcpy(szPath, __argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract application version and store in a global variable
|
||||||
|
DWORD dwHandle, dwVerInfoSize;
|
||||||
|
|
||||||
|
dwVerInfoSize = GetFileVersionInfoSize(szPath, &dwHandle);
|
||||||
|
|
||||||
|
if(dwVerInfoSize > 0)
|
||||||
|
{
|
||||||
|
char* pVerInfoBlock = new char[dwVerInfoSize];
|
||||||
|
|
||||||
|
if(GetFileVersionInfo(szPath, NULL, dwVerInfoSize, pVerInfoBlock))
|
||||||
|
{
|
||||||
|
VS_FIXEDFILEINFO* pFixedFileInfo;
|
||||||
|
UINT pFixedFileInfoLen;
|
||||||
|
|
||||||
|
VerQueryValue(pVerInfoBlock, TEXT("\\"), (LPVOID*) &pFixedFileInfo, (PUINT) &pFixedFileInfoLen);
|
||||||
|
|
||||||
|
// Construct version string from fixed file info block
|
||||||
|
|
||||||
|
unsigned long major = pFixedFileInfo->dwFileVersionMS >> 16;
|
||||||
|
unsigned long minor = pFixedFileInfo->dwFileVersionMS & 0xffff;
|
||||||
|
unsigned long fix = pFixedFileInfo->dwFileVersionLS >> 16;
|
||||||
|
unsigned long fix_minor = pFixedFileInfo->dwFileVersionLS & 0xffff;
|
||||||
|
|
||||||
|
sprintf(VERSIONSTRING, "%d.%d.%d.%d", major, minor, fix, fix_minor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if DBG_CALC_FREQ
|
||||||
|
QueryPerformanceFrequency((LARGE_INTEGER*)&g_nPerfFreq);
|
||||||
|
if(g_fh) fprintf(g_fh, "Performance frequency = %d\n",g_nPerfFreq);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----
|
||||||
|
|
||||||
|
// Initialize COM
|
||||||
|
CoInitialize( NULL );
|
||||||
|
SysClk_InitTimer();
|
||||||
|
// DSInit(); // Done when framewindow is created (WM_CREATE)
|
||||||
|
|
||||||
|
// DO ONE-TIME INITIALIZATION
|
||||||
|
instance = passinstance;
|
||||||
|
GdiSetBatchLimit(512);
|
||||||
|
GetProgramDirectory();
|
||||||
|
RegisterExtensions();
|
||||||
|
FrameRegisterClass();
|
||||||
|
ImageInitialize();
|
||||||
|
DiskInitialize();
|
||||||
|
CreateColorMixMap(); // For tv emulation mode
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
int nError = 0;
|
||||||
|
if(szImageName_drive1)
|
||||||
|
{
|
||||||
|
nError = DoDiskInsert(0, szImageName_drive1);
|
||||||
|
bBoot = true;
|
||||||
|
}
|
||||||
|
if(szImageName_drive2)
|
||||||
|
{
|
||||||
|
nError |= DoDiskInsert(1, szImageName_drive2);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// DO INITIALIZATION THAT MUST BE REPEATED FOR A RESTART
|
||||||
|
restart = 0;
|
||||||
|
mode = MODE_LOGO;
|
||||||
|
LoadConfiguration();
|
||||||
|
DebugInitialize();
|
||||||
|
JoyInitialize();
|
||||||
|
MemInitialize();
|
||||||
|
VideoInitialize();
|
||||||
|
FrameCreateWindow();
|
||||||
|
Snapshot_Startup(); // Do this after everything has been init'ed
|
||||||
|
|
||||||
|
if(bSetFullScreen)
|
||||||
|
{
|
||||||
|
PostMessage(framewindow, WM_KEYDOWN, VK_F1+BTN_FULLSCR, 0);
|
||||||
|
PostMessage(framewindow, WM_KEYUP, VK_F1+BTN_FULLSCR, 0);
|
||||||
|
bSetFullScreen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bBoot)
|
||||||
|
{
|
||||||
|
PostMessage(framewindow, WM_KEYDOWN, VK_F1+BTN_RUN, 0);
|
||||||
|
PostMessage(framewindow, WM_KEYUP, VK_F1+BTN_RUN, 0);
|
||||||
|
bBoot = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ENTER THE MAIN MESSAGE LOOP
|
||||||
|
EnterMessageLoop();
|
||||||
|
MB_Reset();
|
||||||
|
}
|
||||||
|
while (restart);
|
||||||
|
|
||||||
|
// Release COM
|
||||||
|
DSUninit();
|
||||||
|
SysClk_UninitTimer();
|
||||||
|
CoUninitialize();
|
||||||
|
|
||||||
|
if(g_fh)
|
||||||
|
{
|
||||||
|
fprintf(g_fh,"*** Logging ended\n\n");
|
||||||
|
fclose(g_fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
RiffFinishWriteFile();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern char VERSIONSTRING[]; // Contructed in WinMain()
|
||||||
|
|
||||||
|
extern BOOL apple2e;
|
||||||
|
extern BOOL behind;
|
||||||
|
extern DWORD cumulativecycles;
|
||||||
|
extern DWORD cyclenum;
|
||||||
|
extern DWORD emulmsec;
|
||||||
|
extern bool g_bFullSpeed;
|
||||||
|
extern HINSTANCE instance;
|
||||||
|
extern int mode;
|
||||||
|
extern DWORD needsprecision;
|
||||||
|
extern TCHAR progdir[MAX_PATH];
|
||||||
|
extern BOOL resettiming;
|
||||||
|
extern BOOL restart;
|
||||||
|
|
||||||
|
extern DWORD g_dwSpeed;
|
||||||
|
extern double g_fCurrentCLK6502;
|
||||||
|
|
||||||
|
extern int g_nCpuCyclesFeedback;
|
||||||
|
extern FILE* g_fh; // Filehandle for log file
|
||||||
|
extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (so no MB support)
|
||||||
|
|
||||||
|
void SetCurrentCLK6502();
|
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define CPU_COMPILING 0
|
||||||
|
#define CPU_INTERPRETIVE 1
|
||||||
|
#define CPU_FASTPAGING 2
|
||||||
|
|
||||||
|
typedef struct _regsrec {
|
||||||
|
BYTE a; // accumulator
|
||||||
|
BYTE x; // index X
|
||||||
|
BYTE y; // index Y
|
||||||
|
BYTE ps; // processor status
|
||||||
|
WORD pc; // program counter
|
||||||
|
WORD sp; // stack pointer
|
||||||
|
BYTE bIRQ; // IRQ asserted flag
|
||||||
|
} regsrec, *regsptr;
|
||||||
|
|
||||||
|
extern DWORD cpuemtype;
|
||||||
|
extern regsrec regs;
|
||||||
|
extern unsigned __int64 g_nCumulativeCycles;
|
||||||
|
|
||||||
|
void CpuDestroy ();
|
||||||
|
void CpuCalcCycles(ULONG nCyclesLeft);
|
||||||
|
DWORD CpuExecute (DWORD);
|
||||||
|
void CpuGetCode (WORD,LPBYTE *,DWORD *);
|
||||||
|
void CpuInitialize ();
|
||||||
|
void CpuReinitialize ();
|
||||||
|
void CpuResetCompilerData ();
|
||||||
|
void CpuSetupBenchmark ();
|
||||||
|
BOOL CpuSupportsFastPaging ();
|
||||||
|
void CpuIRQ ();
|
||||||
|
DWORD CpuGetSnapshot(SS_CPU6502* pSS);
|
||||||
|
DWORD CpuSetSnapshot(SS_CPU6502* pSS);
|
|
@ -0,0 +1,73 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
const double _M14 = 14.31818e6;
|
||||||
|
const double CLK_6502 = (_M14 / 14.0);
|
||||||
|
|
||||||
|
const UINT uCyclesPerLine = 65; // 25 cycles of HBL & 40 cycles of HBL'
|
||||||
|
const UINT uVisibleLinesPerFrame = 64*3; // 192
|
||||||
|
const UINT uLinesPerFrame = 262; // 64 in each third of the screen & 70 in VBL
|
||||||
|
const DWORD dwClksPerFrame = uCyclesPerLine * uLinesPerFrame; // 17030
|
||||||
|
|
||||||
|
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
#define RAMWORKS // 8MB RamWorks III support
|
||||||
|
|
||||||
|
// Use a base freq so that DirectX (or sound h/w) doesn't have to up/down-sample
|
||||||
|
// Assume base freqs are 44.1KHz & 48KHz
|
||||||
|
const DWORD SPKR_SAMPLE_RATE = 44100;
|
||||||
|
|
||||||
|
#define MODE_LOGO 0
|
||||||
|
#define MODE_PAUSED 1
|
||||||
|
#define MODE_RUNNING 2
|
||||||
|
#define MODE_DEBUG 3
|
||||||
|
#define MODE_STEPPING 4
|
||||||
|
|
||||||
|
#define SPEED_MIN 0
|
||||||
|
#define SPEED_NORMAL 10
|
||||||
|
#define SPEED_MAX 40
|
||||||
|
|
||||||
|
#define DRAW_BACKGROUND 1
|
||||||
|
#define DRAW_LEDS 2
|
||||||
|
#define DRAW_TITLE 4
|
||||||
|
#define DRAW_BUTTON_DRIVES 8
|
||||||
|
|
||||||
|
#define BTN_HELP 0
|
||||||
|
#define BTN_RUN 1
|
||||||
|
#define BTN_DRIVE1 2
|
||||||
|
#define BTN_DRIVE2 3
|
||||||
|
#define BTN_DRIVESWAP 4
|
||||||
|
#define BTN_FULLSCR 5
|
||||||
|
#define BTN_DEBUG 6
|
||||||
|
#define BTN_SETUP 7
|
||||||
|
|
||||||
|
#define MAXIMAGES 16
|
||||||
|
#define TITLE TEXT("Apple //e Emulator")
|
||||||
|
|
||||||
|
#define LOAD(a,b) RegLoadValue(TEXT("Configuration"),a,1,b)
|
||||||
|
#define SAVE(a,b) RegSaveValue(TEXT("Configuration"),a,1,b)
|
||||||
|
|
||||||
|
#define REGVALUE_SPKR_VOLUME "Speaker Volume"
|
||||||
|
#define REGVALUE_MB_VOLUME "Mockingboard Volume"
|
||||||
|
#define REGVALUE_SOUNDCARD_TYPE "Soundcard Type"
|
||||||
|
#define REGVALUE_KEYB_BUFFER_ENABLE "Keyboard Buffer Enable"
|
||||||
|
#define REGVALUE_SAVESTATE_FILENAME "Save State Filename"
|
||||||
|
#define REGVALUE_SAVE_STATE_ON_EXIT "Save State On Exit"
|
||||||
|
#define REGVALUE_HDD_ENABLED "Harddisk Enable"
|
||||||
|
#define REGVALUE_HDD_IMAGE1 "Harddisk Image 1"
|
||||||
|
#define REGVALUE_HDD_IMAGE2 "Harddisk Image 2"
|
||||||
|
#define REGVALUE_PDL_XTRIM "PDL X-Trim"
|
||||||
|
#define REGVALUE_PDL_YTRIM "PDL Y-Trim"
|
||||||
|
|
||||||
|
#define WM_USER_BENCHMARK WM_USER+1
|
||||||
|
#define WM_USER_RESTART WM_USER+2
|
||||||
|
#define WM_USER_SAVESTATE WM_USER+3
|
||||||
|
#define WM_USER_LOADSTATE WM_USER+4
|
||||||
|
|
||||||
|
enum eSOUNDCARDTYPE {SC_UNINIT=0, SC_NONE, SC_MOCKINGBOARD, SC_PHASOR}; // Apple soundcard type
|
||||||
|
|
||||||
|
typedef BYTE (__stdcall *iofunction)(WORD nPC, BYTE nAddr, BYTE nWriteFlag, BYTE nWriteValue, ULONG nCyclesLeft);
|
||||||
|
typedef BYTE (__stdcall *cxfunction)(WORD nPC, WORD nAddr, BYTE nWriteFlag, BYTE nWriteValue, ULONG nCyclesLeft);
|
||||||
|
|
||||||
|
typedef struct _IMAGE__ { int unused; } *HIMAGE;
|
||||||
|
|
|
@ -0,0 +1,583 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, Michael O'Brien
|
||||||
|
Copyright (C) 1999-2001, Oliver Schmidt
|
||||||
|
Copyright (C) 2002-2005, Tom Charlesworth
|
||||||
|
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: Disk
|
||||||
|
*
|
||||||
|
* Author: Various
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
|
||||||
|
typedef struct _floppyrec {
|
||||||
|
TCHAR imagename[16];
|
||||||
|
TCHAR fullname[128];
|
||||||
|
HIMAGE imagehandle;
|
||||||
|
int track;
|
||||||
|
LPBYTE trackimage;
|
||||||
|
int phase;
|
||||||
|
int byte;
|
||||||
|
BOOL writeprotected;
|
||||||
|
BOOL trackimagedata;
|
||||||
|
BOOL trackimagedirty;
|
||||||
|
DWORD spinning;
|
||||||
|
DWORD writelight;
|
||||||
|
int nibbles;
|
||||||
|
} floppyrec, *floppyptr;
|
||||||
|
|
||||||
|
static int currdrive = 0;
|
||||||
|
static BOOL diskaccessed = 0;
|
||||||
|
BOOL enhancedisk = 1;
|
||||||
|
static floppyrec floppy[DRIVES];
|
||||||
|
static BYTE floppylatch = 0;
|
||||||
|
static BOOL floppymotoron = 0;
|
||||||
|
static BOOL floppywritemode = 0;
|
||||||
|
|
||||||
|
static void ReadTrack (int drive);
|
||||||
|
static void RemoveDisk (int drive);
|
||||||
|
static void WriteTrack (int drive);
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CheckSpinning () {
|
||||||
|
DWORD modechange = (floppymotoron && !floppy[currdrive].spinning);
|
||||||
|
if (floppymotoron)
|
||||||
|
floppy[currdrive].spinning = 20000;
|
||||||
|
if (modechange)
|
||||||
|
FrameRefreshStatus(DRAW_LEDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void GetImageTitle (LPCTSTR imagefilename, floppyptr fptr) {
|
||||||
|
TCHAR imagetitle[128];
|
||||||
|
LPCTSTR startpos = imagefilename;
|
||||||
|
|
||||||
|
// imagetitle = <FILENAME.EXT>
|
||||||
|
if (_tcsrchr(startpos,TEXT('\\')))
|
||||||
|
startpos = _tcsrchr(startpos,TEXT('\\'))+1;
|
||||||
|
_tcsncpy(imagetitle,startpos,127);
|
||||||
|
imagetitle[127] = 0;
|
||||||
|
|
||||||
|
// if imagetitle contains a lowercase char, then found=1 (why?)
|
||||||
|
BOOL found = 0;
|
||||||
|
int loop = 0;
|
||||||
|
while (imagetitle[loop] && !found)
|
||||||
|
{
|
||||||
|
if (IsCharLower(imagetitle[loop]))
|
||||||
|
found = 1;
|
||||||
|
else
|
||||||
|
loop++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!found) && (loop > 2))
|
||||||
|
CharLowerBuff(imagetitle+1,_tcslen(imagetitle+1));
|
||||||
|
|
||||||
|
// fptr->fullname = <FILENAME.EXT>
|
||||||
|
_tcsncpy(fptr->fullname,imagetitle,127);
|
||||||
|
fptr->fullname[127] = 0;
|
||||||
|
|
||||||
|
if (imagetitle[0])
|
||||||
|
{
|
||||||
|
LPTSTR dot = imagetitle;
|
||||||
|
if (_tcsrchr(dot,TEXT('.')))
|
||||||
|
dot = _tcsrchr(dot,TEXT('.'));
|
||||||
|
if (dot > imagetitle)
|
||||||
|
*dot = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fptr->imagename = <FILENAME> (ie. no extension)
|
||||||
|
_tcsncpy(fptr->imagename,imagetitle,15);
|
||||||
|
fptr->imagename[15] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
static void AllocTrack(int drive)
|
||||||
|
{
|
||||||
|
floppyptr fptr = &floppy[drive];
|
||||||
|
fptr->trackimage = (LPBYTE)VirtualAlloc(NULL,NIBBLES_PER_TRACK,MEM_COMMIT,PAGE_READWRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
static void ReadTrack (int drive) {
|
||||||
|
floppyptr fptr = &floppy[drive];
|
||||||
|
if (fptr->track >= TRACKS) {
|
||||||
|
fptr->trackimagedata = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!fptr->trackimage)
|
||||||
|
AllocTrack(drive);
|
||||||
|
if (fptr->trackimage && fptr->imagehandle) {
|
||||||
|
ImageReadTrack(fptr->imagehandle,
|
||||||
|
fptr->track,
|
||||||
|
fptr->phase,
|
||||||
|
fptr->trackimage,
|
||||||
|
&fptr->nibbles);
|
||||||
|
fptr->byte = 0;
|
||||||
|
fptr->trackimagedata = (fptr->nibbles != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
static void RemoveDisk (int drive) {
|
||||||
|
floppyptr fptr = &floppy[drive];
|
||||||
|
if (fptr->imagehandle) {
|
||||||
|
if (fptr->trackimage && fptr->trackimagedirty)
|
||||||
|
WriteTrack(drive);
|
||||||
|
ImageClose(fptr->imagehandle);
|
||||||
|
fptr->imagehandle = (HIMAGE)0;
|
||||||
|
}
|
||||||
|
if (fptr->trackimage) {
|
||||||
|
VirtualFree(fptr->trackimage,0,MEM_RELEASE);
|
||||||
|
fptr->trackimage = NULL;
|
||||||
|
fptr->trackimagedata = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
static void WriteTrack (int drive) {
|
||||||
|
floppyptr fptr = &floppy[drive];
|
||||||
|
if (fptr->track >= TRACKS)
|
||||||
|
return;
|
||||||
|
if (fptr->trackimage && fptr->imagehandle)
|
||||||
|
ImageWriteTrack(fptr->imagehandle,
|
||||||
|
fptr->track,
|
||||||
|
fptr->phase,
|
||||||
|
fptr->trackimage,
|
||||||
|
fptr->nibbles);
|
||||||
|
fptr->trackimagedirty = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE -----
|
||||||
|
//
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DiskBoot () {
|
||||||
|
|
||||||
|
// THIS FUNCTION RELOADS A PROGRAM IMAGE IF ONE IS LOADED IN DRIVE ONE.
|
||||||
|
// IF A DISK IMAGE OR NO IMAGE IS LOADED IN DRIVE ONE, IT DOES NOTHING.
|
||||||
|
if (floppy[0].imagehandle && ImageBoot(floppy[0].imagehandle))
|
||||||
|
floppymotoron = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall DiskControlMotor (WORD, BYTE address, BYTE, BYTE, ULONG) {
|
||||||
|
floppymotoron = address & 1;
|
||||||
|
CheckSpinning();
|
||||||
|
return MemReturnRandomData(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall DiskControlStepper (WORD, BYTE address, BYTE, BYTE, ULONG) {
|
||||||
|
floppyptr fptr = &floppy[currdrive];
|
||||||
|
if (address & 1) {
|
||||||
|
int phase = (address >> 1) & 3;
|
||||||
|
int direction = 0;
|
||||||
|
if (phase == ((fptr->phase+1) & 3))
|
||||||
|
direction = 1;
|
||||||
|
if (phase == ((fptr->phase+3) & 3))
|
||||||
|
direction = -1;
|
||||||
|
if (direction) {
|
||||||
|
fptr->phase = MAX(0,MIN(79,fptr->phase+direction));
|
||||||
|
if (!(fptr->phase & 1)) {
|
||||||
|
int newtrack = MIN(TRACKS-1,fptr->phase >> 1);
|
||||||
|
if (newtrack != fptr->track) {
|
||||||
|
if (fptr->trackimage && fptr->trackimagedirty)
|
||||||
|
WriteTrack(currdrive);
|
||||||
|
fptr->track = newtrack;
|
||||||
|
fptr->trackimagedata = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (address == 0xE0) ? 0xFF : MemReturnRandomData(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DiskDestroy () {
|
||||||
|
RemoveDisk(0);
|
||||||
|
RemoveDisk(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall DiskEnable (WORD, BYTE address, BYTE, BYTE, ULONG) {
|
||||||
|
currdrive = address & 1;
|
||||||
|
floppy[!currdrive].spinning = 0;
|
||||||
|
floppy[!currdrive].writelight = 0;
|
||||||
|
CheckSpinning();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
LPCTSTR DiskGetFullName (int drive) {
|
||||||
|
return floppy[drive].fullname;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DiskGetLightStatus (int *drive1, int *drive2) {
|
||||||
|
*drive1 = floppy[0].spinning ? floppy[0].writelight ? 2
|
||||||
|
: 1
|
||||||
|
: 0;
|
||||||
|
*drive2 = floppy[1].spinning ? floppy[1].writelight ? 2
|
||||||
|
: 1
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
LPCTSTR DiskGetName (int drive) {
|
||||||
|
return floppy[drive].imagename;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DiskInitialize () {
|
||||||
|
int loop = DRIVES;
|
||||||
|
while (loop--)
|
||||||
|
ZeroMemory(&floppy[loop],sizeof(floppyrec));
|
||||||
|
TCHAR imagefilename[MAX_PATH];
|
||||||
|
_tcscpy(imagefilename,progdir);
|
||||||
|
_tcscat(imagefilename,TEXT("MASTER.DSK"));
|
||||||
|
DiskInsert(0,imagefilename,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
int DiskInsert (int drive, LPCTSTR imagefilename, BOOL writeprotected, BOOL createifnecessary) {
|
||||||
|
floppyptr fptr = &floppy[drive];
|
||||||
|
if (fptr->imagehandle)
|
||||||
|
RemoveDisk(drive);
|
||||||
|
ZeroMemory(fptr,sizeof(floppyrec));
|
||||||
|
fptr->writeprotected = writeprotected;
|
||||||
|
int error = ImageOpen(imagefilename,
|
||||||
|
&fptr->imagehandle,
|
||||||
|
&fptr->writeprotected,
|
||||||
|
createifnecessary);
|
||||||
|
if (!error)
|
||||||
|
GetImageTitle(imagefilename,fptr);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BOOL DiskIsSpinning () {
|
||||||
|
return floppymotoron;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DiskNotifyInvalidImage (LPCTSTR imagefilename,int error) {
|
||||||
|
TCHAR buffer[MAX_PATH+128];
|
||||||
|
switch (error) {
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
wsprintf(buffer,
|
||||||
|
TEXT("Unable to open the file %s."),
|
||||||
|
(LPCTSTR)imagefilename);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
wsprintf(buffer,
|
||||||
|
TEXT("Unable to use the file %s\nbecause the ")
|
||||||
|
TEXT("disk image format is not recognized."),
|
||||||
|
(LPCTSTR)imagefilename);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
// IGNORE OTHER ERRORS SILENTLY
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MessageBox(framewindow,
|
||||||
|
buffer,
|
||||||
|
TITLE,
|
||||||
|
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall DiskReadWrite (WORD programcounter, BYTE, BYTE, BYTE, ULONG) {
|
||||||
|
floppyptr fptr = &floppy[currdrive];
|
||||||
|
diskaccessed = 1;
|
||||||
|
if ((!fptr->trackimagedata) && fptr->imagehandle)
|
||||||
|
ReadTrack(currdrive);
|
||||||
|
if (!fptr->trackimagedata)
|
||||||
|
return 0xFF;
|
||||||
|
BYTE result = 0;
|
||||||
|
if ((!floppywritemode) || (!fptr->writeprotected))
|
||||||
|
if (floppywritemode)
|
||||||
|
if (floppylatch & 0x80) {
|
||||||
|
*(fptr->trackimage+fptr->byte) = floppylatch;
|
||||||
|
fptr->trackimagedirty = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
result = *(fptr->trackimage+fptr->byte);
|
||||||
|
if (++fptr->byte >= fptr->nibbles)
|
||||||
|
fptr->byte = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DiskReset () {
|
||||||
|
floppymotoron = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DiskSelectImage (int drive, LPSTR pszFilename)
|
||||||
|
{
|
||||||
|
TCHAR directory[MAX_PATH] = TEXT("");
|
||||||
|
TCHAR filename[MAX_PATH];
|
||||||
|
TCHAR title[40];
|
||||||
|
|
||||||
|
strcpy(filename, pszFilename);
|
||||||
|
|
||||||
|
RegLoadString(TEXT("Preferences"),TEXT("Starting Directory"),1,directory,MAX_PATH);
|
||||||
|
_tcscpy(title,TEXT("Select Disk Image For Drive "));
|
||||||
|
_tcscat(title,drive ? TEXT("2") : TEXT("1"));
|
||||||
|
|
||||||
|
OPENFILENAME ofn;
|
||||||
|
ZeroMemory(&ofn,sizeof(OPENFILENAME));
|
||||||
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
||||||
|
ofn.hwndOwner = framewindow;
|
||||||
|
ofn.hInstance = instance;
|
||||||
|
ofn.lpstrFilter = TEXT("All Images\0*.apl;*.bin;*.do;*.dsk;*.iie;*.nib;*.po\0")
|
||||||
|
TEXT("Disk Images (*.bin,*.do,*.dsk,*.iie,*.nib,*.po)\0*.bin;*.do;*.dsk;*.iie;*.nib;*.po\0")
|
||||||
|
TEXT("All Files\0*.*\0");
|
||||||
|
ofn.lpstrFile = filename;
|
||||||
|
ofn.nMaxFile = MAX_PATH;
|
||||||
|
ofn.lpstrInitialDir = directory;
|
||||||
|
ofn.Flags = OFN_PATHMUSTEXIST;
|
||||||
|
ofn.lpstrTitle = title;
|
||||||
|
|
||||||
|
if (GetOpenFileName(&ofn))
|
||||||
|
{
|
||||||
|
if ((!ofn.nFileExtension) || !filename[ofn.nFileExtension])
|
||||||
|
_tcscat(filename,TEXT(".DSK"));
|
||||||
|
|
||||||
|
int error = DiskInsert(drive,filename,ofn.Flags & OFN_READONLY,1);
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
|
filename[ofn.nFileOffset] = 0;
|
||||||
|
if (_tcsicmp(directory,filename))
|
||||||
|
RegSaveString(TEXT("Preferences"),TEXT("Starting Directory"),1,filename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DiskNotifyInvalidImage(filename,error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DiskSelect (int drive)
|
||||||
|
{
|
||||||
|
DiskSelectImage(drive, TEXT(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall DiskSetLatchValue (WORD, BYTE, BYTE write, BYTE value, ULONG) {
|
||||||
|
if (write)
|
||||||
|
floppylatch = value;
|
||||||
|
return floppylatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall DiskSetReadMode (WORD, BYTE, BYTE, BYTE, ULONG) {
|
||||||
|
floppywritemode = 0;
|
||||||
|
return MemReturnRandomData(floppy[currdrive].writeprotected);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall DiskSetWriteMode (WORD, BYTE, BYTE, BYTE, ULONG) {
|
||||||
|
floppywritemode = 1;
|
||||||
|
BOOL modechange = !floppy[currdrive].writelight;
|
||||||
|
floppy[currdrive].writelight = 20000;
|
||||||
|
if (modechange)
|
||||||
|
FrameRefreshStatus(DRAW_LEDS);
|
||||||
|
return MemReturnRandomData(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DiskUpdatePosition (DWORD cycles) {
|
||||||
|
int loop = 2;
|
||||||
|
while (loop--) {
|
||||||
|
floppyptr fptr = &floppy[loop];
|
||||||
|
if (fptr->spinning && !floppymotoron) {
|
||||||
|
if (!(fptr->spinning -= MIN(fptr->spinning,(cycles >> 6))))
|
||||||
|
FrameRefreshStatus(DRAW_LEDS);
|
||||||
|
}
|
||||||
|
if (floppywritemode && (currdrive == loop) && fptr->spinning)
|
||||||
|
fptr->writelight = 20000;
|
||||||
|
else if (fptr->writelight) {
|
||||||
|
if (!(fptr->writelight -= MIN(fptr->writelight,(cycles >> 6))))
|
||||||
|
FrameRefreshStatus(DRAW_LEDS);
|
||||||
|
}
|
||||||
|
if ((!enhancedisk) && (!diskaccessed) && fptr->spinning) {
|
||||||
|
needsprecision = cumulativecycles;
|
||||||
|
fptr->byte += (cycles >> 5);
|
||||||
|
if (fptr->byte >= fptr->nibbles)
|
||||||
|
fptr->byte -= fptr->nibbles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diskaccessed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
bool DiskDriveSwap()
|
||||||
|
{
|
||||||
|
// Refuse to swap if either Disk][ is active
|
||||||
|
if(floppy[0].spinning || floppy[1].spinning)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Swap disks between drives
|
||||||
|
floppyrec fr;
|
||||||
|
|
||||||
|
// Swap trackimage ptrs (so don't need to swap the buffers' data)
|
||||||
|
memcpy(&fr, &floppy[0], sizeof(floppyrec));
|
||||||
|
memcpy(&floppy[0], &floppy[1], sizeof(floppyrec));
|
||||||
|
memcpy(&floppy[1], &fr, sizeof(floppyrec));
|
||||||
|
|
||||||
|
FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
DWORD DiskGetSnapshot(SS_CARD_DISK2* pSS, DWORD dwSlot)
|
||||||
|
{
|
||||||
|
pSS->Hdr.UnitHdr.dwLength = sizeof(SS_CARD_DISK2);
|
||||||
|
pSS->Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,1);
|
||||||
|
|
||||||
|
pSS->Hdr.dwSlot = dwSlot;
|
||||||
|
pSS->Hdr.dwType = CT_Disk2;
|
||||||
|
|
||||||
|
pSS->currdrive = currdrive;
|
||||||
|
pSS->diskaccessed = diskaccessed;
|
||||||
|
pSS->enhancedisk = enhancedisk;
|
||||||
|
pSS->floppylatch = floppylatch;
|
||||||
|
pSS->floppymotoron = floppymotoron;
|
||||||
|
pSS->floppywritemode = floppywritemode;
|
||||||
|
|
||||||
|
for(UINT i=0; i<2; i++)
|
||||||
|
{
|
||||||
|
strcpy(pSS->Unit[i].szFileName, floppy[i].fullname);
|
||||||
|
pSS->Unit[i].track = floppy[i].track;
|
||||||
|
pSS->Unit[i].phase = floppy[i].phase;
|
||||||
|
pSS->Unit[i].byte = floppy[i].byte;
|
||||||
|
pSS->Unit[i].writeprotected = floppy[i].writeprotected;
|
||||||
|
pSS->Unit[i].trackimagedata = floppy[i].trackimagedata;
|
||||||
|
pSS->Unit[i].trackimagedirty = floppy[i].trackimagedirty;
|
||||||
|
pSS->Unit[i].spinning = floppy[i].spinning;
|
||||||
|
pSS->Unit[i].writelight = floppy[i].writelight;
|
||||||
|
pSS->Unit[i].nibbles = floppy[i].nibbles;
|
||||||
|
|
||||||
|
if(floppy[i].trackimage)
|
||||||
|
memcpy(pSS->Unit[i].nTrack, floppy[i].trackimage, NIBBLES_PER_TRACK);
|
||||||
|
else
|
||||||
|
memset(pSS->Unit[i].nTrack, 0, NIBBLES_PER_TRACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD DiskSetSnapshot(SS_CARD_DISK2* pSS, DWORD /*dwSlot*/)
|
||||||
|
{
|
||||||
|
if(pSS->Hdr.UnitHdr.dwVersion != MAKE_VERSION(1,0,0,1))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
currdrive = pSS->currdrive;
|
||||||
|
diskaccessed = pSS->diskaccessed;
|
||||||
|
enhancedisk = pSS->enhancedisk;
|
||||||
|
floppylatch = pSS->floppylatch;
|
||||||
|
floppymotoron = pSS->floppymotoron;
|
||||||
|
floppywritemode = pSS->floppywritemode;
|
||||||
|
|
||||||
|
for(UINT i=0; i<2; i++)
|
||||||
|
{
|
||||||
|
bool bImageError = false;
|
||||||
|
|
||||||
|
ZeroMemory(&floppy[i], sizeof(floppyrec));
|
||||||
|
if(pSS->Unit[i].szFileName[0] == 0x00)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
DWORD dwAttributes = GetFileAttributes(pSS->Unit[i].szFileName);
|
||||||
|
if(dwAttributes == INVALID_FILE_ATTRIBUTES)
|
||||||
|
{
|
||||||
|
// Get user to browse for file
|
||||||
|
DiskSelectImage(i, pSS->Unit[i].szFileName);
|
||||||
|
|
||||||
|
dwAttributes = GetFileAttributes(pSS->Unit[i].szFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dwAttributes != INVALID_FILE_ATTRIBUTES)
|
||||||
|
{
|
||||||
|
BOOL bWriteProtected = (dwAttributes & FILE_ATTRIBUTE_READONLY) ? TRUE : FALSE;
|
||||||
|
|
||||||
|
if(DiskInsert(i, pSS->Unit[i].szFileName, bWriteProtected, 0))
|
||||||
|
bImageError = true;
|
||||||
|
|
||||||
|
// DiskInsert() sets up:
|
||||||
|
// . fullname
|
||||||
|
// . imagename
|
||||||
|
// . writeprotected
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
// strcpy(floppy[i].fullname, pSS->Unit[i].szFileName);
|
||||||
|
floppy[i].track = pSS->Unit[i].track;
|
||||||
|
floppy[i].phase = pSS->Unit[i].phase;
|
||||||
|
floppy[i].byte = pSS->Unit[i].byte;
|
||||||
|
// floppy[i].writeprotected = pSS->Unit[i].writeprotected;
|
||||||
|
floppy[i].trackimagedata = pSS->Unit[i].trackimagedata;
|
||||||
|
floppy[i].trackimagedirty = pSS->Unit[i].trackimagedirty;
|
||||||
|
floppy[i].spinning = pSS->Unit[i].spinning;
|
||||||
|
floppy[i].writelight = pSS->Unit[i].writelight;
|
||||||
|
floppy[i].nibbles = pSS->Unit[i].nibbles;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
if(!bImageError)
|
||||||
|
{
|
||||||
|
if((floppy[i].trackimage == NULL) && floppy[i].nibbles)
|
||||||
|
AllocTrack(i);
|
||||||
|
|
||||||
|
if(floppy[i].trackimage == NULL)
|
||||||
|
bImageError = true;
|
||||||
|
else
|
||||||
|
memcpy(floppy[i].trackimage, pSS->Unit[i].nTrack, NIBBLES_PER_TRACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bImageError)
|
||||||
|
{
|
||||||
|
floppy[i].trackimagedata = 0;
|
||||||
|
floppy[i].trackimagedirty = 0;
|
||||||
|
floppy[i].nibbles = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define DRIVE_1 0
|
||||||
|
#define DRIVE_2 1
|
||||||
|
|
||||||
|
#define DRIVES 2
|
||||||
|
#define TRACKS 35
|
||||||
|
|
||||||
|
extern BOOL enhancedisk;
|
||||||
|
|
||||||
|
void DiskBoot ();
|
||||||
|
void DiskDestroy ();
|
||||||
|
LPCTSTR DiskGetFullName (int);
|
||||||
|
void DiskGetLightStatus (int *,int *);
|
||||||
|
LPCTSTR DiskGetName (int);
|
||||||
|
void DiskInitialize ();
|
||||||
|
int DiskInsert (int,LPCTSTR,BOOL,BOOL);
|
||||||
|
BOOL DiskIsSpinning ();
|
||||||
|
void DiskNotifyInvalidImage (LPCTSTR,int);
|
||||||
|
void DiskReset ();
|
||||||
|
void DiskSelect (int);
|
||||||
|
void DiskUpdatePosition (DWORD);
|
||||||
|
bool DiskDriveSwap();
|
||||||
|
DWORD DiskGetSnapshot(SS_CARD_DISK2* pSS, DWORD dwSlot);
|
||||||
|
DWORD DiskSetSnapshot(SS_CARD_DISK2* pSS, DWORD dwSlot);
|
||||||
|
|
||||||
|
BYTE __stdcall DiskControlMotor (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall DiskControlStepper (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall DiskEnable (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall DiskReadWrite (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall DiskSetLatchValue (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall DiskSetReadMode (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall DiskSetWriteMode (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
|
@ -0,0 +1,900 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, Michael O'Brien
|
||||||
|
Copyright (C) 1999-2001, Oliver Schmidt
|
||||||
|
Copyright (C) 2002-2005, Tom Charlesworth
|
||||||
|
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: Disk Image
|
||||||
|
*
|
||||||
|
* Author: Various
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
|
||||||
|
/* DO logical order 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||||
|
/* physical order 0 D B 9 7 5 3 1 E C A 8 6 4 2 F */
|
||||||
|
|
||||||
|
/* PO logical order 0 E D C B A 9 8 7 6 5 4 3 2 1 F */
|
||||||
|
/* physical order 0 2 4 6 8 A C E 1 3 5 7 9 B D F */
|
||||||
|
|
||||||
|
typedef struct _imageinforec {
|
||||||
|
TCHAR filename[MAX_PATH];
|
||||||
|
DWORD format;
|
||||||
|
HANDLE file;
|
||||||
|
DWORD offset;
|
||||||
|
BOOL writeprotected;
|
||||||
|
DWORD headersize;
|
||||||
|
LPBYTE header;
|
||||||
|
BOOL validtrack[TRACKS];
|
||||||
|
} imageinforec, *imageinfoptr;
|
||||||
|
|
||||||
|
typedef BOOL (*boottype )(imageinfoptr);
|
||||||
|
typedef DWORD (*detecttype)(LPBYTE,DWORD);
|
||||||
|
typedef void (*readtype )(imageinfoptr,int,int,LPBYTE,int *);
|
||||||
|
typedef void (*writetype )(imageinfoptr,int,int,LPBYTE,int);
|
||||||
|
|
||||||
|
BOOL AplBoot (imageinfoptr ptr);
|
||||||
|
DWORD AplDetect (LPBYTE imageptr, DWORD imagesize);
|
||||||
|
DWORD DoDetect (LPBYTE imageptr, DWORD imagesize);
|
||||||
|
void DoRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles);
|
||||||
|
void DoWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles);
|
||||||
|
DWORD IieDetect (LPBYTE imageptr, DWORD imagesize);
|
||||||
|
void IieRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles);
|
||||||
|
void IieWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles);
|
||||||
|
DWORD Nib1Detect (LPBYTE imageptr, DWORD imagesize);
|
||||||
|
void Nib1Read (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles);
|
||||||
|
void Nib1Write (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles);
|
||||||
|
DWORD Nib2Detect (LPBYTE imageptr, DWORD imagesize);
|
||||||
|
void Nib2Read (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles);
|
||||||
|
void Nib2Write (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles);
|
||||||
|
DWORD PoDetect (LPBYTE imageptr, DWORD imagesize);
|
||||||
|
void PoRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles);
|
||||||
|
void PoWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles);
|
||||||
|
BOOL PrgBoot (imageinfoptr ptr);
|
||||||
|
DWORD PrgDetect (LPBYTE imageptr, DWORD imagesize);
|
||||||
|
|
||||||
|
typedef struct _imagetyperec {
|
||||||
|
LPCTSTR createexts;
|
||||||
|
LPCTSTR rejectexts;
|
||||||
|
detecttype detect;
|
||||||
|
boottype boot;
|
||||||
|
readtype read;
|
||||||
|
writetype write;
|
||||||
|
} imagetyperec, *imagetypeptr;
|
||||||
|
|
||||||
|
static imagetyperec imagetype[IMAGETYPES] = {{TEXT(".prg"),
|
||||||
|
TEXT(".do;.dsk;.iie;.nib;.po"),
|
||||||
|
PrgDetect,
|
||||||
|
PrgBoot,
|
||||||
|
NULL,
|
||||||
|
NULL},
|
||||||
|
{TEXT(".do;.dsk"),
|
||||||
|
TEXT(".nib;.iie;.po;.prg"),
|
||||||
|
DoDetect,
|
||||||
|
NULL,
|
||||||
|
DoRead,
|
||||||
|
DoWrite},
|
||||||
|
{TEXT(".po"),
|
||||||
|
TEXT(".do;.iie;.nib;.prg"),
|
||||||
|
PoDetect,
|
||||||
|
NULL,
|
||||||
|
PoRead,
|
||||||
|
PoWrite},
|
||||||
|
{TEXT(".apl"),
|
||||||
|
TEXT(".do;.dsk;.iie;.nib;.po"),
|
||||||
|
AplDetect,
|
||||||
|
AplBoot,
|
||||||
|
NULL,
|
||||||
|
NULL},
|
||||||
|
{TEXT(".nib"),
|
||||||
|
TEXT(".do;.iie;.po;.prg"),
|
||||||
|
Nib1Detect,
|
||||||
|
NULL,
|
||||||
|
Nib1Read,
|
||||||
|
Nib1Write},
|
||||||
|
{TEXT(".nb2"),
|
||||||
|
TEXT(".do;.iie;.po;.prg"),
|
||||||
|
Nib2Detect,
|
||||||
|
NULL,
|
||||||
|
Nib2Read,
|
||||||
|
Nib2Write},
|
||||||
|
{TEXT(".iie"),
|
||||||
|
TEXT(".do.;.nib;.po;.prg"),
|
||||||
|
IieDetect,
|
||||||
|
NULL,
|
||||||
|
IieRead,
|
||||||
|
IieWrite}};
|
||||||
|
|
||||||
|
static BYTE diskbyte[0x40] = {0x96,0x97,0x9A,0x9B,0x9D,0x9E,0x9F,0xA6,
|
||||||
|
0xA7,0xAB,0xAC,0xAD,0xAE,0xAF,0xB2,0xB3,
|
||||||
|
0xB4,0xB5,0xB6,0xB7,0xB9,0xBA,0xBB,0xBC,
|
||||||
|
0xBD,0xBE,0xBF,0xCB,0xCD,0xCE,0xCF,0xD3,
|
||||||
|
0xD6,0xD7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,
|
||||||
|
0xDF,0xE5,0xE6,0xE7,0xE9,0xEA,0xEB,0xEC,
|
||||||
|
0xED,0xEE,0xEF,0xF2,0xF3,0xF4,0xF5,0xF6,
|
||||||
|
0xF7,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF};
|
||||||
|
|
||||||
|
static BYTE sectornumber[3][0x10] = {{0x00,0x08,0x01,0x09,0x02,0x0A,0x03,0x0B,
|
||||||
|
0x04,0x0C,0x05,0x0D,0x06,0x0E,0x07,0x0F},
|
||||||
|
{0x00,0x07,0x0E,0x06,0x0D,0x05,0x0C,0x04,
|
||||||
|
0x0B,0x03,0x0A,0x02,0x09,0x01,0x08,0x0F},
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};
|
||||||
|
|
||||||
|
static LPBYTE workbuffer = NULL;
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* NIBBLIZATION FUNCTIONS
|
||||||
|
*
|
||||||
|
***/
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
LPBYTE Code62 (int sector) {
|
||||||
|
|
||||||
|
// CONVERT THE 256 8-BIT BYTES INTO 342 6-BIT BYTES, WHICH WE STORE
|
||||||
|
// STARTING AT 4K INTO THE WORK BUFFER.
|
||||||
|
{
|
||||||
|
LPBYTE sectorbase = workbuffer+(sector << 8);
|
||||||
|
LPBYTE resultptr = workbuffer+0x1000;
|
||||||
|
BYTE offset = 0xAC;
|
||||||
|
while (offset != 0x02) {
|
||||||
|
BYTE value = 0;
|
||||||
|
#define ADDVALUE(a) value = (value << 2) | \
|
||||||
|
(((a) & 0x01) << 1) | \
|
||||||
|
(((a) & 0x02) >> 1)
|
||||||
|
ADDVALUE(*(sectorbase+offset)); offset -= 0x56;
|
||||||
|
ADDVALUE(*(sectorbase+offset)); offset -= 0x56;
|
||||||
|
ADDVALUE(*(sectorbase+offset)); offset -= 0x53;
|
||||||
|
#undef ADDVALUE
|
||||||
|
*(resultptr++) = value << 2;
|
||||||
|
}
|
||||||
|
*(resultptr-2) &= 0x3F;
|
||||||
|
*(resultptr-1) &= 0x3F;
|
||||||
|
int loop = 0;
|
||||||
|
while (loop < 0x100)
|
||||||
|
*(resultptr++) = *(sectorbase+(loop++));
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXCLUSIVE-OR THE ENTIRE DATA BLOCK WITH ITSELF OFFSET BY ONE BYTE,
|
||||||
|
// CREATING A 343RD BYTE WHICH IS USED AS A CHECKSUM. STORE THE NEW
|
||||||
|
// BLOCK OF 343 BYTES STARTING AT 5K INTO THE WORK BUFFER.
|
||||||
|
{
|
||||||
|
BYTE savedval = 0;
|
||||||
|
LPBYTE sourceptr = workbuffer+0x1000;
|
||||||
|
LPBYTE resultptr = workbuffer+0x1400;
|
||||||
|
int loop = 342;
|
||||||
|
while (loop--) {
|
||||||
|
*(resultptr++) = savedval ^ *sourceptr;
|
||||||
|
savedval = *(sourceptr++);
|
||||||
|
}
|
||||||
|
*resultptr = savedval;
|
||||||
|
}
|
||||||
|
|
||||||
|
// USING A LOOKUP TABLE, CONVERT THE 6-BIT BYTES INTO DISK BYTES. A VALID
|
||||||
|
// DISK BYTE IS A BYTE THAT HAS THE HIGH BIT SET, AT LEAST TWO ADJACENT
|
||||||
|
// BITS SET (EXCLUDING THE HIGH BIT), AND AT MOST ONE PAIR OF CONSECUTIVE
|
||||||
|
// ZERO BITS. THE CONVERTED BLOCK OF 343 BYTES IS STORED STARTING AT 4K
|
||||||
|
// INTO THE WORK BUFFER.
|
||||||
|
{
|
||||||
|
LPBYTE sourceptr = workbuffer+0x1400;
|
||||||
|
LPBYTE resultptr = workbuffer+0x1000;
|
||||||
|
int loop = 343;
|
||||||
|
while (loop--)
|
||||||
|
*(resultptr++) = diskbyte[(*(sourceptr++)) >> 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
return workbuffer+0x1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void Decode62 (LPBYTE imageptr) {
|
||||||
|
|
||||||
|
// IF WE HAVEN'T ALREADY DONE SO, GENERATE A TABLE FOR CONVERTING
|
||||||
|
// DISK BYTES BACK INTO 6-BIT BYTES
|
||||||
|
static BOOL tablegenerated = 0;
|
||||||
|
static BYTE sixbitbyte[0x80];
|
||||||
|
if (!tablegenerated) {
|
||||||
|
ZeroMemory(sixbitbyte,0x80);
|
||||||
|
int loop = 0;
|
||||||
|
while (loop < 0x40) {
|
||||||
|
sixbitbyte[diskbyte[loop]-0x80] = loop << 2;
|
||||||
|
loop++;
|
||||||
|
}
|
||||||
|
tablegenerated = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// USING OUR TABLE, CONVERT THE DISK BYTES BACK INTO 6-BIT BYTES
|
||||||
|
{
|
||||||
|
LPBYTE sourceptr = workbuffer+0x1000;
|
||||||
|
LPBYTE resultptr = workbuffer+0x1400;
|
||||||
|
int loop = 343;
|
||||||
|
while (loop--)
|
||||||
|
*(resultptr++) = sixbitbyte[*(sourceptr++) & 0x7F];
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXCLUSIVE-OR THE ENTIRE DATA BLOCK WITH ITSELF OFFSET BY ONE BYTE
|
||||||
|
// TO UNDO THE EFFECTS OF THE CHECKSUMMING PROCESS
|
||||||
|
{
|
||||||
|
BYTE savedval = 0;
|
||||||
|
LPBYTE sourceptr = workbuffer+0x1400;
|
||||||
|
LPBYTE resultptr = workbuffer+0x1000;
|
||||||
|
int loop = 342;
|
||||||
|
while (loop--) {
|
||||||
|
*resultptr = savedval ^ *(sourceptr++);
|
||||||
|
savedval = *(resultptr++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONVERT THE 342 6-BIT BYTES INTO 256 8-BIT BYTES
|
||||||
|
{
|
||||||
|
LPBYTE lowbitsptr = workbuffer+0x1000;
|
||||||
|
LPBYTE sectorbase = workbuffer+0x1056;
|
||||||
|
BYTE offset = 0xAC;
|
||||||
|
while (offset != 0x02) {
|
||||||
|
if (offset >= 0xAC)
|
||||||
|
*(imageptr+offset) = (*(sectorbase+offset) & 0xFC)
|
||||||
|
| (((*lowbitsptr) & 0x80) >> 7)
|
||||||
|
| (((*lowbitsptr) & 0x40) >> 5);
|
||||||
|
offset -= 0x56;
|
||||||
|
*(imageptr+offset) = (*(sectorbase+offset) & 0xFC)
|
||||||
|
| (((*lowbitsptr) & 0x20) >> 5)
|
||||||
|
| (((*lowbitsptr) & 0x10) >> 3);
|
||||||
|
offset -= 0x56;
|
||||||
|
*(imageptr+offset) = (*(sectorbase+offset) & 0xFC)
|
||||||
|
| (((*lowbitsptr) & 0x08) >> 3)
|
||||||
|
| (((*lowbitsptr) & 0x04) >> 1);
|
||||||
|
offset -= 0x53;
|
||||||
|
lowbitsptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DenibblizeTrack (LPBYTE trackimage, BOOL dosorder, int nibbles) {
|
||||||
|
ZeroMemory(workbuffer,0x1000);
|
||||||
|
|
||||||
|
// SEARCH THROUGH THE TRACK IMAGE FOR EACH SECTOR. FOR EVERY SECTOR
|
||||||
|
// WE FIND, COPY THE NIBBLIZED DATA FOR THAT SECTOR INTO THE WORK
|
||||||
|
// BUFFER AT OFFSET 4K. THEN CALL DECODE62() TO DENIBBLIZE THE DATA
|
||||||
|
// IN THE BUFFER AND WRITE IT INTO THE FIRST PART OF THE WORK BUFFER
|
||||||
|
// OFFSET BY THE SECTOR NUMBER.
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
int partsleft = 33;
|
||||||
|
int sector = 0;
|
||||||
|
while (partsleft--) {
|
||||||
|
BYTE byteval[3] = {0,0,0};
|
||||||
|
int bytenum = 0;
|
||||||
|
int loop = nibbles;
|
||||||
|
while ((loop--) && (bytenum < 3)) {
|
||||||
|
if (bytenum)
|
||||||
|
byteval[bytenum++] = *(trackimage+offset++);
|
||||||
|
else if (*(trackimage+offset++) == 0xD5)
|
||||||
|
bytenum = 1;
|
||||||
|
if (offset >= nibbles)
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
if ((bytenum == 3) && (byteval[1] = 0xAA)) {
|
||||||
|
int loop = 0;
|
||||||
|
int tempoffset = offset;
|
||||||
|
while (loop < 384) {
|
||||||
|
*(workbuffer+0x1000+loop++) = *(trackimage+tempoffset++);
|
||||||
|
if (tempoffset >= nibbles)
|
||||||
|
tempoffset = 0;
|
||||||
|
}
|
||||||
|
if (byteval[2] == 0x96)
|
||||||
|
sector = ((*(workbuffer+0x1004) & 0x55) << 1)
|
||||||
|
| (*(workbuffer+0x1005) & 0x55);
|
||||||
|
else if (byteval[2] == 0xAD) {
|
||||||
|
Decode62(workbuffer+(sectornumber[dosorder][sector] << 8));
|
||||||
|
sector = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
DWORD NibblizeTrack (LPBYTE trackimagebuffer, BOOL dosorder, int track) {
|
||||||
|
ZeroMemory(workbuffer+4096,4096);
|
||||||
|
LPBYTE imageptr = trackimagebuffer;
|
||||||
|
BYTE sector = 0;
|
||||||
|
|
||||||
|
// WRITE GAP ONE, WHICH CONTAINS 48 SELF-SYNC BYTES
|
||||||
|
int loop;
|
||||||
|
for (loop = 0; loop < 48; loop++)
|
||||||
|
*(imageptr++) = 0xFF;
|
||||||
|
|
||||||
|
while (sector < 16) {
|
||||||
|
|
||||||
|
// WRITE THE ADDRESS FIELD, WHICH CONTAINS:
|
||||||
|
// - PROLOGUE (D5AA96)
|
||||||
|
// - VOLUME NUMBER ("4 AND 4" ENCODED)
|
||||||
|
// - TRACK NUMBER ("4 AND 4" ENCODED)
|
||||||
|
// - SECTOR NUMBER ("4 AND 4" ENCODED)
|
||||||
|
// - CHECKSUM ("4 AND 4" ENCODED)
|
||||||
|
// - EPILOGUE (DEAAEB)
|
||||||
|
*(imageptr++) = 0xD5;
|
||||||
|
*(imageptr++) = 0xAA;
|
||||||
|
*(imageptr++) = 0x96;
|
||||||
|
*(imageptr++) = 0xFF;
|
||||||
|
*(imageptr++) = 0xFE;
|
||||||
|
#define CODE44A(a) ((((a) >> 1) & 0x55) | 0xAA)
|
||||||
|
#define CODE44B(a) (((a) & 0x55) | 0xAA)
|
||||||
|
*(imageptr++) = CODE44A((BYTE)track);
|
||||||
|
*(imageptr++) = CODE44B((BYTE)track);
|
||||||
|
*(imageptr++) = CODE44A(sector);
|
||||||
|
*(imageptr++) = CODE44B(sector);
|
||||||
|
*(imageptr++) = CODE44A(0xFE ^ ((BYTE)track) ^ sector);
|
||||||
|
*(imageptr++) = CODE44B(0xFE ^ ((BYTE)track) ^ sector);
|
||||||
|
#undef CODE44A
|
||||||
|
#undef CODE44B
|
||||||
|
*(imageptr++) = 0xDE;
|
||||||
|
*(imageptr++) = 0xAA;
|
||||||
|
*(imageptr++) = 0xEB;
|
||||||
|
|
||||||
|
// WRITE GAP TWO, WHICH CONTAINS SIX SELF-SYNC BYTES
|
||||||
|
for (loop = 0; loop < 6; loop++)
|
||||||
|
*(imageptr++) = 0xFF;
|
||||||
|
|
||||||
|
// WRITE THE DATA FIELD, WHICH CONTAINS:
|
||||||
|
// - PROLOGUE (D5AAAD)
|
||||||
|
// - 343 6-BIT BYTES OF NIBBLIZED DATA, INCLUDING A 6-BIT CHECKSUM
|
||||||
|
// - EPILOGUE (DEAAEB)
|
||||||
|
*(imageptr++) = 0xD5;
|
||||||
|
*(imageptr++) = 0xAA;
|
||||||
|
*(imageptr++) = 0xAD;
|
||||||
|
CopyMemory(imageptr,Code62(sectornumber[dosorder][sector]),343);
|
||||||
|
imageptr += 343;
|
||||||
|
*(imageptr++) = 0xDE;
|
||||||
|
*(imageptr++) = 0xAA;
|
||||||
|
*(imageptr++) = 0xEB;
|
||||||
|
|
||||||
|
// WRITE GAP THREE, WHICH CONTAINS 27 SELF-SYNC BYTES
|
||||||
|
for (loop = 0; loop < 27; loop++)
|
||||||
|
*(imageptr++) = 0xFF;
|
||||||
|
|
||||||
|
sector++;
|
||||||
|
}
|
||||||
|
return imageptr-trackimagebuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void SkewTrack (int track, int nibbles, LPBYTE trackimagebuffer) {
|
||||||
|
int skewbytes = (track*768) % nibbles;
|
||||||
|
CopyMemory(workbuffer,trackimagebuffer,nibbles);
|
||||||
|
CopyMemory(trackimagebuffer,workbuffer+skewbytes,nibbles-skewbytes);
|
||||||
|
CopyMemory(trackimagebuffer+nibbles-skewbytes,workbuffer,skewbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* RAW PROGRAM IMAGE (APL) FORMAT IMPLEMENTATION
|
||||||
|
*
|
||||||
|
***/
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BOOL AplBoot (imageinfoptr ptr) {
|
||||||
|
SetFilePointer(ptr->file,0,NULL,FILE_BEGIN);
|
||||||
|
WORD address = 0;
|
||||||
|
WORD length = 0;
|
||||||
|
DWORD bytesread;
|
||||||
|
ReadFile(ptr->file,&address,sizeof(WORD),&bytesread,NULL);
|
||||||
|
ReadFile(ptr->file,&length ,sizeof(WORD),&bytesread,NULL);
|
||||||
|
if ((((WORD)(address+length)) <= address) ||
|
||||||
|
(address >= 0xC000) ||
|
||||||
|
(address+length-1 >= 0xC000))
|
||||||
|
return 0;
|
||||||
|
ReadFile(ptr->file,mem+address,length,&bytesread,NULL);
|
||||||
|
int loop = 192;
|
||||||
|
while (loop--)
|
||||||
|
*(memdirty+loop) = 0xFF;
|
||||||
|
regs.pc = address;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
DWORD AplDetect (LPBYTE imageptr, DWORD imagesize) {
|
||||||
|
DWORD length = *(LPWORD)(imageptr+2);
|
||||||
|
return (((length+4) == imagesize) ||
|
||||||
|
((length+4+((256-((length+4) & 255)) & 255)) == imagesize));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* DOS ORDER (DO) FORMAT IMPLEMENTATION
|
||||||
|
*
|
||||||
|
***/
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
DWORD DoDetect (LPBYTE imageptr, DWORD imagesize) {
|
||||||
|
if (((imagesize < 143105) || (imagesize > 143364)) &&
|
||||||
|
(imagesize != 143403) && (imagesize != 143488))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// CHECK FOR A DOS ORDER IMAGE OF A DOS DISKETTE
|
||||||
|
{
|
||||||
|
int loop = 0;
|
||||||
|
BOOL mismatch = 0;
|
||||||
|
while ((loop++ < 15) && !mismatch)
|
||||||
|
if (*(imageptr+0x11002+(loop << 8)) != loop-1)
|
||||||
|
mismatch = 1;
|
||||||
|
if (!mismatch)
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK FOR A DOS ORDER IMAGE OF A PRODOS DISKETTE
|
||||||
|
{
|
||||||
|
int loop = 1;
|
||||||
|
BOOL mismatch = 0;
|
||||||
|
while ((loop++ < 5) && !mismatch)
|
||||||
|
if ((*(LPWORD)(imageptr+(loop << 9)+0x100) != ((loop == 5) ? 0 : 6-loop)) ||
|
||||||
|
(*(LPWORD)(imageptr+(loop << 9)+0x102) != ((loop == 2) ? 0 : 8-loop)))
|
||||||
|
mismatch = 1;
|
||||||
|
if (!mismatch)
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DoRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles) {
|
||||||
|
SetFilePointer(ptr->file,ptr->offset+(track << 12),NULL,FILE_BEGIN);
|
||||||
|
ZeroMemory(workbuffer,4096);
|
||||||
|
DWORD bytesread;
|
||||||
|
ReadFile(ptr->file,workbuffer,4096,&bytesread,NULL);
|
||||||
|
*nibbles = NibblizeTrack(trackimagebuffer,1,track);
|
||||||
|
if (!enhancedisk)
|
||||||
|
SkewTrack(track,*nibbles,trackimagebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void DoWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles) {
|
||||||
|
ZeroMemory(workbuffer,4096);
|
||||||
|
DenibblizeTrack(trackimage,1,nibbles);
|
||||||
|
SetFilePointer(ptr->file,ptr->offset+(track << 12),NULL,FILE_BEGIN);
|
||||||
|
DWORD byteswritten;
|
||||||
|
WriteFile(ptr->file,workbuffer,4096,&byteswritten,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* SIMSYSTEM IIE (IIE) FORMAT IMPLEMENTATION
|
||||||
|
*
|
||||||
|
***/
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void IieConvertSectorOrder (LPBYTE sourceorder) {
|
||||||
|
int loop = 16;
|
||||||
|
while (loop--) {
|
||||||
|
BYTE found = 0xFF;
|
||||||
|
int loop2 = 16;
|
||||||
|
while (loop2-- && (found == 0xFF))
|
||||||
|
if (*(sourceorder+loop2) == loop)
|
||||||
|
found = loop2;
|
||||||
|
if (found == 0xFF)
|
||||||
|
found = 0;
|
||||||
|
sectornumber[2][loop] = found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
DWORD IieDetect (LPBYTE imageptr, DWORD imagesize) {
|
||||||
|
if (strncmp((const char *)imageptr,"SIMSYSTEM_IIE",13) ||
|
||||||
|
(*(imageptr+13) > 3))
|
||||||
|
return 0;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void IieRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles) {
|
||||||
|
|
||||||
|
// IF WE HAVEN'T ALREADY DONE SO, READ THE IMAGE FILE HEADER
|
||||||
|
if (!ptr->header) {
|
||||||
|
ptr->header = (LPBYTE)VirtualAlloc(NULL,88,MEM_COMMIT,PAGE_READWRITE);
|
||||||
|
if (!ptr->header) {
|
||||||
|
*nibbles = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ZeroMemory(ptr->header,88);
|
||||||
|
DWORD bytesread;
|
||||||
|
SetFilePointer(ptr->file,0,NULL,FILE_BEGIN);
|
||||||
|
ReadFile(ptr->file,ptr->header,88,&bytesread,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// IF THIS IMAGE CONTAINS USER DATA, READ THE TRACK AND NIBBLIZE IT
|
||||||
|
if (*(ptr->header+13) <= 2) {
|
||||||
|
IieConvertSectorOrder(ptr->header+14);
|
||||||
|
SetFilePointer(ptr->file,(track << 12)+30,NULL,FILE_BEGIN);
|
||||||
|
ZeroMemory(workbuffer,4096);
|
||||||
|
DWORD bytesread;
|
||||||
|
ReadFile(ptr->file,workbuffer,4096,&bytesread,NULL);
|
||||||
|
*nibbles = NibblizeTrack(trackimagebuffer,2,track);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OTHERWISE, IF THIS IMAGE CONTAINS NIBBLE INFORMATION, READ IT
|
||||||
|
// DIRECTLY INTO THE TRACK BUFFER
|
||||||
|
else {
|
||||||
|
*nibbles = *(LPWORD)(ptr->header+(track << 1)+14);
|
||||||
|
DWORD offset = 88;
|
||||||
|
while (track--)
|
||||||
|
offset += *(LPWORD)(ptr->header+(track << 1)+14);
|
||||||
|
SetFilePointer(ptr->file,offset,NULL,FILE_BEGIN);
|
||||||
|
ZeroMemory(trackimagebuffer,*nibbles);
|
||||||
|
DWORD bytesread;
|
||||||
|
ReadFile(ptr->file,trackimagebuffer,*nibbles,&bytesread,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void IieWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles) {
|
||||||
|
// note: unimplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* NIBBLIZED 6656-NIBBLE (NIB) FORMAT IMPLEMENTATION
|
||||||
|
*
|
||||||
|
***/
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
DWORD Nib1Detect (LPBYTE imageptr, DWORD imagesize) {
|
||||||
|
return (imagesize == 232960) ? 2 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void Nib1Read (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles) {
|
||||||
|
SetFilePointer(ptr->file,ptr->offset+track*NIBBLES,NULL,FILE_BEGIN);
|
||||||
|
ReadFile(ptr->file,trackimagebuffer,NIBBLES,(DWORD *)nibbles,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void Nib1Write (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles) {
|
||||||
|
SetFilePointer(ptr->file,ptr->offset+track*NIBBLES,NULL,FILE_BEGIN);
|
||||||
|
DWORD byteswritten;
|
||||||
|
WriteFile(ptr->file,trackimage,nibbles,&byteswritten,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* NIBBLIZED 6384-NIBBLE (NB2) FORMAT IMPLEMENTATION
|
||||||
|
*
|
||||||
|
***/
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
DWORD Nib2Detect (LPBYTE imageptr, DWORD imagesize) {
|
||||||
|
return (imagesize == 223440) ? 2 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void Nib2Read (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles) {
|
||||||
|
SetFilePointer(ptr->file,ptr->offset+track*6384,NULL,FILE_BEGIN);
|
||||||
|
ReadFile(ptr->file,trackimagebuffer,6384,(DWORD *)nibbles,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void Nib2Write (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles) {
|
||||||
|
SetFilePointer(ptr->file,ptr->offset+track*6384,NULL,FILE_BEGIN);
|
||||||
|
DWORD byteswritten;
|
||||||
|
WriteFile(ptr->file,trackimage,nibbles,&byteswritten,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* PRODOS ORDER (PO) FORMAT IMPLEMENTATION
|
||||||
|
*
|
||||||
|
***/
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
DWORD PoDetect (LPBYTE imageptr, DWORD imagesize) {
|
||||||
|
if (((imagesize < 143105) || (imagesize > 143364)) &&
|
||||||
|
(imagesize != 143488))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// CHECK FOR A PRODOS ORDER IMAGE OF A DOS DISKETTE
|
||||||
|
{
|
||||||
|
int loop = 4;
|
||||||
|
BOOL mismatch = 0;
|
||||||
|
while ((loop++ < 13) && !mismatch)
|
||||||
|
if (*(imageptr+0x11002+(loop << 8)) != 14-loop)
|
||||||
|
mismatch = 1;
|
||||||
|
if (!mismatch)
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK FOR A PRODOS ORDER IMAGE OF A PRODOS DISKETTE
|
||||||
|
{
|
||||||
|
int loop = 1;
|
||||||
|
BOOL mismatch = 0;
|
||||||
|
while ((loop++ < 5) && !mismatch)
|
||||||
|
if ((*(LPWORD)(imageptr+(loop << 9) ) != ((loop == 2) ? 0 : loop-1)) ||
|
||||||
|
(*(LPWORD)(imageptr+(loop << 9)+2) != ((loop == 5) ? 0 : loop+1)))
|
||||||
|
mismatch = 1;
|
||||||
|
if (!mismatch)
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void PoRead (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimagebuffer, int *nibbles) {
|
||||||
|
SetFilePointer(ptr->file,ptr->offset+(track << 12),NULL,FILE_BEGIN);
|
||||||
|
ZeroMemory(workbuffer,4096);
|
||||||
|
DWORD bytesread;
|
||||||
|
ReadFile(ptr->file,workbuffer,4096,&bytesread,NULL);
|
||||||
|
*nibbles = NibblizeTrack(trackimagebuffer,0,track);
|
||||||
|
if (!enhancedisk)
|
||||||
|
SkewTrack(track,*nibbles,trackimagebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void PoWrite (imageinfoptr ptr, int track, int quartertrack, LPBYTE trackimage, int nibbles) {
|
||||||
|
ZeroMemory(workbuffer,4096);
|
||||||
|
DenibblizeTrack(trackimage,0,nibbles);
|
||||||
|
SetFilePointer(ptr->file,ptr->offset+(track << 12),NULL,FILE_BEGIN);
|
||||||
|
DWORD byteswritten;
|
||||||
|
WriteFile(ptr->file,workbuffer,4096,&byteswritten,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* PRODOS PROGRAM IMAGE (PRG) FORMAT IMPLEMENTATION
|
||||||
|
*
|
||||||
|
***/
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BOOL PrgBoot (imageinfoptr ptr) {
|
||||||
|
SetFilePointer(ptr->file,5,NULL,FILE_BEGIN);
|
||||||
|
WORD address = 0;
|
||||||
|
WORD length = 0;
|
||||||
|
DWORD bytesread;
|
||||||
|
ReadFile(ptr->file,&address,sizeof(WORD),&bytesread,NULL);
|
||||||
|
ReadFile(ptr->file,&length ,sizeof(WORD),&bytesread,NULL);
|
||||||
|
length <<= 1;
|
||||||
|
if ((((WORD)(address+length)) <= address) ||
|
||||||
|
(address >= 0xC000) ||
|
||||||
|
(address+length-1 >= 0xC000))
|
||||||
|
return 0;
|
||||||
|
SetFilePointer(ptr->file,128,NULL,FILE_BEGIN);
|
||||||
|
ReadFile(ptr->file,mem+address,length,&bytesread,NULL);
|
||||||
|
int loop = 192;
|
||||||
|
while (loop--)
|
||||||
|
*(memdirty+loop) = 0xFF;
|
||||||
|
regs.pc = address;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
DWORD PrgDetect (LPBYTE imageptr, DWORD imagesize) {
|
||||||
|
return (*(LPDWORD)imageptr == 0x214C470A) ? 2 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE -----
|
||||||
|
//
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BOOL ImageBoot (HIMAGE imagehandle) {
|
||||||
|
imageinfoptr ptr = (imageinfoptr)imagehandle;
|
||||||
|
BOOL result = 0;
|
||||||
|
if (imagetype[ptr->format].boot)
|
||||||
|
result = imagetype[ptr->format].boot(ptr);
|
||||||
|
if (result)
|
||||||
|
ptr->writeprotected = 1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void ImageClose (HIMAGE imagehandle) {
|
||||||
|
imageinfoptr ptr = (imageinfoptr)imagehandle;
|
||||||
|
if (ptr->file != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle(ptr->file);
|
||||||
|
for (int track = 0; track < TRACKS; track++)
|
||||||
|
if (!ptr->validtrack[track]) {
|
||||||
|
DeleteFile(ptr->filename);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ptr->header)
|
||||||
|
VirtualFree(ptr->header,0,MEM_RELEASE);
|
||||||
|
VirtualFree(ptr,0,MEM_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void ImageDestroy () {
|
||||||
|
VirtualFree(workbuffer,0,MEM_RELEASE);
|
||||||
|
workbuffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void ImageInitialize () {
|
||||||
|
workbuffer = (LPBYTE)VirtualAlloc(NULL,0x2000,MEM_COMMIT,PAGE_READWRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
int ImageOpen (LPCTSTR imagefilename,
|
||||||
|
HIMAGE *imagehandle,
|
||||||
|
BOOL *writeprotected,
|
||||||
|
BOOL createifnecessary) {
|
||||||
|
if (!(imagefilename && imagehandle && writeprotected && workbuffer))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// TRY TO OPEN THE IMAGE FILE
|
||||||
|
HANDLE file = INVALID_HANDLE_VALUE;
|
||||||
|
if (!*writeprotected)
|
||||||
|
file = CreateFile(imagefilename,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
(LPSECURITY_ATTRIBUTES)NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL);
|
||||||
|
if (file == INVALID_HANDLE_VALUE) {
|
||||||
|
file = CreateFile(imagefilename,
|
||||||
|
GENERIC_READ,
|
||||||
|
FILE_SHARE_READ,
|
||||||
|
(LPSECURITY_ATTRIBUTES)NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL);
|
||||||
|
if (file != INVALID_HANDLE_VALUE)
|
||||||
|
*writeprotected = 1;
|
||||||
|
}
|
||||||
|
if ((file == INVALID_HANDLE_VALUE) && createifnecessary)
|
||||||
|
file = CreateFile(imagefilename,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
(LPSECURITY_ATTRIBUTES)NULL,
|
||||||
|
CREATE_NEW,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
// IF WE AREN'T ABLE TO OPEN THE FILE, RETURN
|
||||||
|
if (file == INVALID_HANDLE_VALUE)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// DETERMINE THE FILE'S EXTENSION AND CONVERT IT TO LOWERCASE
|
||||||
|
LPCTSTR imagefileext = imagefilename;
|
||||||
|
if (_tcsrchr(imagefileext,TEXT('\\')))
|
||||||
|
imagefileext = _tcsrchr(imagefileext,TEXT('\\'))+1;
|
||||||
|
if (_tcsrchr(imagefileext,TEXT('.')))
|
||||||
|
imagefileext = _tcsrchr(imagefileext,TEXT('.'));
|
||||||
|
TCHAR ext[_MAX_EXT];
|
||||||
|
_tcsncpy(ext,imagefileext,_MAX_EXT);
|
||||||
|
CharLowerBuff(ext,_tcslen(ext));
|
||||||
|
|
||||||
|
DWORD size = GetFileSize(file,NULL);
|
||||||
|
LPBYTE view = NULL;
|
||||||
|
LPBYTE imageptr = NULL;
|
||||||
|
DWORD format = 0xFFFFFFFF;
|
||||||
|
if (size > 0) {
|
||||||
|
|
||||||
|
// MAP THE FILE INTO MEMORY FOR USE BY THE DETECTION FUNCTIONS
|
||||||
|
HANDLE mapping = CreateFileMapping(file,
|
||||||
|
(LPSECURITY_ATTRIBUTES)NULL,
|
||||||
|
PAGE_READONLY,
|
||||||
|
0,0,NULL);
|
||||||
|
view = (LPBYTE)MapViewOfFile(mapping,FILE_MAP_READ,0,0,0);
|
||||||
|
imageptr = view;
|
||||||
|
if (imageptr) {
|
||||||
|
|
||||||
|
// DETERMINE WHETHER THE FILE HAS A 128-BYTE MACBINARY HEADER
|
||||||
|
if ((size > 128) &&
|
||||||
|
(!*imageptr) &&
|
||||||
|
(*(imageptr+1) < 120) &&
|
||||||
|
(!*(imageptr+*(imageptr+1)+2)) &&
|
||||||
|
(*(imageptr+0x7A) == 0x81) &&
|
||||||
|
(*(imageptr+0x7B) == 0x81)) {
|
||||||
|
imageptr += 128;
|
||||||
|
size -= 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CALL THE DETECTION FUNCTIONS IN ORDER, LOOKING FOR A MATCH
|
||||||
|
DWORD possibleformat = 0xFFFFFFFF;
|
||||||
|
int loop = 0;
|
||||||
|
while ((loop < IMAGETYPES) && (format == 0xFFFFFFFF)) {
|
||||||
|
if (*ext && _tcsstr(imagetype[loop].rejectexts,ext))
|
||||||
|
++loop;
|
||||||
|
else {
|
||||||
|
DWORD result = imagetype[loop].detect(imageptr,size);
|
||||||
|
if (result == 2)
|
||||||
|
format = loop;
|
||||||
|
else if ((result == 1) && (possibleformat == 0xFFFFFFFF))
|
||||||
|
possibleformat = loop++;
|
||||||
|
else
|
||||||
|
++loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (format == 0xFFFFFFFF)
|
||||||
|
format = possibleformat;
|
||||||
|
|
||||||
|
// CLOSE THE MEMORY MAPPING
|
||||||
|
UnmapViewOfFile(view);
|
||||||
|
}
|
||||||
|
CloseHandle(mapping);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
// WE CREATE ONLY DOS ORDER (DO) OR 6656-NIBBLE (NIB) FORMAT FILES
|
||||||
|
for (int loop = 1; loop <= 4; loop += 3)
|
||||||
|
if (*ext && _tcsstr(imagetype[loop].createexts,ext)) {
|
||||||
|
format = loop;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IF THE FILE DOES MATCH A KNOWN FORMAT...
|
||||||
|
if (format != 0xFFFFFFFF) {
|
||||||
|
|
||||||
|
// CREATE A RECORD FOR THE FILE, AND RETURN AN IMAGE HANDLE
|
||||||
|
*imagehandle = (HIMAGE)VirtualAlloc(NULL,sizeof(imageinforec),MEM_COMMIT,PAGE_READWRITE);
|
||||||
|
if (*imagehandle) {
|
||||||
|
ZeroMemory(*imagehandle,sizeof(imageinforec));
|
||||||
|
_tcsncpy(((imageinfoptr)*imagehandle)->filename,imagefilename,MAX_PATH);
|
||||||
|
((imageinfoptr)*imagehandle)->format = format;
|
||||||
|
((imageinfoptr)*imagehandle)->file = file;
|
||||||
|
((imageinfoptr)*imagehandle)->offset = imageptr-view;
|
||||||
|
((imageinfoptr)*imagehandle)->writeprotected = *writeprotected;
|
||||||
|
for (int track = 0; track < TRACKS; track++)
|
||||||
|
((imageinfoptr)*imagehandle)->validtrack[track] = (size > 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(file);
|
||||||
|
if (!(size > 0))
|
||||||
|
DeleteFile(imagefilename);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void ImageReadTrack (HIMAGE imagehandle,
|
||||||
|
int track,
|
||||||
|
int quartertrack,
|
||||||
|
LPBYTE trackimagebuffer,
|
||||||
|
int *nibbles) {
|
||||||
|
imageinfoptr ptr = (imageinfoptr)imagehandle;
|
||||||
|
if (imagetype[ptr->format].read && ptr->validtrack[track])
|
||||||
|
imagetype[ptr->format].read(ptr,track,quartertrack,trackimagebuffer,nibbles);
|
||||||
|
else
|
||||||
|
for (*nibbles = 0; *nibbles < NIBBLES; (*nibbles)++)
|
||||||
|
trackimagebuffer[*nibbles] = (BYTE)(rand() & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void ImageWriteTrack (HIMAGE imagehandle,
|
||||||
|
int track,
|
||||||
|
int quartertrack,
|
||||||
|
LPBYTE trackimage,
|
||||||
|
int nibbles) {
|
||||||
|
imageinfoptr ptr = (imageinfoptr)imagehandle;
|
||||||
|
if (imagetype[ptr->format].write && !ptr->writeprotected) {
|
||||||
|
imagetype[ptr->format].write(ptr,track,quartertrack,trackimage,nibbles);
|
||||||
|
ptr->validtrack[track] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define TRACKS 35
|
||||||
|
#define IMAGETYPES 7
|
||||||
|
#define NIBBLES 6656
|
||||||
|
|
||||||
|
BOOL ImageBoot (HIMAGE);
|
||||||
|
void ImageClose (HIMAGE);
|
||||||
|
void ImageDestroy ();
|
||||||
|
void ImageInitialize ();
|
||||||
|
int ImageOpen (LPCTSTR,HIMAGE *,BOOL *,BOOL);
|
||||||
|
void ImageReadTrack (HIMAGE,int,int,LPBYTE,int *);
|
||||||
|
void ImageWriteTrack (HIMAGE,int,int,LPBYTE,int);
|
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum {NOT_ASCII=0, ASCII};
|
||||||
|
|
||||||
|
extern HWND framewindow;
|
||||||
|
extern BOOL fullscreen;
|
||||||
|
|
||||||
|
void FrameCreateWindow ();
|
||||||
|
HDC FrameGetDC ();
|
||||||
|
HDC FrameGetVideoDC (LPBYTE *,LONG *);
|
||||||
|
void FrameRefreshStatus (int);
|
||||||
|
void FrameRegisterClass ();
|
||||||
|
void FrameReleaseDC ();
|
||||||
|
void FrameReleaseVideoDC ();
|
|
@ -0,0 +1,567 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, Michael O'Brien
|
||||||
|
Copyright (C) 1999-2001, Oliver Schmidt
|
||||||
|
Copyright (C) 2002-2005, Tom Charlesworth
|
||||||
|
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: Hard drive emulation
|
||||||
|
*
|
||||||
|
* Author: Copyright (c) 2005, Robert Hoem
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
#include "..\resource\resource.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Memory map:
|
||||||
|
|
||||||
|
C0F0 (r) EXECUTE AND RETURN STATUS
|
||||||
|
C0F1 (r) STATUS (or ERROR)
|
||||||
|
C0F2 (r/w) COMMAND
|
||||||
|
C0F3 (r/w) UNIT NUMBER
|
||||||
|
C0F4 (r/w) LOW BYTE OF MEMORY BUFFER
|
||||||
|
C0F5 (r/w) HIGH BYTE OF MEMORY BUFFER
|
||||||
|
C0F6 (r/w) LOW BYTE OF BLOCK NUMBER
|
||||||
|
C0F7 (r/w) HIGH BYTE OF BLOCK NUMBER
|
||||||
|
C0F8 (r) NEXT BYTE
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Hard drive emulation in Applewin.
|
||||||
|
|
||||||
|
Concept
|
||||||
|
To emulate a 32mb hard drive connected to an Apple IIe via Applewin.
|
||||||
|
Designed to work with Autoboot Rom and Prodos.
|
||||||
|
|
||||||
|
Overview
|
||||||
|
1. Hard drive image file
|
||||||
|
The hard drive image file (.HDV) will be formatted into blocks of 512
|
||||||
|
bytes, in a linear fashion. The internal formatting and meaning of each
|
||||||
|
block to be decided by the Apple's operating system (ProDos). To create
|
||||||
|
an empty .HDV file, just create a 0 byte file (I prefer the debug method).
|
||||||
|
|
||||||
|
2. Emulation code
|
||||||
|
There are 4 commands Prodos will send to a block device.
|
||||||
|
Listed below are each command and how it's handled:
|
||||||
|
|
||||||
|
1. STATUS
|
||||||
|
In the emulation's case, returns only a DEVICE OK (0) or DEVICE I/O ERROR (8).
|
||||||
|
DEVICE I/O ERROR only returned if no HDV file is selected.
|
||||||
|
|
||||||
|
2. READ
|
||||||
|
Loads requested block into a 512 byte buffer by attempting to seek to
|
||||||
|
location in HDV file.
|
||||||
|
If seek fails, returns a DEVICE I/O ERROR. Resets hd_buf_ptr used by HD_NEXTBYTE
|
||||||
|
Returns a DEVICE OK if read was successful, or a DEVICE I/O ERROR otherwise.
|
||||||
|
|
||||||
|
3. WRITE
|
||||||
|
Copies requested block from the Apple's memory to a 512 byte buffer
|
||||||
|
then attempts to seek to requested block.
|
||||||
|
If the seek fails (usually because the seek is beyond the EOF for the
|
||||||
|
HDV file), the Emulation will attempt to "grow" the HDV file to accomodate.
|
||||||
|
Once the file can accomodate, or if the seek did not fail, the buffer is
|
||||||
|
written to the HDV file. NOTE: A2PC will grow *AND* shrink the HDV file.
|
||||||
|
I didn't see the point in shrinking the file as this behaviour would require
|
||||||
|
patching prodos (to detect DELETE FILE calls).
|
||||||
|
|
||||||
|
4. FORMAT
|
||||||
|
Ignored. This would be used for low level formatting of the device
|
||||||
|
(as in the case of a tape or SCSI drive, perhaps).
|
||||||
|
|
||||||
|
3. Bugs
|
||||||
|
The only thing I've noticed is that Copy II+ 7.1 seems to crash or stall
|
||||||
|
occasionally when trying to calculate how many free block are available
|
||||||
|
when running a catalog. This might be due to the great number of blocks
|
||||||
|
available. Also, DDD pro will not optimise the disk correctally (it's
|
||||||
|
doing a disk defragment of some sort, and when it requests a block outside
|
||||||
|
the range of the image file, it starts getting I/O errors), so don't
|
||||||
|
bother. Any program that preforms a read before write to an "unwritten"
|
||||||
|
block (a block that should be located beyond the EOF of the .HDV, which is
|
||||||
|
valid for writing but not for reading until written to) will fail with I/O
|
||||||
|
errors (although these are few and far between).
|
||||||
|
|
||||||
|
I'm sure there are programs out there that may try to use the I/O ports in
|
||||||
|
ways they weren't designed (like telling Ultima 5 that you have a Phazor
|
||||||
|
sound card in slot 7 is a generally bad idea) will cause problems.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
TCHAR hd_imagename[16];
|
||||||
|
TCHAR hd_fullname[128];
|
||||||
|
BYTE hd_error;
|
||||||
|
WORD hd_memblock;
|
||||||
|
WORD hd_diskblock;
|
||||||
|
WORD hd_buf_ptr;
|
||||||
|
BOOL hd_imageloaded;
|
||||||
|
HANDLE hd_file;
|
||||||
|
BYTE hd_buf[513];
|
||||||
|
} HDD, *PHDD;
|
||||||
|
|
||||||
|
static bool g_bHD_RomLoaded = false;
|
||||||
|
static bool g_bHD_Enabled = false;
|
||||||
|
|
||||||
|
static BYTE g_nHD_UnitNum = DRIVE_1;
|
||||||
|
|
||||||
|
// The HDD interface has a single Command register for both drives:
|
||||||
|
// . ProDOS will write to Command before switching drives
|
||||||
|
static BYTE g_nHD_Command;
|
||||||
|
|
||||||
|
static HDD g_HardDrive[2] = {0};
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
static void GetImageTitle (LPCTSTR imagefilename, PHDD pHardDrive)
|
||||||
|
{
|
||||||
|
TCHAR imagetitle[128];
|
||||||
|
LPCTSTR startpos = imagefilename;
|
||||||
|
|
||||||
|
// imagetitle = <FILENAME.EXT>
|
||||||
|
if (_tcsrchr(startpos,TEXT('\\')))
|
||||||
|
startpos = _tcsrchr(startpos,TEXT('\\'))+1;
|
||||||
|
_tcsncpy(imagetitle,startpos,127);
|
||||||
|
imagetitle[127] = 0;
|
||||||
|
|
||||||
|
// if imagetitle contains a lowercase char, then found=1 (why?)
|
||||||
|
BOOL found = 0;
|
||||||
|
int loop = 0;
|
||||||
|
while (imagetitle[loop] && !found)
|
||||||
|
{
|
||||||
|
if (IsCharLower(imagetitle[loop]))
|
||||||
|
found = 1;
|
||||||
|
else
|
||||||
|
loop++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!found) && (loop > 2))
|
||||||
|
CharLowerBuff(imagetitle+1,_tcslen(imagetitle+1));
|
||||||
|
|
||||||
|
// fptr->fullname = <FILENAME.EXT>
|
||||||
|
_tcsncpy(pHardDrive->hd_fullname,imagetitle,127);
|
||||||
|
pHardDrive->hd_fullname[127] = 0;
|
||||||
|
|
||||||
|
if (imagetitle[0])
|
||||||
|
{
|
||||||
|
LPTSTR dot = imagetitle;
|
||||||
|
if (_tcsrchr(dot,TEXT('.')))
|
||||||
|
dot = _tcsrchr(dot,TEXT('.'));
|
||||||
|
if (dot > imagetitle)
|
||||||
|
*dot = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fptr->imagename = <FILENAME> (ie. no extension)
|
||||||
|
_tcsncpy(pHardDrive->hd_imagename,imagetitle,15);
|
||||||
|
pHardDrive->hd_imagename[15] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void NotifyInvalidImage (TCHAR* filename)
|
||||||
|
{
|
||||||
|
// TC: TO DO
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HD_CleanupDrive(int nDrive)
|
||||||
|
{
|
||||||
|
CloseHandle(g_HardDrive[nDrive].hd_file);
|
||||||
|
g_HardDrive[nDrive].hd_imageloaded = false;
|
||||||
|
g_HardDrive[nDrive].hd_imagename[0] = 0;
|
||||||
|
g_HardDrive[nDrive].hd_fullname[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL HD_Load_Image(int nDrive, LPCSTR filename)
|
||||||
|
{
|
||||||
|
g_HardDrive[nDrive].hd_file = CreateFile(filename,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ,
|
||||||
|
(LPSECURITY_ATTRIBUTES)NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (g_HardDrive[nDrive].hd_file == INVALID_HANDLE_VALUE)
|
||||||
|
g_HardDrive[nDrive].hd_imageloaded = false;
|
||||||
|
else
|
||||||
|
g_HardDrive[nDrive].hd_imageloaded = true;
|
||||||
|
|
||||||
|
return g_HardDrive[nDrive].hd_imageloaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
static LPCTSTR HD_DiskGetName (int nDrive)
|
||||||
|
{
|
||||||
|
return g_HardDrive[nDrive].hd_imagename;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
// everything below is global
|
||||||
|
|
||||||
|
static const DWORD HDDRVR_SIZE = 0x100;
|
||||||
|
static LPBYTE lpMemC000 = NULL;
|
||||||
|
|
||||||
|
bool HD_CardIsEnabled()
|
||||||
|
{
|
||||||
|
return g_bHD_RomLoaded && g_bHD_Enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HD_SetEnabled(bool bEnabled)
|
||||||
|
{
|
||||||
|
if(g_bHD_Enabled == bEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_bHD_Enabled = bEnabled;
|
||||||
|
|
||||||
|
if(lpMemC000 == NULL) // This will be NULL when called after loading value from Registry
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(g_bHD_Enabled)
|
||||||
|
HD_Load_Rom(lpMemC000);
|
||||||
|
else
|
||||||
|
memset(lpMemC000+0x700, 0, HDDRVR_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
LPCTSTR HD_GetFullName (int nDrive)
|
||||||
|
{
|
||||||
|
return g_HardDrive[nDrive].hd_fullname;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID HD_Load_Rom(LPBYTE lpMemRom)
|
||||||
|
{
|
||||||
|
lpMemC000 = lpMemRom; // Keep a copy for HD_SetEnabled()
|
||||||
|
|
||||||
|
if(!g_bHD_Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_HDDRVR), RT_RCDATA);
|
||||||
|
if(hResInfo == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DWORD dwResSize = SizeofResource(NULL, hResInfo);
|
||||||
|
if(dwResSize != HDDRVR_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;
|
||||||
|
|
||||||
|
memcpy(lpMemRom+0x700, pData, HDDRVR_SIZE);
|
||||||
|
g_bHD_RomLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID HD_Cleanup()
|
||||||
|
{
|
||||||
|
for(int i=DRIVE_1; i<DRIVE_2; i++)
|
||||||
|
{
|
||||||
|
HD_CleanupDrive(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pszFilename is not qualified with path
|
||||||
|
BOOL HD_InsertDisk2(int nDrive, LPCTSTR pszFilename)
|
||||||
|
{
|
||||||
|
if (*pszFilename == 0x00)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char szFullFilename[MAX_PATH];
|
||||||
|
|
||||||
|
RegLoadString(TEXT("Preferences"),TEXT("HDV Starting Directory"), 1, szFullFilename, MAX_PATH);
|
||||||
|
strcat(szFullFilename, pszFilename);
|
||||||
|
|
||||||
|
return HD_InsertDisk(nDrive, szFullFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// imagefilename is qualified with path
|
||||||
|
BOOL HD_InsertDisk(int nDrive, LPCTSTR imagefilename)
|
||||||
|
{
|
||||||
|
if (*imagefilename == 0x00)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (g_HardDrive[nDrive].hd_imageloaded)
|
||||||
|
HD_CleanupDrive(nDrive);
|
||||||
|
|
||||||
|
BOOL result = HD_Load_Image(nDrive, imagefilename);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
GetImageTitle(imagefilename, &g_HardDrive[nDrive]);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HD_Select(int nDrive)
|
||||||
|
{
|
||||||
|
TCHAR directory[MAX_PATH] = TEXT("");
|
||||||
|
TCHAR filename[MAX_PATH] = TEXT("");
|
||||||
|
TCHAR title[40];
|
||||||
|
|
||||||
|
RegLoadString(TEXT("Preferences"),TEXT("HDV Starting Directory"),1,directory,MAX_PATH);
|
||||||
|
_tcscpy(title,TEXT("Select HDV Image For HDD "));
|
||||||
|
_tcscat(title,nDrive ? TEXT("2") : TEXT("1"));
|
||||||
|
|
||||||
|
OPENFILENAME ofn;
|
||||||
|
ZeroMemory(&ofn,sizeof(OPENFILENAME));
|
||||||
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
||||||
|
ofn.hwndOwner = framewindow;
|
||||||
|
ofn.hInstance = instance;
|
||||||
|
ofn.lpstrFilter = TEXT("Hard Disk Images (*.hdv)\0*.hdv\0");
|
||||||
|
ofn.lpstrFile = filename;
|
||||||
|
ofn.nMaxFile = MAX_PATH;
|
||||||
|
ofn.lpstrInitialDir = directory;
|
||||||
|
ofn.Flags = OFN_CREATEPROMPT | OFN_HIDEREADONLY;
|
||||||
|
ofn.lpstrTitle = title;
|
||||||
|
ofn.lpTemplateName = TEXT("INSERT_DIALOG");
|
||||||
|
|
||||||
|
if (GetOpenFileName(&ofn))
|
||||||
|
{
|
||||||
|
if ((!ofn.nFileExtension) || !filename[ofn.nFileExtension])
|
||||||
|
_tcscat(filename,TEXT(".hdv"));
|
||||||
|
|
||||||
|
if (HD_InsertDisk(nDrive, filename))
|
||||||
|
{
|
||||||
|
filename[ofn.nFileOffset] = 0;
|
||||||
|
if (_tcsicmp(directory,filename))
|
||||||
|
RegSaveString(TEXT("Preferences"),TEXT("HDV Starting Directory"),1,filename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NotifyInvalidImage(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define DEVICE_OK 0x00
|
||||||
|
#define DEVICE_UNKNOWN_ERROR 0x03
|
||||||
|
#define DEVICE_IO_ERROR 0x08
|
||||||
|
|
||||||
|
BYTE __stdcall HD_IO_EMUL (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft)
|
||||||
|
{
|
||||||
|
BYTE r = DEVICE_OK;
|
||||||
|
|
||||||
|
if (!HD_CardIsEnabled())
|
||||||
|
return r;
|
||||||
|
|
||||||
|
PHDD pHDD = &g_HardDrive[g_nHD_UnitNum >> 7]; // bit7 = drive select
|
||||||
|
|
||||||
|
if (bWrite == 0) // read
|
||||||
|
{
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0xF0:
|
||||||
|
{
|
||||||
|
if (pHDD->hd_imageloaded)
|
||||||
|
{
|
||||||
|
// based on loaded data block request, load block into memory
|
||||||
|
// returns status
|
||||||
|
switch (g_nHD_Command)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case 0x00: //status
|
||||||
|
if (GetFileSize(pHDD->hd_file,NULL) == 0)
|
||||||
|
{
|
||||||
|
pHDD->hd_error = 1;
|
||||||
|
r = DEVICE_IO_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x01: //read
|
||||||
|
{
|
||||||
|
DWORD br = GetFileSize(pHDD->hd_file,NULL);
|
||||||
|
if ((DWORD)(pHDD->hd_diskblock * 512) <= br) // seek to block
|
||||||
|
{
|
||||||
|
SetFilePointer(pHDD->hd_file,pHDD->hd_diskblock * 512,NULL,FILE_BEGIN); // seek to block
|
||||||
|
if (ReadFile(pHDD->hd_file,pHDD->hd_buf,512,&br,NULL)) // read block into buffer
|
||||||
|
{
|
||||||
|
pHDD->hd_error = 0;
|
||||||
|
r = 0;
|
||||||
|
pHDD->hd_buf_ptr = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pHDD->hd_error = 1;
|
||||||
|
r = DEVICE_IO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pHDD->hd_error = 1;
|
||||||
|
r = DEVICE_IO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x02: //write
|
||||||
|
{
|
||||||
|
DWORD bw = GetFileSize(pHDD->hd_file,NULL);
|
||||||
|
if ((DWORD)(pHDD->hd_diskblock * 512) <= bw)
|
||||||
|
{
|
||||||
|
MoveMemory(pHDD->hd_buf,mem+pHDD->hd_memblock,512);
|
||||||
|
SetFilePointer(pHDD->hd_file,pHDD->hd_diskblock * 512,NULL,FILE_BEGIN); // seek to block
|
||||||
|
if (WriteFile(pHDD->hd_file,pHDD->hd_buf,512,&bw,NULL)) // write buffer to file
|
||||||
|
{
|
||||||
|
pHDD->hd_error = 0;
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pHDD->hd_error = 1;
|
||||||
|
r = DEVICE_IO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD fsize = SetFilePointer(pHDD->hd_file,0,NULL,FILE_END);
|
||||||
|
DWORD addblocks = pHDD->hd_diskblock - (fsize / 512);
|
||||||
|
FillMemory(pHDD->hd_buf,512,0);
|
||||||
|
while (addblocks--)
|
||||||
|
{
|
||||||
|
DWORD bw;
|
||||||
|
WriteFile(pHDD->hd_file,pHDD->hd_buf,512,&bw,NULL);
|
||||||
|
}
|
||||||
|
if (SetFilePointer(pHDD->hd_file,pHDD->hd_diskblock * 512,NULL,FILE_BEGIN) != 0xFFFFFFFF) { // seek to block
|
||||||
|
MoveMemory(pHDD->hd_buf,mem+pHDD->hd_memblock,512);
|
||||||
|
if (WriteFile(pHDD->hd_file,pHDD->hd_buf,512,&bw,NULL)) // write buffer to file
|
||||||
|
{
|
||||||
|
pHDD->hd_error = 0;
|
||||||
|
r = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pHDD->hd_error = 1;
|
||||||
|
r = DEVICE_IO_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x03: //format
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pHDD->hd_error = 1;
|
||||||
|
r = DEVICE_UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF1: // hd_error
|
||||||
|
{
|
||||||
|
r = pHDD->hd_error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF2:
|
||||||
|
{
|
||||||
|
r = g_nHD_Command;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF3:
|
||||||
|
{
|
||||||
|
r = g_nHD_UnitNum;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF4:
|
||||||
|
{
|
||||||
|
r = (BYTE)(pHDD->hd_memblock & 0x00FF);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF5:
|
||||||
|
{
|
||||||
|
r = (BYTE)(pHDD->hd_memblock & 0xFF00 >> 8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF6:
|
||||||
|
{
|
||||||
|
r = (BYTE)(pHDD->hd_diskblock & 0x00FF);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF7:
|
||||||
|
{
|
||||||
|
r = (BYTE)(pHDD->hd_diskblock & 0xFF00 >> 8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF8:
|
||||||
|
{
|
||||||
|
r = pHDD->hd_buf[pHDD->hd_buf_ptr];
|
||||||
|
pHDD->hd_buf_ptr++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // write
|
||||||
|
{
|
||||||
|
switch (addr)
|
||||||
|
{
|
||||||
|
case 0xF2:
|
||||||
|
{
|
||||||
|
g_nHD_Command = d;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF3:
|
||||||
|
{
|
||||||
|
// b7 = drive#
|
||||||
|
// b6..4 = slot#
|
||||||
|
// b3..0 = ?
|
||||||
|
g_nHD_UnitNum = d;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF4:
|
||||||
|
{
|
||||||
|
pHDD->hd_memblock = pHDD->hd_memblock & 0xFF00 | d;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF5:
|
||||||
|
{
|
||||||
|
pHDD->hd_memblock = pHDD->hd_memblock & 0x00FF | (d << 8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF6:
|
||||||
|
{
|
||||||
|
pHDD->hd_diskblock = pHDD->hd_diskblock & 0xFF00 | d;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xF7:
|
||||||
|
{
|
||||||
|
pHDD->hd_diskblock = pHDD->hd_diskblock & 0x00FF | (d << 8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
bool HD_CardIsEnabled();
|
||||||
|
void HD_SetEnabled(bool bEnabled);
|
||||||
|
LPCTSTR HD_GetFullName (int drive);
|
||||||
|
VOID HD_Load_Rom(LPBYTE lpMemRom);
|
||||||
|
VOID HD_Cleanup();
|
||||||
|
BOOL HD_InsertDisk2(int nDrive, LPCTSTR pszFilename);
|
||||||
|
BOOL HD_InsertDisk(int nDrive, LPCTSTR imagefilename);
|
||||||
|
void HD_Select(int nDrive);
|
||||||
|
|
||||||
|
BYTE __stdcall HD_IO_EMUL (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
|
@ -0,0 +1,591 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, Michael O'Brien
|
||||||
|
Copyright (C) 1999-2001, Oliver Schmidt
|
||||||
|
Copyright (C) 2002-2005, Tom Charlesworth
|
||||||
|
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: Joystick emulation via keyboard, PC joystick or mouse
|
||||||
|
*
|
||||||
|
* Author: Various
|
||||||
|
*/
|
||||||
|
|
||||||
|
// TC: Extended for 2nd joystick:
|
||||||
|
// Apple joystick #0 can be emulated with: NONE, JOYSTICKID1, KEYBOARD, MOUSE
|
||||||
|
// Apple joystick #1 can be emulated with: NONE, JOYSTICKID2, KEYBOARD, MOUSE
|
||||||
|
// If Apple joystick #0 is using {KEYBOARD | MOUSE} then joystick #1 can't use it.
|
||||||
|
// If Apple joystick #1 is using KEYBOARD, then disable the standard keys that control Apple switches #0/#1.
|
||||||
|
// - So that in a 2 player game, player 2 can't cheat by controlling player 1's buttons.
|
||||||
|
// If Apple joystick #1 is not NONE, then Apple joystick #0 only gets the use of Apple switch #0.
|
||||||
|
// - When using 2 joysticks, button #1 is used by joystick #1 (Archon).
|
||||||
|
// Apple joystick #1's button now controls Apple switches #1 and #2.
|
||||||
|
// - This is because the 2-joystick version of Mario Bros expects the 2nd joystick to control Apple switch #2.
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
|
||||||
|
#define BUTTONTIME 5000
|
||||||
|
|
||||||
|
#define DEVICE_NONE 0
|
||||||
|
#define DEVICE_JOYSTICK 1
|
||||||
|
#define DEVICE_KEYBOARD 2
|
||||||
|
#define DEVICE_MOUSE 3
|
||||||
|
|
||||||
|
#define MODE_NONE 0
|
||||||
|
#define MODE_STANDARD 1
|
||||||
|
#define MODE_CENTERING 2
|
||||||
|
#define MODE_SMOOTH 3
|
||||||
|
|
||||||
|
typedef struct _joyinforec {
|
||||||
|
int device;
|
||||||
|
int mode;
|
||||||
|
} joyinforec, *joyinfoptr;
|
||||||
|
|
||||||
|
static const joyinforec joyinfo[5] = {{DEVICE_NONE,MODE_NONE},
|
||||||
|
{DEVICE_JOYSTICK,MODE_STANDARD},
|
||||||
|
{DEVICE_KEYBOARD,MODE_STANDARD},
|
||||||
|
{DEVICE_KEYBOARD,MODE_CENTERING},
|
||||||
|
{DEVICE_MOUSE,MODE_STANDARD}};
|
||||||
|
|
||||||
|
// Key pad [1..9]; Key pad 0,Key pad '.'; Left ALT,Right ALT
|
||||||
|
enum JOYKEY { JK_DOWNLEFT=0,
|
||||||
|
JK_DOWN,
|
||||||
|
JK_DOWNRIGHT,
|
||||||
|
JK_LEFT,
|
||||||
|
JK_CENTRE,
|
||||||
|
JK_RIGHT,
|
||||||
|
JK_UPLEFT,
|
||||||
|
JK_UP,
|
||||||
|
JK_UPRIGHT,
|
||||||
|
JK_BUTTON0,
|
||||||
|
JK_BUTTON1,
|
||||||
|
JK_OPENAPPLE,
|
||||||
|
JK_CLOSEDAPPLE,
|
||||||
|
JK_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
const UINT PDL_MIN = 0;
|
||||||
|
const UINT PDL_CENTRAL = 127;
|
||||||
|
const UINT PDL_MAX = 255;
|
||||||
|
|
||||||
|
static BOOL keydown[JK_MAX] = {FALSE};
|
||||||
|
static POINT keyvalue[9] = {{PDL_MIN,PDL_MAX}, {PDL_CENTRAL,PDL_MAX}, {PDL_MAX,PDL_MAX},
|
||||||
|
{PDL_MIN,PDL_CENTRAL},{PDL_CENTRAL,PDL_CENTRAL},{PDL_MAX,PDL_CENTRAL},
|
||||||
|
{PDL_MIN,PDL_MIN}, {PDL_CENTRAL,PDL_MIN}, {PDL_MAX,PDL_MIN}};
|
||||||
|
|
||||||
|
static DWORD buttonlatch[3] = {0,0,0};
|
||||||
|
static BOOL joybutton[3] = {0,0,0};
|
||||||
|
|
||||||
|
static int joyshrx[2] = {8,8};
|
||||||
|
static int joyshry[2] = {8,8};
|
||||||
|
static int joysubx[2] = {0,0};
|
||||||
|
static int joysuby[2] = {0,0};
|
||||||
|
|
||||||
|
DWORD joytype[2] = {DEVICE_JOYSTICK,DEVICE_NONE}; // Emulation Type for joysticks #0 & #1
|
||||||
|
|
||||||
|
static BOOL setbutton[3] = {0,0,0}; // Used when a mouse button is pressed/released
|
||||||
|
|
||||||
|
static int xpos[2] = {PDL_CENTRAL,PDL_CENTRAL};
|
||||||
|
static int ypos[2] = {PDL_CENTRAL,PDL_CENTRAL};
|
||||||
|
|
||||||
|
static unsigned __int64 g_nJoyCntrResetCycle = 0; // Abs cycle that joystick counters were reset
|
||||||
|
|
||||||
|
static short g_nPdlTrimX = 0;
|
||||||
|
static short g_nPdlTrimY = 0;
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CheckJoystick0 ()
|
||||||
|
{
|
||||||
|
static DWORD lastcheck = 0;
|
||||||
|
DWORD currtime = GetTickCount();
|
||||||
|
if ((currtime-lastcheck >= 10) || joybutton[0] || joybutton[1])
|
||||||
|
{
|
||||||
|
lastcheck = currtime;
|
||||||
|
JOYINFO info;
|
||||||
|
if (joyGetPos(JOYSTICKID1,&info) == JOYERR_NOERROR)
|
||||||
|
{
|
||||||
|
if ((info.wButtons & JOY_BUTTON1) && !joybutton[0])
|
||||||
|
buttonlatch[0] = BUTTONTIME;
|
||||||
|
if ((info.wButtons & JOY_BUTTON2) && !joybutton[1] &&
|
||||||
|
(joyinfo[joytype[1]].device == DEVICE_NONE) // Only consider 2nd button if NOT emulating a 2nd Apple joystick
|
||||||
|
)
|
||||||
|
buttonlatch[1] = BUTTONTIME;
|
||||||
|
joybutton[0] = ((info.wButtons & JOY_BUTTON1) != 0);
|
||||||
|
if (joyinfo[joytype[1]].device == DEVICE_NONE) // Only consider 2nd button if NOT emulating a 2nd Apple joystick
|
||||||
|
joybutton[1] = ((info.wButtons & JOY_BUTTON2) != 0);
|
||||||
|
|
||||||
|
xpos[0] = (info.wXpos-joysubx[0]) >> joyshrx[0];
|
||||||
|
ypos[0] = (info.wYpos-joysuby[0]) >> joyshry[0];
|
||||||
|
|
||||||
|
// NB. This does not work for analogue joysticks (not self-centreing) - except if Trim=0
|
||||||
|
if(xpos[0] == 127 || xpos[0] == 128) xpos[0] += g_nPdlTrimX;
|
||||||
|
if(ypos[0] == 127 || ypos[0] == 128) ypos[0] += g_nPdlTrimY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckJoystick1 ()
|
||||||
|
{
|
||||||
|
static DWORD lastcheck = 0;
|
||||||
|
DWORD currtime = GetTickCount();
|
||||||
|
if ((currtime-lastcheck >= 10) || joybutton[2])
|
||||||
|
{
|
||||||
|
lastcheck = currtime;
|
||||||
|
JOYINFO info;
|
||||||
|
if (joyGetPos(JOYSTICKID2,&info) == JOYERR_NOERROR)
|
||||||
|
{
|
||||||
|
if ((info.wButtons & JOY_BUTTON1) && !joybutton[2])
|
||||||
|
{
|
||||||
|
buttonlatch[2] = BUTTONTIME;
|
||||||
|
if(joyinfo[joytype[1]].device != DEVICE_NONE)
|
||||||
|
buttonlatch[1] = BUTTONTIME; // Re-map this button when emulating a 2nd Apple joystick
|
||||||
|
}
|
||||||
|
|
||||||
|
joybutton[2] = ((info.wButtons & JOY_BUTTON1) != 0);
|
||||||
|
if(joyinfo[joytype[1]].device != DEVICE_NONE)
|
||||||
|
joybutton[1] = ((info.wButtons & JOY_BUTTON1) != 0); // Re-map this button when emulating a 2nd Apple joystick
|
||||||
|
|
||||||
|
xpos[1] = (info.wXpos-joysubx[1]) >> joyshrx[1];
|
||||||
|
ypos[1] = (info.wYpos-joysuby[1]) >> joyshry[1];
|
||||||
|
|
||||||
|
// NB. This does not work for analogue joysticks (not self-centreing) - except if Trim=0
|
||||||
|
if(xpos[1] == 127 || xpos[1] == 128) xpos[1] += g_nPdlTrimX;
|
||||||
|
if(ypos[1] == 127 || ypos[1] == 128) ypos[1] += g_nPdlTrimY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE -----
|
||||||
|
//
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void JoyInitialize ()
|
||||||
|
{
|
||||||
|
// Emulated joystick #0 can only use JOYSTICKID1 (if no joystick, then use mouse)
|
||||||
|
// Emulated joystick #1 can only use JOYSTICKID2 (if no joystick, then disable)
|
||||||
|
|
||||||
|
//
|
||||||
|
// Init for emulated joystick #0:
|
||||||
|
//
|
||||||
|
|
||||||
|
if (joyinfo[joytype[0]].device == DEVICE_JOYSTICK)
|
||||||
|
{
|
||||||
|
JOYCAPS caps;
|
||||||
|
if (joyGetDevCaps(JOYSTICKID1,&caps,sizeof(JOYCAPS)) == JOYERR_NOERROR)
|
||||||
|
{
|
||||||
|
joyshrx[0] = 0;
|
||||||
|
joyshry[0] = 0;
|
||||||
|
joysubx[0] = (int)caps.wXmin;
|
||||||
|
joysuby[0] = (int)caps.wYmin;
|
||||||
|
UINT xrange = caps.wXmax-caps.wXmin;
|
||||||
|
UINT yrange = caps.wYmax-caps.wYmin;
|
||||||
|
while (xrange > 256)
|
||||||
|
{
|
||||||
|
xrange >>= 1;
|
||||||
|
++joyshrx[0];
|
||||||
|
}
|
||||||
|
while (yrange > 256)
|
||||||
|
{
|
||||||
|
yrange >>= 1;
|
||||||
|
++joyshry[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
joytype[0] = DEVICE_MOUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Init for emulated joystick #1:
|
||||||
|
//
|
||||||
|
|
||||||
|
if (joyinfo[joytype[1]].device == DEVICE_JOYSTICK)
|
||||||
|
{
|
||||||
|
JOYCAPS caps;
|
||||||
|
if (joyGetDevCaps(JOYSTICKID2,&caps,sizeof(JOYCAPS)) == JOYERR_NOERROR)
|
||||||
|
{
|
||||||
|
joyshrx[1] = 0;
|
||||||
|
joyshry[1] = 0;
|
||||||
|
joysubx[1] = (int)caps.wXmin;
|
||||||
|
joysuby[1] = (int)caps.wYmin;
|
||||||
|
UINT xrange = caps.wXmax-caps.wXmin;
|
||||||
|
UINT yrange = caps.wYmax-caps.wYmin;
|
||||||
|
while (xrange > 256)
|
||||||
|
{
|
||||||
|
xrange >>= 1;
|
||||||
|
++joyshrx[1];
|
||||||
|
}
|
||||||
|
while (yrange > 256)
|
||||||
|
{
|
||||||
|
yrange >>= 1;
|
||||||
|
++joyshry[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
joytype[1] = DEVICE_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
BOOL JoyProcessKey (int virtkey, BOOL extended, BOOL down, BOOL autorep)
|
||||||
|
{
|
||||||
|
if( (joyinfo[joytype[0]].device != DEVICE_KEYBOARD) &&
|
||||||
|
(joyinfo[joytype[1]].device != DEVICE_KEYBOARD) &&
|
||||||
|
(virtkey != VK_MENU) // VK_MENU == ALT Key
|
||||||
|
)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Joystick # which is being emulated by keyboard
|
||||||
|
int nJoyNum = (joyinfo[joytype[0]].device == DEVICE_KEYBOARD) ? 0 : 1;
|
||||||
|
int nCenteringType = joyinfo[joytype[nJoyNum]].mode; // MODE_STANDARD or MODE_CENTERING
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
BOOL keychange = !extended;
|
||||||
|
|
||||||
|
if (virtkey == VK_MENU) // VK_MENU == ALT Key (Button #0 or #1)
|
||||||
|
{
|
||||||
|
keychange = 1;
|
||||||
|
keydown[JK_OPENAPPLE+(extended != 0)] = down;
|
||||||
|
}
|
||||||
|
else if (!extended)
|
||||||
|
{
|
||||||
|
if ((virtkey >= VK_NUMPAD1) && (virtkey <= VK_NUMPAD9))
|
||||||
|
{
|
||||||
|
keydown[virtkey-VK_NUMPAD1] = down;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (virtkey)
|
||||||
|
{
|
||||||
|
case VK_END: keydown[ 0] = down; break;
|
||||||
|
case VK_DOWN: keydown[ 1] = down; break;
|
||||||
|
case VK_NEXT: keydown[ 2] = down; break;
|
||||||
|
case VK_LEFT: keydown[ 3] = down; break;
|
||||||
|
case VK_CLEAR: keydown[ 4] = down; break;
|
||||||
|
case VK_RIGHT: keydown[ 5] = down; break;
|
||||||
|
case VK_HOME: keydown[ 6] = down; break;
|
||||||
|
case VK_UP: keydown[ 7] = down; break;
|
||||||
|
case VK_PRIOR: keydown[ 8] = down; break;
|
||||||
|
case VK_NUMPAD0: keydown[ 9] = down; break; // Button #0
|
||||||
|
case VK_INSERT: keydown[ 9] = down; break; // Button #0
|
||||||
|
case VK_DECIMAL: keydown[10] = down; break; // Button #1
|
||||||
|
case VK_DELETE: keydown[10] = down; break; // Button #1
|
||||||
|
default: keychange = 0; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
if (keychange)
|
||||||
|
{
|
||||||
|
if ((virtkey == VK_NUMPAD0) || (virtkey == VK_INSERT))
|
||||||
|
{
|
||||||
|
if(down)
|
||||||
|
{
|
||||||
|
if(joyinfo[joytype[1]].device != DEVICE_KEYBOARD)
|
||||||
|
{
|
||||||
|
buttonlatch[0] = BUTTONTIME;
|
||||||
|
}
|
||||||
|
else if(joyinfo[joytype[1]].device != DEVICE_NONE)
|
||||||
|
{
|
||||||
|
buttonlatch[2] = BUTTONTIME;
|
||||||
|
buttonlatch[1] = BUTTONTIME; // Re-map this button when emulating a 2nd Apple joystick
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((virtkey == VK_DECIMAL) || (virtkey == VK_DELETE))
|
||||||
|
{
|
||||||
|
if(down)
|
||||||
|
{
|
||||||
|
if(joyinfo[joytype[1]].device != DEVICE_KEYBOARD)
|
||||||
|
buttonlatch[1] = BUTTONTIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((down && !autorep) || (nCenteringType == MODE_CENTERING))
|
||||||
|
{
|
||||||
|
int xkeys = 0;
|
||||||
|
int ykeys = 0;
|
||||||
|
int xtotal = 0;
|
||||||
|
int ytotal = 0;
|
||||||
|
int keynum = 0;
|
||||||
|
while (keynum < 9)
|
||||||
|
{
|
||||||
|
if (keydown[keynum])
|
||||||
|
{
|
||||||
|
if ((keynum % 3) != 1)
|
||||||
|
{
|
||||||
|
xkeys++;
|
||||||
|
xtotal += keyvalue[keynum].x;
|
||||||
|
}
|
||||||
|
if ((keynum / 3) != 1)
|
||||||
|
{
|
||||||
|
ykeys++;
|
||||||
|
ytotal += keyvalue[keynum].y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
keynum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xkeys)
|
||||||
|
xpos[nJoyNum] = xtotal / xkeys;
|
||||||
|
else
|
||||||
|
xpos[nJoyNum] = PDL_CENTRAL+g_nPdlTrimX;
|
||||||
|
if (ykeys)
|
||||||
|
ypos[nJoyNum] = ytotal / ykeys;
|
||||||
|
else
|
||||||
|
ypos[nJoyNum] = PDL_CENTRAL+g_nPdlTrimY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return keychange;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
BYTE __stdcall JoyReadButton (WORD, BYTE address, BYTE, BYTE, ULONG)
|
||||||
|
{
|
||||||
|
if(joyinfo[joytype[0]].device == DEVICE_JOYSTICK)
|
||||||
|
CheckJoystick0();
|
||||||
|
if(joyinfo[joytype[1]].device == DEVICE_JOYSTICK)
|
||||||
|
CheckJoystick1();
|
||||||
|
|
||||||
|
BOOL pressed = 0;
|
||||||
|
switch (address) {
|
||||||
|
|
||||||
|
case 0x61:
|
||||||
|
pressed = (buttonlatch[0] || joybutton[0] || setbutton[0] || keydown[JK_OPENAPPLE]);
|
||||||
|
if(joyinfo[joytype[1]].device != DEVICE_KEYBOARD)
|
||||||
|
pressed = (pressed || keydown[JK_BUTTON0]);
|
||||||
|
buttonlatch[0] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x62:
|
||||||
|
pressed = (buttonlatch[1] || joybutton[1] || setbutton[1] || keydown[JK_CLOSEDAPPLE]);
|
||||||
|
if(joyinfo[joytype[1]].device != DEVICE_KEYBOARD)
|
||||||
|
pressed = (pressed || keydown[JK_BUTTON1]);
|
||||||
|
buttonlatch[1] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x63:
|
||||||
|
pressed = (buttonlatch[2] || joybutton[2] || setbutton[2] || (GetKeyState(VK_SHIFT) < 0));
|
||||||
|
buttonlatch[2] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return MemReturnRandomData(pressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
// PREAD: ; $FB1E
|
||||||
|
// AD 70 C0 : (4) LDA $C070
|
||||||
|
// A0 00 : (2) LDA #$00
|
||||||
|
// EA : (2) NOP
|
||||||
|
// EA : (2) NOP
|
||||||
|
// Lbl1: ; 11 cycles is the normal duration of the loop
|
||||||
|
// BD 64 C0 : (4) LDA $C064,X
|
||||||
|
// 10 04 : (2) BPL Lbl2 ; NB. 3 cycles if branch taken (not likely)
|
||||||
|
// C8 : (2) INY
|
||||||
|
// D0 F8 : (3) BNE Lbl1 ; NB. 2 cycles if branck not taken (not likely)
|
||||||
|
// 88 : (2) DEY
|
||||||
|
// Lbl2:
|
||||||
|
// 60 : (6) RTS
|
||||||
|
//
|
||||||
|
|
||||||
|
static const double PDL_CNTR_INTERVAL = 2816.0 / 255.0; // 11.04 (From KEGS)
|
||||||
|
|
||||||
|
BYTE __stdcall JoyReadPosition (WORD programcounter, BYTE address, BYTE, BYTE, ULONG nCyclesLeft)
|
||||||
|
{
|
||||||
|
int nJoyNum = (address & 2) ? 1 : 0; // $C064..$C067
|
||||||
|
|
||||||
|
CpuCalcCycles(nCyclesLeft);
|
||||||
|
|
||||||
|
ULONG nPdlPos = (address & 1) ? ypos[nJoyNum] : xpos[nJoyNum];
|
||||||
|
|
||||||
|
// This is from KEGS. It helps games like Championship Lode Runner & Boulderdash
|
||||||
|
if(nPdlPos >= 255)
|
||||||
|
nPdlPos = 280;
|
||||||
|
|
||||||
|
BOOL nPdlCntrActive = g_nCumulativeCycles <= (g_nJoyCntrResetCycle + (unsigned __int64) ((double)nPdlPos * PDL_CNTR_INTERVAL));
|
||||||
|
|
||||||
|
return MemReturnRandomData(nPdlCntrActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void JoyReset ()
|
||||||
|
{
|
||||||
|
int loop = 0;
|
||||||
|
while (loop < JK_MAX)
|
||||||
|
keydown[loop++] = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall JoyResetPosition (WORD, BYTE, BYTE, BYTE, ULONG nCyclesLeft)
|
||||||
|
{
|
||||||
|
CpuCalcCycles(nCyclesLeft);
|
||||||
|
g_nJoyCntrResetCycle = g_nCumulativeCycles;
|
||||||
|
|
||||||
|
if(joyinfo[joytype[0]].device == DEVICE_JOYSTICK)
|
||||||
|
CheckJoystick0();
|
||||||
|
if(joyinfo[joytype[1]].device == DEVICE_JOYSTICK)
|
||||||
|
CheckJoystick1();
|
||||||
|
|
||||||
|
return MemReturnRandomData(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
// Called when mouse is being used as a joystick && mouse button changes
|
||||||
|
void JoySetButton (int number, BOOL down)
|
||||||
|
{
|
||||||
|
if (number > 1) // Sanity check on mouse button #
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If 2nd joystick is enabled, then both joysticks only have 1 button
|
||||||
|
if((joyinfo[joytype[1]].device != DEVICE_NONE) && (number != 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
setbutton[number] = down;
|
||||||
|
|
||||||
|
if (down)
|
||||||
|
buttonlatch[number] = BUTTONTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BOOL JoySetEmulationType (HWND window, DWORD newtype, int nJoystickNumber)
|
||||||
|
{
|
||||||
|
if(joytype[nJoystickNumber] == newtype)
|
||||||
|
return 1; // Already set to this type. Return OK.
|
||||||
|
|
||||||
|
if (joyinfo[newtype].device == DEVICE_JOYSTICK)
|
||||||
|
{
|
||||||
|
JOYCAPS caps;
|
||||||
|
unsigned int nJoyID = nJoystickNumber == JN_JOYSTICK0 ? JOYSTICKID1 : JOYSTICKID2;
|
||||||
|
if (joyGetDevCaps(nJoyID, &caps, sizeof(JOYCAPS)) != JOYERR_NOERROR)
|
||||||
|
{
|
||||||
|
MessageBox(window,
|
||||||
|
TEXT("The emulator is unable to read your PC joystick. ")
|
||||||
|
TEXT("Ensure that your game port is configured properly, ")
|
||||||
|
TEXT("that the joystick is firmly plugged in, and that ")
|
||||||
|
TEXT("you have a joystick driver installed."),
|
||||||
|
TEXT("Configuration"),
|
||||||
|
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((joyinfo[newtype].device == DEVICE_MOUSE) &&
|
||||||
|
(joyinfo[joytype[nJoystickNumber]].device != DEVICE_MOUSE))
|
||||||
|
{
|
||||||
|
MessageBox(window,
|
||||||
|
TEXT("To begin emulating a joystick with your mouse, move ")
|
||||||
|
TEXT("the mouse cursor over the emulated screen of a running ")
|
||||||
|
TEXT("program and click the left mouse button. During the ")
|
||||||
|
TEXT("time the mouse is emulating a joystick, you will not ")
|
||||||
|
TEXT("be able to use it to perform mouse functions, and the ")
|
||||||
|
TEXT("mouse cursor will not be visible. To end joystick ")
|
||||||
|
TEXT("emulation and regain the mouse cursor, click the left ")
|
||||||
|
TEXT("mouse button while pressing Ctrl."),
|
||||||
|
TEXT("Configuration"),
|
||||||
|
MB_ICONINFORMATION | MB_SETFOREGROUND);
|
||||||
|
}
|
||||||
|
joytype[nJoystickNumber] = newtype;
|
||||||
|
JoyInitialize();
|
||||||
|
JoyReset();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
// Called when mouse is being used as a joystick && mouse position changes
|
||||||
|
void JoySetPosition (int xvalue, int xrange, int yvalue, int yrange)
|
||||||
|
{
|
||||||
|
int nJoyNum = (joyinfo[joytype[0]].device == DEVICE_MOUSE) ? 0 : 1;
|
||||||
|
xpos[nJoyNum] = (xvalue*255)/xrange;
|
||||||
|
ypos[nJoyNum] = (yvalue*255)/yrange;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void JoyUpdatePosition ()
|
||||||
|
{
|
||||||
|
if (buttonlatch[0]) --buttonlatch[0];
|
||||||
|
if (buttonlatch[1]) --buttonlatch[1];
|
||||||
|
if (buttonlatch[2]) --buttonlatch[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BOOL JoyUsingMouse ()
|
||||||
|
{
|
||||||
|
return (joyinfo[joytype[0]].device == DEVICE_MOUSE) || (joyinfo[joytype[1]].device == DEVICE_MOUSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
void JoySetTrim(short nValue, bool bAxisX)
|
||||||
|
{
|
||||||
|
if(bAxisX)
|
||||||
|
g_nPdlTrimX = nValue;
|
||||||
|
else
|
||||||
|
g_nPdlTrimY = nValue;
|
||||||
|
|
||||||
|
int nJoyNum = -1;
|
||||||
|
|
||||||
|
if(joyinfo[joytype[0]].device == DEVICE_KEYBOARD)
|
||||||
|
nJoyNum = 0;
|
||||||
|
else if(joyinfo[joytype[1]].device == DEVICE_KEYBOARD)
|
||||||
|
nJoyNum = 1;
|
||||||
|
|
||||||
|
if(nJoyNum >= 0)
|
||||||
|
{
|
||||||
|
xpos[nJoyNum] = PDL_CENTRAL+g_nPdlTrimX;
|
||||||
|
ypos[nJoyNum] = PDL_CENTRAL+g_nPdlTrimY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
short JoyGetTrim(bool bAxisX)
|
||||||
|
{
|
||||||
|
return bAxisX ? g_nPdlTrimX : g_nPdlTrimY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
DWORD JoyGetSnapshot(SS_IO_Joystick* pSS)
|
||||||
|
{
|
||||||
|
pSS->g_nJoyCntrResetCycle = g_nJoyCntrResetCycle;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD JoySetSnapshot(SS_IO_Joystick* pSS)
|
||||||
|
{
|
||||||
|
g_nJoyCntrResetCycle = pSS->g_nJoyCntrResetCycle;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum JOYNUM {JN_JOYSTICK0=0, JN_JOYSTICK1};
|
||||||
|
|
||||||
|
extern DWORD joytype[2];
|
||||||
|
|
||||||
|
void JoyInitialize ();
|
||||||
|
BOOL JoyProcessKey (int,BOOL,BOOL,BOOL);
|
||||||
|
void JoyReset ();
|
||||||
|
void JoySetButton (int,BOOL);
|
||||||
|
BOOL JoySetEmulationType (HWND,DWORD,int);
|
||||||
|
void JoySetPosition (int,int,int,int);
|
||||||
|
void JoyUpdatePosition ();
|
||||||
|
BOOL JoyUsingMouse ();
|
||||||
|
void JoySetTrim(short nValue, bool bAxisX);
|
||||||
|
short JoyGetTrim(bool bAxisX);
|
||||||
|
DWORD JoyGetSnapshot(SS_IO_Joystick* pSS);
|
||||||
|
DWORD JoySetSnapshot(SS_IO_Joystick* pSS);
|
||||||
|
|
||||||
|
BYTE __stdcall JoyReadButton (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall JoyReadPosition (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall JoyResetPosition (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
|
@ -0,0 +1,396 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, Michael O'Brien
|
||||||
|
Copyright (C) 1999-2001, Oliver Schmidt
|
||||||
|
Copyright (C) 2002-2005, Tom Charlesworth
|
||||||
|
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: Keyboard emulation
|
||||||
|
*
|
||||||
|
* Author: Various
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
|
||||||
|
static bool g_bKeybBufferEnable = false;
|
||||||
|
|
||||||
|
#define KEY_OLD
|
||||||
|
#define OLIVER_SCHMIDT_FIX2 // PC's delete key maps to Apple's DEL key
|
||||||
|
|
||||||
|
#ifdef OLIVER_SCHMIDT_FIX2
|
||||||
|
static BYTE asciicode[10] = {0x08,0x0B,0x15,0x0A,0x00,0x00,0x00,0x00,0x00,0x7F}; // Convert PC arrow keys to Apple keycodes
|
||||||
|
#else
|
||||||
|
static BYTE asciicode[4] = {0x08,0x0B,0x15,0x0A}; // Convert PC arrow keys to Apple keycodes
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool gbShiftKey = false; // +PATCH MJP
|
||||||
|
static bool gbCtrlKey = false; // +PATCH MJP
|
||||||
|
static BOOL capslock = 1;
|
||||||
|
static int lastvirtkey = 0; // Current PC keycode
|
||||||
|
static BYTE keycode = 0; // Current Apple keycode
|
||||||
|
static DWORD keyboardqueries = 0;
|
||||||
|
|
||||||
|
#ifdef KEY_OLD
|
||||||
|
// Original
|
||||||
|
static BOOL keywaiting = 0;
|
||||||
|
#else
|
||||||
|
// Buffered key input:
|
||||||
|
// - Needed on faster PCs where aliasing occurs during short/fast bursts of 6502 code.
|
||||||
|
// - Keyboard only sampled during 6502 execution, so if it's run too fast then key presses will be missed.
|
||||||
|
const int KEY_BUFFER_MIN_SIZE = 1;
|
||||||
|
const int KEY_BUFFER_MAX_SIZE = 2;
|
||||||
|
static int g_nKeyBufferSize = KEY_BUFFER_MAX_SIZE; // Circ key buffer size
|
||||||
|
static int g_nNextInIdx = 0;
|
||||||
|
static int g_nNextOutIdx = 0;
|
||||||
|
static int g_nKeyBufferCnt = 0;
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
int nVirtKey;
|
||||||
|
BYTE nAppleKey;
|
||||||
|
} g_nKeyBuffer[KEY_BUFFER_MAX_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static BYTE g_nLastKey = 0x00;
|
||||||
|
|
||||||
|
//
|
||||||
|
// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE -----
|
||||||
|
//
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
void KeybReset()
|
||||||
|
{
|
||||||
|
#ifdef KEY_OLD
|
||||||
|
keywaiting = 0;
|
||||||
|
#else
|
||||||
|
g_nNextInIdx = 0;
|
||||||
|
g_nNextOutIdx = 0;
|
||||||
|
g_nKeyBufferCnt = 0;
|
||||||
|
g_nLastKey = 0x00;
|
||||||
|
|
||||||
|
g_nKeyBufferSize = g_bKeybBufferEnable ? KEY_BUFFER_MAX_SIZE : KEY_BUFFER_MIN_SIZE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
//void KeybSetBufferMode(bool bNewKeybBufferEnable)
|
||||||
|
//{
|
||||||
|
// if(g_bKeybBufferEnable == bNewKeybBufferEnable)
|
||||||
|
// return;
|
||||||
|
//
|
||||||
|
// g_bKeybBufferEnable = bNewKeybBufferEnable;
|
||||||
|
// KeybReset();
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//bool KeybGetBufferMode()
|
||||||
|
//{
|
||||||
|
// return g_bKeybBufferEnable;
|
||||||
|
//}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void KeybGetCapsStatus (BOOL *status)
|
||||||
|
{
|
||||||
|
*status = capslock;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
bool KeybGetShiftStatus ()
|
||||||
|
{
|
||||||
|
return gbShiftKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
bool KeybGetCtrlStatus ()
|
||||||
|
{
|
||||||
|
return gbCtrlKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void KeybUpdateCtrlShiftStatus()
|
||||||
|
{
|
||||||
|
gbShiftKey = (GetKeyState( VK_SHIFT ) & 0x8000) ? true : false;
|
||||||
|
gbCtrlKey = (GetKeyState( VK_CONTROL) & 0x8000) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE KeybGetKeycode () // Used by MemCheckPaging() & VideoCheckMode()
|
||||||
|
{
|
||||||
|
return keycode;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
DWORD KeybGetNumQueries () // Used in determining 'idleness' of Apple system
|
||||||
|
{
|
||||||
|
DWORD result = keyboardqueries;
|
||||||
|
keyboardqueries = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void KeybQueueKeypress (int key, BOOL bASCII)
|
||||||
|
{
|
||||||
|
if (bASCII == ASCII)
|
||||||
|
{
|
||||||
|
if (key > 0x7F)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((key >= 'a') && (key <= 'z') && (capslock || !apple2e))
|
||||||
|
keycode = key - ('a'-'A');
|
||||||
|
else
|
||||||
|
keycode = key;
|
||||||
|
|
||||||
|
lastvirtkey = LOBYTE(VkKeyScan(key));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((key == VK_CANCEL) && ((!apple2e) || (GetKeyState(VK_CONTROL) < 0)) )
|
||||||
|
{
|
||||||
|
// Ctrl+Reset
|
||||||
|
if (apple2e)
|
||||||
|
MemResetPaging();
|
||||||
|
|
||||||
|
DiskReset();
|
||||||
|
KeybReset();
|
||||||
|
VideoResetState(); // Switch Alternate char set off
|
||||||
|
MB_Reset();
|
||||||
|
|
||||||
|
#ifndef KEY_OLD
|
||||||
|
g_nNextInIdx = g_nNextOutIdx = g_nKeyBufferCnt = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CpuInitialize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((key == VK_INSERT) && (GetKeyState(VK_SHIFT) < 0))
|
||||||
|
{
|
||||||
|
// Shift+Insert
|
||||||
|
ClipboardInitiatePaste();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OLIVER_SCHMIDT_FIX2
|
||||||
|
if (!((key >= VK_LEFT) && (key <= VK_DELETE) && asciicode[key - VK_LEFT]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
keycode = asciicode[key - VK_LEFT]; // Convert to Apple arrow keycode
|
||||||
|
lastvirtkey = key;
|
||||||
|
#else
|
||||||
|
if (!((key >= VK_LEFT) && (key <= VK_DOWN)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
keycode = asciicode[key - VK_LEFT]; // Convert to Apple arrow keycode
|
||||||
|
lastvirtkey = key;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef KEY_OLD
|
||||||
|
keywaiting = 1;
|
||||||
|
#else
|
||||||
|
bool bOverflow = false;
|
||||||
|
|
||||||
|
if(g_nKeyBufferCnt < g_nKeyBufferSize)
|
||||||
|
g_nKeyBufferCnt++;
|
||||||
|
else
|
||||||
|
bOverflow = true;
|
||||||
|
|
||||||
|
g_nKeyBuffer[g_nNextInIdx].nVirtKey = lastvirtkey;
|
||||||
|
g_nKeyBuffer[g_nNextInIdx].nAppleKey = keycode;
|
||||||
|
g_nNextInIdx = (g_nNextInIdx + 1) % g_nKeyBufferSize;
|
||||||
|
|
||||||
|
if(bOverflow)
|
||||||
|
g_nNextOutIdx = (g_nNextOutIdx + 1) % g_nKeyBufferSize;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
static HGLOBAL hglb = NULL;
|
||||||
|
static LPTSTR lptstr = NULL;
|
||||||
|
static bool g_bPasteFromClipboard = false;
|
||||||
|
static bool g_bClipboardActive = false;
|
||||||
|
|
||||||
|
void ClipboardInitiatePaste()
|
||||||
|
{
|
||||||
|
if (g_bClipboardActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_bPasteFromClipboard = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ClipboardDone()
|
||||||
|
{
|
||||||
|
if (g_bClipboardActive)
|
||||||
|
{
|
||||||
|
g_bClipboardActive = false;
|
||||||
|
GlobalUnlock(hglb);
|
||||||
|
CloseClipboard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ClipboardInit()
|
||||||
|
{
|
||||||
|
ClipboardDone();
|
||||||
|
|
||||||
|
if (!IsClipboardFormatAvailable(CF_TEXT))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!OpenClipboard(framewindow))
|
||||||
|
return;
|
||||||
|
|
||||||
|
hglb = GetClipboardData(CF_TEXT);
|
||||||
|
if (hglb == NULL)
|
||||||
|
{
|
||||||
|
CloseClipboard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lptstr = (char*) GlobalLock(hglb);
|
||||||
|
if (lptstr == NULL)
|
||||||
|
{
|
||||||
|
CloseClipboard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_bPasteFromClipboard = false;
|
||||||
|
g_bClipboardActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char ClipboardCurrChar(bool bIncPtr)
|
||||||
|
{
|
||||||
|
char nKey;
|
||||||
|
int nInc = 1;
|
||||||
|
|
||||||
|
if((lptstr[0] == 0x0D) && (lptstr[1] == 0x0A))
|
||||||
|
{
|
||||||
|
nKey = 0x0D;
|
||||||
|
nInc = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nKey = lptstr[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bIncPtr)
|
||||||
|
lptstr += nInc;
|
||||||
|
|
||||||
|
return nKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
BYTE __stdcall KeybReadData (WORD, BYTE, BYTE, BYTE, ULONG)
|
||||||
|
{
|
||||||
|
keyboardqueries++;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
if(g_bPasteFromClipboard)
|
||||||
|
ClipboardInit();
|
||||||
|
|
||||||
|
if(g_bClipboardActive)
|
||||||
|
{
|
||||||
|
if(*lptstr == 0)
|
||||||
|
ClipboardDone();
|
||||||
|
else
|
||||||
|
return 0x80 | ClipboardCurrChar(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef KEY_OLD
|
||||||
|
return keycode | (keywaiting ? 0x80 : 0);
|
||||||
|
#else
|
||||||
|
BYTE nKey = g_nKeyBufferCnt ? 0x80 : 0;
|
||||||
|
if(g_nKeyBufferCnt)
|
||||||
|
{
|
||||||
|
nKey |= g_nKeyBuffer[g_nNextOutIdx].nAppleKey;
|
||||||
|
g_nLastKey = g_nKeyBuffer[g_nNextOutIdx].nAppleKey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nKey |= g_nLastKey;
|
||||||
|
}
|
||||||
|
return nKey;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
BYTE __stdcall KeybReadFlag (WORD, BYTE, BYTE, BYTE, ULONG)
|
||||||
|
{
|
||||||
|
keyboardqueries++;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
if(g_bPasteFromClipboard)
|
||||||
|
ClipboardInit();
|
||||||
|
|
||||||
|
if(g_bClipboardActive)
|
||||||
|
{
|
||||||
|
if(*lptstr == 0)
|
||||||
|
ClipboardDone();
|
||||||
|
else
|
||||||
|
return 0x80 | ClipboardCurrChar(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef KEY_OLD
|
||||||
|
keywaiting = 0;
|
||||||
|
return keycode | ((GetKeyState(lastvirtkey) < 0) ? 0x80 : 0);
|
||||||
|
#else
|
||||||
|
BYTE nKey = (GetKeyState(g_nKeyBuffer[g_nNextOutIdx].nVirtKey) < 0) ? 0x80 : 0;
|
||||||
|
nKey |= g_nKeyBuffer[g_nNextOutIdx].nAppleKey;
|
||||||
|
if(g_nKeyBufferCnt)
|
||||||
|
{
|
||||||
|
g_nKeyBufferCnt--;
|
||||||
|
g_nNextOutIdx = (g_nNextOutIdx + 1) % g_nKeyBufferSize;
|
||||||
|
}
|
||||||
|
return nKey;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void KeybToggleCapsLock ()
|
||||||
|
{
|
||||||
|
if (apple2e)
|
||||||
|
{
|
||||||
|
capslock = (GetKeyState(VK_CAPITAL) & 1);
|
||||||
|
FrameRefreshStatus(DRAW_LEDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
DWORD KeybGetSnapshot(SS_IO_Keyboard* pSS)
|
||||||
|
{
|
||||||
|
pSS->keyboardqueries = keyboardqueries;
|
||||||
|
pSS->nLastKey = g_nLastKey;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD KeybSetSnapshot(SS_IO_Keyboard* pSS)
|
||||||
|
{
|
||||||
|
keyboardqueries = pSS->keyboardqueries;
|
||||||
|
g_nLastKey = pSS->nLastKey;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void ClipboardInitiatePaste();
|
||||||
|
|
||||||
|
void KeybReset();
|
||||||
|
void KeybGetCapsStatus (BOOL *);
|
||||||
|
bool KeybGetShiftStatus();
|
||||||
|
bool KeybGetCtrlStatus();
|
||||||
|
void KeybUpdateCtrlShiftStatus();
|
||||||
|
BYTE KeybGetKeycode ();
|
||||||
|
DWORD KeybGetNumQueries ();
|
||||||
|
void KeybQueueKeypress (int,BOOL);
|
||||||
|
void KeybToggleCapsLock ();
|
||||||
|
DWORD KeybGetSnapshot(SS_IO_Keyboard* pSS);
|
||||||
|
DWORD KeybSetSnapshot(SS_IO_Keyboard* pSS);
|
||||||
|
|
||||||
|
BYTE __stdcall KeybReadData (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall KeybReadFlag (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
|
@ -0,0 +1,33 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern iofunction ioread[0x100];
|
||||||
|
extern iofunction iowrite[0x100];
|
||||||
|
extern LPBYTE memshadow[MAXIMAGES][0x100];
|
||||||
|
extern LPBYTE memwrite[MAXIMAGES][0x100];
|
||||||
|
extern DWORD image;
|
||||||
|
extern DWORD lastimage;
|
||||||
|
extern LPBYTE mem;
|
||||||
|
extern LPBYTE memdirty;
|
||||||
|
extern DWORD pages;
|
||||||
|
|
||||||
|
#ifdef RAMWORKS
|
||||||
|
extern UINT g_uMaxExPages; // user requested ram pages (from cmd line)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void MemDestroy ();
|
||||||
|
LPBYTE MemGetAuxPtr (WORD);
|
||||||
|
LPBYTE MemGetMainPtr (WORD);
|
||||||
|
void MemInitialize ();
|
||||||
|
void MemReset ();
|
||||||
|
void MemResetPaging ();
|
||||||
|
BYTE MemReturnRandomData (BYTE highbit);
|
||||||
|
void MemSetFastPaging (BOOL);
|
||||||
|
void MemTrimImages ();
|
||||||
|
DWORD MemGetSnapshot(SS_BaseMemory* pSS);
|
||||||
|
DWORD MemSetSnapshot(SS_BaseMemory* pSS);
|
||||||
|
|
||||||
|
BYTE __stdcall CxReadFunc(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall CxWriteFunc(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
|
||||||
|
BYTE __stdcall MemCheckPaging (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall MemSetPaging (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern bool g_bMBTimerIrqActive;
|
||||||
|
|
||||||
|
void MB_Initialize();
|
||||||
|
void MB_Reinitialize();
|
||||||
|
void MB_Destroy();
|
||||||
|
void MB_Reset();
|
||||||
|
BYTE MB_Read(WORD nAddr);
|
||||||
|
void MB_Write(WORD nAddr, BYTE nValue);
|
||||||
|
void MB_Mute();
|
||||||
|
void MB_Demute();
|
||||||
|
void MB_EndOfFrame();
|
||||||
|
void MB_CheckIRQ();
|
||||||
|
void MB_UpdateCycles(USHORT nClocks);
|
||||||
|
eSOUNDCARDTYPE MB_GetSoundcardType();
|
||||||
|
void MB_SetSoundcardType(eSOUNDCARDTYPE NewSoundcardType);
|
||||||
|
double MB_GetFramePeriod();
|
||||||
|
bool MB_IsActive();
|
||||||
|
DWORD MB_GetVolume();
|
||||||
|
void MB_SetVolume(DWORD dwVolume, DWORD dwVolumeMax);
|
||||||
|
DWORD MB_GetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD dwSlot);
|
||||||
|
DWORD MB_SetSnapshot(SS_CARD_MOCKINGBOARD* pSS, DWORD dwSlot);
|
||||||
|
|
||||||
|
BYTE __stdcall PhasorIO (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void PSP_Init();
|
||||||
|
DWORD PSP_GetVolumeMax();
|
||||||
|
bool PSP_SaveStateSelectImage(HWND hWindow, bool bSave);
|
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, Michael O'Brien
|
||||||
|
Copyright (C) 1999-2001, Oliver Schmidt
|
||||||
|
Copyright (C) 2002-2005, Tom Charlesworth
|
||||||
|
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: Registry module
|
||||||
|
*
|
||||||
|
* Author: Various
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BOOL RegLoadString (LPCTSTR section, LPCTSTR key, BOOL peruser,
|
||||||
|
LPTSTR buffer, DWORD chars) {
|
||||||
|
BOOL success = 0;
|
||||||
|
TCHAR fullkeyname[256];
|
||||||
|
wsprintf(fullkeyname,
|
||||||
|
TEXT("Software\\AppleWin\\CurrentVersion\\%s"),
|
||||||
|
(LPCTSTR)section);
|
||||||
|
HKEY keyhandle;
|
||||||
|
if (!RegOpenKeyEx((peruser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE),
|
||||||
|
fullkeyname,
|
||||||
|
0,
|
||||||
|
KEY_READ,
|
||||||
|
&keyhandle)) {
|
||||||
|
DWORD type;
|
||||||
|
DWORD size = chars;
|
||||||
|
success = (!RegQueryValueEx(keyhandle,key,0,&type,(LPBYTE)buffer,&size)) &&
|
||||||
|
size;
|
||||||
|
RegCloseKey(keyhandle);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BOOL RegLoadValue (LPCTSTR section, LPCTSTR key, BOOL peruser, DWORD *value) {
|
||||||
|
if (!value)
|
||||||
|
return 0;
|
||||||
|
TCHAR buffer[32] = TEXT("");
|
||||||
|
if (!RegLoadString(section,key,peruser,buffer,32))
|
||||||
|
return 0;
|
||||||
|
buffer[31] = 0;
|
||||||
|
*value = (DWORD)_ttoi(buffer);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void RegSaveString (LPCTSTR section, LPCTSTR key, BOOL peruser, LPCTSTR buffer) {
|
||||||
|
TCHAR fullkeyname[256];
|
||||||
|
wsprintf(fullkeyname,
|
||||||
|
TEXT("Software\\AppleWin\\CurrentVersion\\%s"),
|
||||||
|
(LPCTSTR)section);
|
||||||
|
HKEY keyhandle;
|
||||||
|
DWORD disposition;
|
||||||
|
if (!RegCreateKeyEx((peruser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE),
|
||||||
|
fullkeyname,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
REG_OPTION_NON_VOLATILE,
|
||||||
|
KEY_READ | KEY_WRITE,
|
||||||
|
(LPSECURITY_ATTRIBUTES)NULL,
|
||||||
|
&keyhandle,
|
||||||
|
&disposition)) {
|
||||||
|
RegSetValueEx(keyhandle,
|
||||||
|
key,
|
||||||
|
0,
|
||||||
|
REG_SZ,
|
||||||
|
(CONST BYTE *)buffer,
|
||||||
|
(_tcslen(buffer)+1)*sizeof(TCHAR));
|
||||||
|
RegCloseKey(keyhandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void RegSaveValue (LPCTSTR section, LPCTSTR key, BOOL peruser, DWORD value) {
|
||||||
|
TCHAR buffer[32] = TEXT("");
|
||||||
|
_ultot(value,buffer,10);
|
||||||
|
RegSaveString(section,key,peruser,buffer);
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
BOOL RegLoadString (LPCTSTR,LPCTSTR,BOOL,LPTSTR,DWORD);
|
||||||
|
BOOL RegLoadValue (LPCTSTR,LPCTSTR,BOOL,DWORD *);
|
||||||
|
void RegSaveString (LPCTSTR,LPCTSTR,BOOL,LPCTSTR);
|
||||||
|
void RegSaveValue (LPCTSTR,LPCTSTR,BOOL,DWORD);
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, Michael O'Brien
|
||||||
|
Copyright (C) 1999-2001, Oliver Schmidt
|
||||||
|
Copyright (C) 2002-2005, Tom Charlesworth
|
||||||
|
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: RIFF funcs
|
||||||
|
*
|
||||||
|
* Author: Various
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include "riff.h"
|
||||||
|
|
||||||
|
static HANDLE g_hRiffFile = INVALID_HANDLE_VALUE;
|
||||||
|
static DWORD dwTotalOffset;
|
||||||
|
static DWORD dwDataOffset;
|
||||||
|
static DWORD g_dwTotalNumberOfBytesWritten = 0;
|
||||||
|
static unsigned int g_NumChannels = 2;
|
||||||
|
|
||||||
|
int RiffInitWriteFile(char* pszFile, unsigned int sample_rate, unsigned int NumChannels)
|
||||||
|
{
|
||||||
|
g_hRiffFile = CreateFile(pszFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
|
||||||
|
if(g_hRiffFile == INVALID_HANDLE_VALUE)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
g_NumChannels = NumChannels;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
UINT32 temp32;
|
||||||
|
UINT16 temp16;
|
||||||
|
|
||||||
|
DWORD dwNumberOfBytesWritten;
|
||||||
|
|
||||||
|
WriteFile(g_hRiffFile, "RIFF", 4, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
temp32 = 0; // total size
|
||||||
|
dwTotalOffset = SetFilePointer(g_hRiffFile, 0, NULL, FILE_CURRENT);
|
||||||
|
WriteFile(g_hRiffFile, &temp32, 4, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
WriteFile(g_hRiffFile, "WAVE", 4, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
WriteFile(g_hRiffFile, "fmt ", 4, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
temp32 = 16; // format length
|
||||||
|
WriteFile(g_hRiffFile, &temp32, 4, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
temp16 = 1; // PCM format
|
||||||
|
WriteFile(g_hRiffFile, &temp16, 2, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
temp16 = NumChannels; // channels
|
||||||
|
WriteFile(g_hRiffFile, &temp16, 2, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
temp32 = sample_rate; // sample rate
|
||||||
|
WriteFile(g_hRiffFile, &temp32, 4, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
temp32 = sample_rate * 2 * NumChannels; // bytes/second
|
||||||
|
WriteFile(g_hRiffFile, &temp32, 4, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
temp16 = 2 * NumChannels; // block align
|
||||||
|
WriteFile(g_hRiffFile, &temp16, 2, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
temp16 = 16; // bits/sample
|
||||||
|
WriteFile(g_hRiffFile, &temp16, 2, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
WriteFile(g_hRiffFile, "data", 4, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
temp32 = 0; // data length
|
||||||
|
dwDataOffset = SetFilePointer(g_hRiffFile, 0, NULL, FILE_CURRENT);
|
||||||
|
WriteFile(g_hRiffFile, &temp32, 4, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RiffFinishWriteFile()
|
||||||
|
{
|
||||||
|
if(g_hRiffFile == INVALID_HANDLE_VALUE)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
UINT32 temp32;
|
||||||
|
|
||||||
|
DWORD dwNumberOfBytesWritten;
|
||||||
|
|
||||||
|
temp32 = g_dwTotalNumberOfBytesWritten - (dwTotalOffset + 4);
|
||||||
|
SetFilePointer(g_hRiffFile, dwTotalOffset, NULL, FILE_BEGIN);
|
||||||
|
WriteFile(g_hRiffFile, &temp32, 4, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
temp32 = g_dwTotalNumberOfBytesWritten - (dwDataOffset + 4);
|
||||||
|
SetFilePointer(g_hRiffFile, dwDataOffset, NULL, FILE_BEGIN);
|
||||||
|
WriteFile(g_hRiffFile, &temp32, 4, &dwNumberOfBytesWritten, NULL);
|
||||||
|
|
||||||
|
return CloseHandle(g_hRiffFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RiffPutSamples(short* buf, unsigned int uSamples)
|
||||||
|
{
|
||||||
|
if(g_hRiffFile == INVALID_HANDLE_VALUE)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
DWORD dwNumberOfBytesWritten;
|
||||||
|
|
||||||
|
BOOL bRes = WriteFile(
|
||||||
|
g_hRiffFile,
|
||||||
|
buf,
|
||||||
|
uSamples * sizeof(short) * g_NumChannels,
|
||||||
|
&dwNumberOfBytesWritten,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
g_dwTotalNumberOfBytesWritten += dwNumberOfBytesWritten;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
int RiffInitWriteFile(char* pszFile, unsigned int sample_rate, unsigned int NumChannels);
|
||||||
|
int RiffFinishWriteFile();
|
||||||
|
int RiffPutSamples(short* buf, unsigned int uSamples);
|
|
@ -0,0 +1,290 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, Michael O'Brien
|
||||||
|
Copyright (C) 1999-2001, Oliver Schmidt
|
||||||
|
Copyright (C) 2002-2005, Tom Charlesworth
|
||||||
|
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: Save-state (snapshot) module
|
||||||
|
*
|
||||||
|
* Author: Copyright (c) 2004-2006 Tom Charlesworth
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
|
||||||
|
#define DEFAULT_SNAPSHOT_NAME "SaveState.aws"
|
||||||
|
|
||||||
|
bool g_bSaveStateOnExit = false;
|
||||||
|
|
||||||
|
static char g_szSaveStateFilename[MAX_PATH] = {0};
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
char* Snapshot_GetFilename()
|
||||||
|
{
|
||||||
|
return g_szSaveStateFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Snapshot_SetFilename(char* pszFilename)
|
||||||
|
{
|
||||||
|
if(*pszFilename)
|
||||||
|
strcpy(g_szSaveStateFilename, (const char *) pszFilename);
|
||||||
|
else
|
||||||
|
strcpy(g_szSaveStateFilename, DEFAULT_SNAPSHOT_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void Snapshot_LoadState()
|
||||||
|
{
|
||||||
|
char szMessage[32 + MAX_PATH];
|
||||||
|
|
||||||
|
APPLEWIN_SNAPSHOT* pSS = (APPLEWIN_SNAPSHOT*) new char[sizeof(APPLEWIN_SNAPSHOT)];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(pSS == NULL)
|
||||||
|
throw(0);
|
||||||
|
|
||||||
|
memset(pSS, 0, sizeof(APPLEWIN_SNAPSHOT));
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
HANDLE hFile = CreateFile( g_szSaveStateFilename,
|
||||||
|
GENERIC_READ,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if(hFile == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
strcpy(szMessage, "File not found: ");
|
||||||
|
strcpy(szMessage + strlen(szMessage), g_szSaveStateFilename);
|
||||||
|
throw(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD dwBytesRead;
|
||||||
|
BOOL bRes = ReadFile( hFile,
|
||||||
|
pSS,
|
||||||
|
sizeof(APPLEWIN_SNAPSHOT),
|
||||||
|
&dwBytesRead,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
CloseHandle(hFile);
|
||||||
|
|
||||||
|
if(!bRes || (dwBytesRead != sizeof(APPLEWIN_SNAPSHOT)))
|
||||||
|
{
|
||||||
|
// File size wrong: probably because of version mismatch or corrupt file
|
||||||
|
strcpy(szMessage, "File size mismatch");
|
||||||
|
throw(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pSS->Hdr.dwTag != AW_SS_TAG)
|
||||||
|
{
|
||||||
|
strcpy(szMessage, "File corrupt");
|
||||||
|
throw(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pSS->Hdr.dwVersion != MAKE_VERSION(1,0,0,1))
|
||||||
|
{
|
||||||
|
strcpy(szMessage, "Version mismatch");
|
||||||
|
throw(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TO DO: Verify checksum
|
||||||
|
|
||||||
|
//
|
||||||
|
// Reset all sub-systems
|
||||||
|
MemReset();
|
||||||
|
|
||||||
|
if (apple2e)
|
||||||
|
MemResetPaging();
|
||||||
|
|
||||||
|
DiskReset();
|
||||||
|
KeybReset();
|
||||||
|
VideoResetState();
|
||||||
|
MB_Reset();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Apple2 uint
|
||||||
|
//
|
||||||
|
|
||||||
|
CpuSetSnapshot(&pSS->Apple2Unit.CPU6502);
|
||||||
|
CommSetSnapshot(&pSS->Apple2Unit.Comms);
|
||||||
|
JoySetSnapshot(&pSS->Apple2Unit.Joystick);
|
||||||
|
KeybSetSnapshot(&pSS->Apple2Unit.Keyboard);
|
||||||
|
SpkrSetSnapshot(&pSS->Apple2Unit.Speaker);
|
||||||
|
VideoSetSnapshot(&pSS->Apple2Unit.Video);
|
||||||
|
MemSetSnapshot(&pSS->Apple2Unit.Memory);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Slot4: Mockingboard
|
||||||
|
MB_SetSnapshot(&pSS->Mockingboard1, 4);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Slot5: Mockingboard
|
||||||
|
MB_SetSnapshot(&pSS->Mockingboard2, 5);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Slot6: Disk][
|
||||||
|
DiskSetSnapshot(&pSS->Disk2, 6);
|
||||||
|
}
|
||||||
|
catch(int)
|
||||||
|
{
|
||||||
|
MessageBox( framewindow,
|
||||||
|
szMessage,
|
||||||
|
TEXT("Load State"),
|
||||||
|
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete [] pSS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void Snapshot_SaveState()
|
||||||
|
{
|
||||||
|
APPLEWIN_SNAPSHOT* pSS = (APPLEWIN_SNAPSHOT*) new char[sizeof(APPLEWIN_SNAPSHOT)];
|
||||||
|
if(pSS == NULL)
|
||||||
|
{
|
||||||
|
// To do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(pSS, 0, sizeof(APPLEWIN_SNAPSHOT));
|
||||||
|
|
||||||
|
pSS->Hdr.dwTag = AW_SS_TAG;
|
||||||
|
pSS->Hdr.dwVersion = MAKE_VERSION(1,0,0,1);
|
||||||
|
pSS->Hdr.dwChecksum = 0; // TO DO
|
||||||
|
|
||||||
|
//
|
||||||
|
// Apple2 uint
|
||||||
|
//
|
||||||
|
|
||||||
|
pSS->Apple2Unit.UnitHdr.dwLength = sizeof(SS_APPLE2_Unit);
|
||||||
|
pSS->Apple2Unit.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0);
|
||||||
|
|
||||||
|
CpuGetSnapshot(&pSS->Apple2Unit.CPU6502);
|
||||||
|
CommGetSnapshot(&pSS->Apple2Unit.Comms);
|
||||||
|
JoyGetSnapshot(&pSS->Apple2Unit.Joystick);
|
||||||
|
KeybGetSnapshot(&pSS->Apple2Unit.Keyboard);
|
||||||
|
SpkrGetSnapshot(&pSS->Apple2Unit.Speaker);
|
||||||
|
VideoGetSnapshot(&pSS->Apple2Unit.Video);
|
||||||
|
MemGetSnapshot(&pSS->Apple2Unit.Memory);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Slot1: Empty
|
||||||
|
pSS->Empty1.Hdr.UnitHdr.dwLength = sizeof(SS_CARD_EMPTY);
|
||||||
|
pSS->Empty1.Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0);
|
||||||
|
pSS->Empty1.Hdr.dwSlot = 1;
|
||||||
|
pSS->Empty1.Hdr.dwType = CT_Empty;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Slot2: Empty
|
||||||
|
pSS->Empty2.Hdr.UnitHdr.dwLength = sizeof(SS_CARD_EMPTY);
|
||||||
|
pSS->Empty2.Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0);
|
||||||
|
pSS->Empty2.Hdr.dwSlot = 2;
|
||||||
|
pSS->Empty2.Hdr.dwType = CT_Empty;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Slot3: Empty
|
||||||
|
pSS->Empty3.Hdr.UnitHdr.dwLength = sizeof(SS_CARD_EMPTY);
|
||||||
|
pSS->Empty3.Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,0);
|
||||||
|
pSS->Empty3.Hdr.dwSlot = 3;
|
||||||
|
pSS->Empty3.Hdr.dwType = CT_Empty;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Slot4: Mockingboard
|
||||||
|
MB_GetSnapshot(&pSS->Mockingboard1, 4);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Slot5: Mockingboard
|
||||||
|
MB_GetSnapshot(&pSS->Mockingboard2, 5);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Slot6: Disk][
|
||||||
|
DiskGetSnapshot(&pSS->Disk2, 6);
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
HANDLE hFile = CreateFile( g_szSaveStateFilename,
|
||||||
|
GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
CREATE_ALWAYS,
|
||||||
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
DWORD dwError = GetLastError();
|
||||||
|
_ASSERT((dwError == 0) || (dwError == ERROR_ALREADY_EXISTS));
|
||||||
|
|
||||||
|
if(hFile != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
DWORD dwBytesWritten;
|
||||||
|
BOOL bRes = WriteFile( hFile,
|
||||||
|
pSS,
|
||||||
|
sizeof(APPLEWIN_SNAPSHOT),
|
||||||
|
&dwBytesWritten,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if(!bRes || (dwBytesWritten != sizeof(APPLEWIN_SNAPSHOT)))
|
||||||
|
dwError = GetLastError();
|
||||||
|
|
||||||
|
CloseHandle(hFile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dwError = GetLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
_ASSERT((dwError == 0) || (dwError == ERROR_ALREADY_EXISTS));
|
||||||
|
|
||||||
|
delete [] pSS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void Snapshot_Startup()
|
||||||
|
{
|
||||||
|
static bool bDone = false;
|
||||||
|
|
||||||
|
if(!g_bSaveStateOnExit || bDone)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Snapshot_LoadState();
|
||||||
|
|
||||||
|
bDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Snapshot_Shutdown()
|
||||||
|
{
|
||||||
|
static bool bDone = false;
|
||||||
|
|
||||||
|
if(!g_bSaveStateOnExit || bDone)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Snapshot_SaveState();
|
||||||
|
|
||||||
|
bDone = true;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern bool g_bSaveStateOnExit;
|
||||||
|
|
||||||
|
char* Snapshot_GetFilename();
|
||||||
|
void Snapshot_SetFilename(char* pszFilename);
|
||||||
|
void Snapshot_LoadState();
|
||||||
|
void Snapshot_SaveState();
|
||||||
|
void Snapshot_Startup();
|
||||||
|
void Snapshot_Shutdown();
|
|
@ -0,0 +1,301 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, Michael O'Brien
|
||||||
|
Copyright (C) 1999-2001, Oliver Schmidt
|
||||||
|
Copyright (C) 2002-2005, Tom Charlesworth
|
||||||
|
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: Enhanced //e & //c serial port emulation
|
||||||
|
*
|
||||||
|
* Author: Various
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
|
||||||
|
static DWORD baudrate = CBR_19200;
|
||||||
|
static BYTE bytesize = 8;
|
||||||
|
static BYTE commandbyte = 0x00;
|
||||||
|
static HANDLE commhandle = INVALID_HANDLE_VALUE;
|
||||||
|
static DWORD comminactivity = 0;
|
||||||
|
static BYTE controlbyte = 0x1F;
|
||||||
|
static BYTE parity = NOPARITY;
|
||||||
|
static BYTE recvbuffer[9];
|
||||||
|
static DWORD recvbytes = 0;
|
||||||
|
DWORD serialport = 0;
|
||||||
|
static BYTE stopbits = ONESTOPBIT;
|
||||||
|
|
||||||
|
static void UpdateCommState ();
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
static BOOL CheckComm () {
|
||||||
|
comminactivity = 0;
|
||||||
|
if ((commhandle == INVALID_HANDLE_VALUE) && serialport) {
|
||||||
|
TCHAR portname[8];
|
||||||
|
wsprintf(portname,
|
||||||
|
TEXT("COM%u"),
|
||||||
|
serialport);
|
||||||
|
commhandle = CreateFile(portname,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
(LPSECURITY_ATTRIBUTES)NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
NULL);
|
||||||
|
if (commhandle != INVALID_HANDLE_VALUE) {
|
||||||
|
UpdateCommState();
|
||||||
|
COMMTIMEOUTS ct;
|
||||||
|
ZeroMemory(&ct,sizeof(COMMTIMEOUTS));
|
||||||
|
ct.ReadIntervalTimeout = MAXDWORD;
|
||||||
|
SetCommTimeouts(commhandle,&ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (commhandle != INVALID_HANDLE_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
static void CheckReceive () {
|
||||||
|
if (recvbytes || (commhandle == INVALID_HANDLE_VALUE))
|
||||||
|
return;
|
||||||
|
ReadFile(commhandle,recvbuffer,8,&recvbytes,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
static void CloseComm () {
|
||||||
|
if (commhandle != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle(commhandle);
|
||||||
|
commhandle = INVALID_HANDLE_VALUE;
|
||||||
|
comminactivity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
static void UpdateCommState () {
|
||||||
|
if (commhandle == INVALID_HANDLE_VALUE)
|
||||||
|
return;
|
||||||
|
DCB dcb;
|
||||||
|
ZeroMemory(&dcb,sizeof(DCB));
|
||||||
|
dcb.DCBlength = sizeof(DCB);
|
||||||
|
GetCommState(commhandle,&dcb);
|
||||||
|
dcb.BaudRate = baudrate;
|
||||||
|
dcb.ByteSize = bytesize;
|
||||||
|
dcb.Parity = parity;
|
||||||
|
dcb.StopBits = stopbits;
|
||||||
|
SetCommState(commhandle,&dcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall CommCommand (WORD, BYTE, BYTE write, BYTE value, ULONG) {
|
||||||
|
if (!CheckComm())
|
||||||
|
return 0;
|
||||||
|
if (write && (value != commandbyte)) {
|
||||||
|
commandbyte = value;
|
||||||
|
|
||||||
|
// UPDATE THE PARITY
|
||||||
|
if (commandbyte & 0x20)
|
||||||
|
switch (commandbyte & 0xC0) {
|
||||||
|
case 0x00 : parity = ODDPARITY; break;
|
||||||
|
case 0x40 : parity = EVENPARITY; break;
|
||||||
|
case 0x80 : parity = MARKPARITY; break;
|
||||||
|
case 0xC0 : parity = SPACEPARITY; break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
parity = NOPARITY;
|
||||||
|
|
||||||
|
UpdateCommState();
|
||||||
|
}
|
||||||
|
return commandbyte;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall CommControl (WORD, BYTE, BYTE write, BYTE value, ULONG) {
|
||||||
|
if (!CheckComm())
|
||||||
|
return 0;
|
||||||
|
if (write && (value != controlbyte)) {
|
||||||
|
controlbyte = value;
|
||||||
|
|
||||||
|
// UPDATE THE BAUD RATE
|
||||||
|
switch (controlbyte & 0x0F) {
|
||||||
|
case 0x00: // fall through
|
||||||
|
case 0x01: // fall through
|
||||||
|
case 0x02: // fall through
|
||||||
|
case 0x03: // fall through
|
||||||
|
case 0x04: // fall through
|
||||||
|
case 0x05: baudrate = CBR_110; break;
|
||||||
|
case 0x06: baudrate = CBR_300; break;
|
||||||
|
case 0x07: baudrate = CBR_600; break;
|
||||||
|
case 0x08: baudrate = CBR_1200; break;
|
||||||
|
case 0x09: // fall through
|
||||||
|
case 0x0A: baudrate = CBR_2400; break;
|
||||||
|
case 0x0B: // fall through
|
||||||
|
case 0x0C: baudrate = CBR_4800; break;
|
||||||
|
case 0x0D: // fall through
|
||||||
|
case 0x0E: baudrate = CBR_9600; break;
|
||||||
|
case 0x0F: baudrate = CBR_19200; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPDATE THE BYTE SIZE
|
||||||
|
switch (controlbyte & 0x60) {
|
||||||
|
case 0x00: bytesize = 8; break;
|
||||||
|
case 0x20: bytesize = 7; break;
|
||||||
|
case 0x40: bytesize = 6; break;
|
||||||
|
case 0x60: bytesize = 5; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPDATE THE NUMBER OF STOP BITS
|
||||||
|
if (controlbyte & 0x80) {
|
||||||
|
if ((bytesize == 8) && (parity == NOPARITY))
|
||||||
|
stopbits = ONESTOPBIT;
|
||||||
|
else if ((bytesize == 5) && (parity == NOPARITY))
|
||||||
|
stopbits = ONE5STOPBITS;
|
||||||
|
else
|
||||||
|
stopbits = TWOSTOPBITS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
stopbits = ONESTOPBIT;
|
||||||
|
|
||||||
|
UpdateCommState();
|
||||||
|
}
|
||||||
|
return controlbyte;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CommDestroy () {
|
||||||
|
if ((baudrate != CBR_19200) ||
|
||||||
|
(bytesize != 8) ||
|
||||||
|
(parity != NOPARITY) ||
|
||||||
|
(stopbits != ONESTOPBIT)) {
|
||||||
|
CommReset();
|
||||||
|
CheckComm();
|
||||||
|
}
|
||||||
|
CloseComm();
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall CommDipSw (WORD, BYTE, BYTE, BYTE, ULONG) {
|
||||||
|
// note: determine what values a real SSC returns
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CommSetSerialPort (HWND window, DWORD newserialport) {
|
||||||
|
if (commhandle == INVALID_HANDLE_VALUE)
|
||||||
|
serialport = newserialport;
|
||||||
|
else
|
||||||
|
MessageBox(window,
|
||||||
|
TEXT("You cannot change the serial port while it is ")
|
||||||
|
TEXT("in use."),
|
||||||
|
TEXT("Configuration"),
|
||||||
|
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CommUpdate (DWORD totalcycles) {
|
||||||
|
if (commhandle == INVALID_HANDLE_VALUE)
|
||||||
|
return;
|
||||||
|
if ((comminactivity += totalcycles) > 1000000) {
|
||||||
|
static DWORD lastcheck = 0;
|
||||||
|
if ((comminactivity > 2000000) || (comminactivity-lastcheck > 99950)) {
|
||||||
|
DWORD modemstatus = 0;
|
||||||
|
GetCommModemStatus(commhandle,&modemstatus);
|
||||||
|
if ((modemstatus & MS_RLSD_ON) || DiskIsSpinning())
|
||||||
|
comminactivity = 0;
|
||||||
|
}
|
||||||
|
if (comminactivity > 2000000)
|
||||||
|
CloseComm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall CommReceive (WORD, BYTE, BYTE, BYTE, ULONG) {
|
||||||
|
if (!CheckComm())
|
||||||
|
return 0;
|
||||||
|
if (!recvbytes)
|
||||||
|
CheckReceive();
|
||||||
|
BYTE result = 0;
|
||||||
|
if (recvbytes) {
|
||||||
|
result = recvbuffer[0];
|
||||||
|
if (--recvbytes)
|
||||||
|
MoveMemory(recvbuffer,recvbuffer+1,recvbytes);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
void CommReset () {
|
||||||
|
CloseComm();
|
||||||
|
baudrate = CBR_19200;
|
||||||
|
bytesize = 8;
|
||||||
|
commandbyte = 0x00;
|
||||||
|
controlbyte = 0x1F;
|
||||||
|
parity = NOPARITY;
|
||||||
|
recvbytes = 0;
|
||||||
|
stopbits = ONESTOPBIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall CommStatus (WORD, BYTE, BYTE, BYTE, ULONG) {
|
||||||
|
if (!CheckComm())
|
||||||
|
return 0x70;
|
||||||
|
if (!recvbytes)
|
||||||
|
CheckReceive();
|
||||||
|
DWORD modemstatus = 0;
|
||||||
|
GetCommModemStatus(commhandle,&modemstatus);
|
||||||
|
return 0x10 | (recvbytes ? 0x08 : 0x00)
|
||||||
|
| ((modemstatus & MS_RLSD_ON) ? 0x00 : 0x20)
|
||||||
|
| ((modemstatus & MS_DSR_ON) ? 0x00 : 0x40);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
BYTE __stdcall CommTransmit (WORD, BYTE, BYTE, BYTE value, ULONG) {
|
||||||
|
if (!CheckComm())
|
||||||
|
return 0;
|
||||||
|
DWORD byteswritten;
|
||||||
|
WriteFile(commhandle,&value,1,&byteswritten,NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
DWORD CommGetSnapshot(SS_IO_Comms* pSS)
|
||||||
|
{
|
||||||
|
pSS->baudrate = baudrate;
|
||||||
|
pSS->bytesize = bytesize;
|
||||||
|
pSS->commandbyte = commandbyte;
|
||||||
|
pSS->comminactivity = comminactivity;
|
||||||
|
pSS->controlbyte = controlbyte;
|
||||||
|
pSS->parity = parity;
|
||||||
|
memcpy(pSS->recvbuffer, recvbuffer, 9);
|
||||||
|
pSS->recvbytes = recvbytes;
|
||||||
|
pSS->stopbits = stopbits;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD CommSetSnapshot(SS_IO_Comms* pSS)
|
||||||
|
{
|
||||||
|
baudrate = pSS->baudrate;
|
||||||
|
bytesize = pSS->bytesize;
|
||||||
|
commandbyte = pSS->commandbyte;
|
||||||
|
comminactivity = pSS->comminactivity;
|
||||||
|
controlbyte = pSS->controlbyte;
|
||||||
|
parity = pSS->parity;
|
||||||
|
memcpy(recvbuffer, pSS->recvbuffer, 9);
|
||||||
|
recvbytes = pSS->recvbytes;
|
||||||
|
stopbits = pSS->stopbits;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern DWORD serialport;
|
||||||
|
|
||||||
|
void CommDestroy ();
|
||||||
|
void CommReset ();
|
||||||
|
void CommSetSerialPort (HWND,DWORD);
|
||||||
|
void CommUpdate (DWORD);
|
||||||
|
DWORD CommGetSnapshot(SS_IO_Comms* pSS);
|
||||||
|
DWORD CommSetSnapshot(SS_IO_Comms* pSS);
|
||||||
|
|
||||||
|
BYTE __stdcall CommCommand (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall CommControl (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall CommDipSw (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall CommReceive (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall CommStatus (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall CommTransmit (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
|
@ -0,0 +1,645 @@
|
||||||
|
/*
|
||||||
|
AppleWin : An Apple //e emulator for Windows
|
||||||
|
|
||||||
|
Copyright (C) 1994-1996, Michael O'Brien
|
||||||
|
Copyright (C) 1999-2001, Oliver Schmidt
|
||||||
|
Copyright (C) 2002-2005, Tom Charlesworth
|
||||||
|
Copyright (C) 2006, Tom Charlesworth, Michael Pohoreski
|
||||||
|
|
||||||
|
AppleWin is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
AppleWin is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with AppleWin; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Description: Core sound related functionality
|
||||||
|
*
|
||||||
|
* Author: Tom Charlesworth
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "StdAfx.h"
|
||||||
|
#pragma hdrstop
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define MAX_SOUND_DEVICES 10
|
||||||
|
|
||||||
|
static char *sound_devices[MAX_SOUND_DEVICES];
|
||||||
|
static GUID sound_device_guid[MAX_SOUND_DEVICES];
|
||||||
|
static int num_sound_devices = 0;
|
||||||
|
|
||||||
|
static LPDIRECTSOUND g_lpDS = NULL;
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
// Used for muting & fading:
|
||||||
|
|
||||||
|
static const UINT uMAX_VOICES = 66; // 64 phonemes + spkr + mockingboard
|
||||||
|
static UINT g_uNumVoices = 0;
|
||||||
|
static VOICE* g_pVoices[uMAX_VOICES] = {NULL};
|
||||||
|
|
||||||
|
static VOICE* g_pSpeakerVoice = NULL;
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
bool g_bDSAvailable = false;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext)
|
||||||
|
{
|
||||||
|
int i = num_sound_devices;
|
||||||
|
if(i == MAX_SOUND_DEVICES)
|
||||||
|
return TRUE;
|
||||||
|
if(lpGUID != NULL)
|
||||||
|
memcpy(&sound_device_guid[i], lpGUID, sizeof (GUID));
|
||||||
|
sound_devices[i] = strdup(lpszDesc);
|
||||||
|
|
||||||
|
if(g_fh) fprintf(g_fh, "%d: %s - %s\n",i,lpszDesc,lpszDrvName);
|
||||||
|
|
||||||
|
num_sound_devices++;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
static char *DirectSound_ErrorText (HRESULT error)
|
||||||
|
{
|
||||||
|
switch( error )
|
||||||
|
{
|
||||||
|
case DSERR_ALLOCATED:
|
||||||
|
return "Allocated";
|
||||||
|
case DSERR_CONTROLUNAVAIL:
|
||||||
|
return "Control Unavailable";
|
||||||
|
case DSERR_INVALIDPARAM:
|
||||||
|
return "Invalid Parameter";
|
||||||
|
case DSERR_INVALIDCALL:
|
||||||
|
return "Invalid Call";
|
||||||
|
case DSERR_GENERIC:
|
||||||
|
return "Generic";
|
||||||
|
case DSERR_PRIOLEVELNEEDED:
|
||||||
|
return "Priority Level Needed";
|
||||||
|
case DSERR_OUTOFMEMORY:
|
||||||
|
return "Out of Memory";
|
||||||
|
case DSERR_BADFORMAT:
|
||||||
|
return "Bad Format";
|
||||||
|
case DSERR_UNSUPPORTED:
|
||||||
|
return "Unsupported";
|
||||||
|
case DSERR_NODRIVER:
|
||||||
|
return "No Driver";
|
||||||
|
case DSERR_ALREADYINITIALIZED:
|
||||||
|
return "Already Initialized";
|
||||||
|
case DSERR_NOAGGREGATION:
|
||||||
|
return "No Aggregation";
|
||||||
|
case DSERR_BUFFERLOST:
|
||||||
|
return "Buffer Lost";
|
||||||
|
case DSERR_OTHERAPPHASPRIO:
|
||||||
|
return "Other Application Has Priority";
|
||||||
|
case DSERR_UNINITIALIZED:
|
||||||
|
return "Uninitialized";
|
||||||
|
case DSERR_NOINTERFACE:
|
||||||
|
return "No Interface";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool DSGetLock(LPDIRECTSOUNDBUFFER pVoice, DWORD dwOffset, DWORD dwBytes,
|
||||||
|
SHORT** ppDSLockedBuffer0, DWORD* pdwDSLockedBufferSize0,
|
||||||
|
SHORT** ppDSLockedBuffer1, DWORD* pdwDSLockedBufferSize1)
|
||||||
|
{
|
||||||
|
DWORD nStatus;
|
||||||
|
HRESULT hr = pVoice->GetStatus(&nStatus);
|
||||||
|
if(hr != DS_OK)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(nStatus & DSBSTATUS_BUFFERLOST)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
hr = pVoice->Restore();
|
||||||
|
if(hr == DSERR_BUFFERLOST)
|
||||||
|
Sleep(10);
|
||||||
|
}
|
||||||
|
while(hr != DS_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get write only pointer(s) to sound buffer
|
||||||
|
if(dwBytes == 0)
|
||||||
|
{
|
||||||
|
if(FAILED(hr = pVoice->Lock(0, 0,
|
||||||
|
(void**)ppDSLockedBuffer0, pdwDSLockedBufferSize0,
|
||||||
|
(void**)ppDSLockedBuffer1, pdwDSLockedBufferSize1,
|
||||||
|
DSBLOCK_ENTIREBUFFER)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(FAILED(hr = pVoice->Lock(dwOffset, dwBytes,
|
||||||
|
(void**)ppDSLockedBuffer0, pdwDSLockedBufferSize0,
|
||||||
|
(void**)ppDSLockedBuffer1, pdwDSLockedBufferSize1,
|
||||||
|
0)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
HRESULT DSGetSoundBuffer(VOICE* pVoice, DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels)
|
||||||
|
{
|
||||||
|
WAVEFORMATEX wavfmt;
|
||||||
|
DSBUFFERDESC dsbdesc;
|
||||||
|
|
||||||
|
wavfmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
wavfmt.nChannels = nChannels;
|
||||||
|
wavfmt.nSamplesPerSec = nSampleRate;
|
||||||
|
wavfmt.wBitsPerSample = 16;
|
||||||
|
wavfmt.nBlockAlign = wavfmt.nChannels==1 ? 2 : 4;
|
||||||
|
wavfmt.nAvgBytesPerSec = wavfmt.nBlockAlign * wavfmt.nSamplesPerSec;
|
||||||
|
|
||||||
|
memset (&dsbdesc, 0, sizeof (dsbdesc));
|
||||||
|
dsbdesc.dwSize = sizeof (dsbdesc);
|
||||||
|
dsbdesc.dwBufferBytes = dwBufferSize;
|
||||||
|
dsbdesc.lpwfxFormat = &wavfmt;
|
||||||
|
dsbdesc.dwFlags = dwFlags | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS;
|
||||||
|
|
||||||
|
// Are buffers released when g_lpDS OR pVoice->lpDSBvoice is released?
|
||||||
|
// . From DirectX doc:
|
||||||
|
// "Buffer objects are owned by the device object that created them. When the
|
||||||
|
// device object is released, all buffers created by that object are also released..."
|
||||||
|
HRESULT hr = g_lpDS->CreateSoundBuffer(&dsbdesc, &pVoice->lpDSBvoice, NULL);
|
||||||
|
if(FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
_ASSERT(g_uNumVoices < uMAX_VOICES);
|
||||||
|
if(g_uNumVoices < uMAX_VOICES)
|
||||||
|
g_pVoices[g_uNumVoices++] = pVoice;
|
||||||
|
|
||||||
|
if(pVoice->bIsSpeaker)
|
||||||
|
g_pSpeakerVoice = pVoice;
|
||||||
|
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSReleaseSoundBuffer(VOICE* pVoice)
|
||||||
|
{
|
||||||
|
if(pVoice->bIsSpeaker)
|
||||||
|
g_pSpeakerVoice = NULL;
|
||||||
|
|
||||||
|
for(UINT i=0; i<g_uNumVoices; i++)
|
||||||
|
{
|
||||||
|
if(g_pVoices[i] == pVoice)
|
||||||
|
{
|
||||||
|
g_pVoices[i] = g_pVoices[g_uNumVoices-1];
|
||||||
|
g_pVoices[g_uNumVoices-1] = NULL;
|
||||||
|
g_uNumVoices--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_RELEASE(pVoice->lpDSBvoice);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool DSZeroVoiceBuffer(PVOICE Voice, char* pszDevName, DWORD dwBufferSize)
|
||||||
|
{
|
||||||
|
DWORD dwDSLockedBufferSize = 0; // Size of the locked DirectSound buffer
|
||||||
|
SHORT* pDSLockedBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT hr = Voice->lpDSBvoice->Stop();
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
if(g_fh) fprintf(g_fh, "%s: DSStop failed (%08X)\n",pszDevName,hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = DSGetLock(Voice->lpDSBvoice, 0, 0, &pDSLockedBuffer, &dwDSLockedBufferSize, NULL, 0);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
if(g_fh) fprintf(g_fh, "%s: DSGetLock failed (%08X)\n",pszDevName,hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ASSERT(dwDSLockedBufferSize == dwBufferSize);
|
||||||
|
memset(pDSLockedBuffer, 0x00, dwDSLockedBufferSize);
|
||||||
|
|
||||||
|
hr = Voice->lpDSBvoice->Unlock((void*)pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
if(g_fh) fprintf(g_fh, "%s: DSUnlock failed (%08X)\n",pszDevName,hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = Voice->lpDSBvoice->Play(0,0,DSBPLAY_LOOPING);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
if(g_fh) fprintf(g_fh, "%s: DSPlay failed (%08X)\n",pszDevName,hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool DSZeroVoiceWritableBuffer(PVOICE Voice, char* pszDevName, DWORD dwBufferSize)
|
||||||
|
{
|
||||||
|
DWORD dwDSLockedBufferSize0=0, dwDSLockedBufferSize1=0;
|
||||||
|
SHORT *pDSLockedBuffer0, *pDSLockedBuffer1;
|
||||||
|
|
||||||
|
|
||||||
|
HRESULT hr = DSGetLock(Voice->lpDSBvoice,
|
||||||
|
0, dwBufferSize,
|
||||||
|
&pDSLockedBuffer0, &dwDSLockedBufferSize0,
|
||||||
|
&pDSLockedBuffer1, &dwDSLockedBufferSize1);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
if(g_fh) fprintf(g_fh, "%s: DSGetLock failed (%08X)\n",pszDevName,hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(pDSLockedBuffer0, 0x00, dwDSLockedBufferSize0);
|
||||||
|
if(pDSLockedBuffer1)
|
||||||
|
memset(pDSLockedBuffer1, 0x00, dwDSLockedBufferSize1);
|
||||||
|
|
||||||
|
hr = Voice->lpDSBvoice->Unlock((void*)pDSLockedBuffer0, dwDSLockedBufferSize0,
|
||||||
|
(void*)pDSLockedBuffer1, dwDSLockedBufferSize1);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
if(g_fh) fprintf(g_fh, "%s: DSUnlock failed (%08X)\n",pszDevName,hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static bool g_bTimerActive = false;
|
||||||
|
static eFADE g_FadeType = FADE_NONE;
|
||||||
|
static UINT_PTR g_nTimerID = 0;
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
static VOID CALLBACK SoundCore_TimerFunc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
|
||||||
|
|
||||||
|
static bool SoundCore_StartTimer()
|
||||||
|
{
|
||||||
|
if(g_bTimerActive)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
g_nTimerID = SetTimer(NULL, 0, 1, SoundCore_TimerFunc); // 1ms interval
|
||||||
|
if(g_nTimerID == 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error creating timer\n");
|
||||||
|
_ASSERT(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_bTimerActive = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SoundCore_StopTimer()
|
||||||
|
{
|
||||||
|
if(!g_bTimerActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(KillTimer(NULL, g_nTimerID) == FALSE)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error killing timer\n");
|
||||||
|
_ASSERT(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_bTimerActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SoundCore_GetTimerState()
|
||||||
|
{
|
||||||
|
return g_bTimerActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
// [OLD: Used to fade volume in/out]
|
||||||
|
// FADE_OUT : Just keep filling speaker soundbuffer with same value
|
||||||
|
// FADE_IN : Switch to FADE_NONE & StopTimer()
|
||||||
|
|
||||||
|
static VOID CALLBACK SoundCore_TimerFunc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
||||||
|
{
|
||||||
|
if((g_pSpeakerVoice == NULL) || (g_pSpeakerVoice->bActive == false))
|
||||||
|
g_FadeType = FADE_NONE;
|
||||||
|
|
||||||
|
// Timer expired
|
||||||
|
if(g_FadeType == FADE_NONE)
|
||||||
|
{
|
||||||
|
SoundCore_StopTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
if(g_FadeType == FADE_IN)
|
||||||
|
g_FadeType = FADE_NONE;
|
||||||
|
else
|
||||||
|
SpkrUpdate_Timer();
|
||||||
|
#else
|
||||||
|
const LONG nFadeUnit_Fast = (DSBVOLUME_MAX - DSBVOLUME_MIN) / 10;
|
||||||
|
const LONG nFadeUnit_Slow = (DSBVOLUME_MAX - DSBVOLUME_MIN) / 1000; // Less noisy for 'silence'
|
||||||
|
|
||||||
|
LONG nFadeUnit = g_pSpeakerVoice->bRecentlyActive ? nFadeUnit_Fast : nFadeUnit_Slow;
|
||||||
|
LONG nFadeVolume = g_pSpeakerVoice->nFadeVolume;
|
||||||
|
|
||||||
|
if(g_FadeType == FADE_IN)
|
||||||
|
{
|
||||||
|
if(nFadeVolume == g_pSpeakerVoice->nVolume)
|
||||||
|
{
|
||||||
|
g_FadeType = FADE_NONE;
|
||||||
|
SoundCore_StopTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nFadeVolume += nFadeUnit;
|
||||||
|
|
||||||
|
if(nFadeVolume > g_pSpeakerVoice->nVolume)
|
||||||
|
nFadeVolume = g_pSpeakerVoice->nVolume;
|
||||||
|
}
|
||||||
|
else // FADE_OUT
|
||||||
|
{
|
||||||
|
if(nFadeVolume == DSBVOLUME_MIN)
|
||||||
|
{
|
||||||
|
g_FadeType = FADE_NONE;
|
||||||
|
SoundCore_StopTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nFadeVolume -= nFadeUnit;
|
||||||
|
|
||||||
|
if(nFadeVolume < DSBVOLUME_MIN)
|
||||||
|
nFadeVolume = DSBVOLUME_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_pSpeakerVoice->nFadeVolume = nFadeVolume;
|
||||||
|
g_pSpeakerVoice->lpDSBvoice->SetVolume(nFadeVolume);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void SoundCore_SetFade(eFADE FadeType)
|
||||||
|
{
|
||||||
|
static int nLastMode = -1;
|
||||||
|
|
||||||
|
if(mode == MODE_DEBUG)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Fade in/out just for speaker, the others are demuted/muted
|
||||||
|
if(FadeType != FADE_NONE)
|
||||||
|
{
|
||||||
|
for(UINT i=0; i<g_uNumVoices; i++)
|
||||||
|
{
|
||||||
|
// Note: Kludge for fading speaker if curr/last mode is/was MODE_LOGO:
|
||||||
|
// . Bug in DirectSound? SpeakerVoice.lpDSBvoice->SetVolume() doesn't work without this!
|
||||||
|
if((g_pVoices[i]->bIsSpeaker) && (mode != MODE_LOGO) && (nLastMode != MODE_LOGO))
|
||||||
|
{
|
||||||
|
g_pVoices[i]->lpDSBvoice->GetVolume(&g_pVoices[i]->nFadeVolume);
|
||||||
|
g_FadeType = FadeType;
|
||||||
|
SoundCore_StartTimer();
|
||||||
|
}
|
||||||
|
else if(FadeType == FADE_OUT)
|
||||||
|
{
|
||||||
|
g_pVoices[i]->lpDSBvoice->SetVolume(DSBVOLUME_MIN);
|
||||||
|
g_pVoices[i]->bMute = true;
|
||||||
|
}
|
||||||
|
else // FADE_IN
|
||||||
|
{
|
||||||
|
g_pVoices[i]->lpDSBvoice->SetVolume(g_pVoices[i]->nVolume);
|
||||||
|
g_pVoices[i]->bMute = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // FadeType == FADE_NONE
|
||||||
|
{
|
||||||
|
if( (g_FadeType != FADE_NONE) && // Currently fading-in/out
|
||||||
|
(g_pSpeakerVoice && g_pSpeakerVoice->bActive) )
|
||||||
|
{
|
||||||
|
g_FadeType = FADE_NONE; // TimerFunc will call StopTimer()
|
||||||
|
g_pSpeakerVoice->lpDSBvoice->SetVolume(g_pSpeakerVoice->nVolume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nLastMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static UINT g_uDSInitRefCount = 0;
|
||||||
|
|
||||||
|
bool DSInit()
|
||||||
|
{
|
||||||
|
if(g_bDSAvailable)
|
||||||
|
{
|
||||||
|
g_uDSInitRefCount++;
|
||||||
|
return true; // Already initialised successfully
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT hr = DirectSoundEnumerate((LPDSENUMCALLBACK)DSEnumProc, NULL);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
if(g_fh) fprintf(g_fh, "DSEnumerate failed (%08X)\n",hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(g_fh)
|
||||||
|
{
|
||||||
|
fprintf(g_fh, "Number of sound devices = %d\n",num_sound_devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bCreatedOK = false;
|
||||||
|
for(int x=0; x<num_sound_devices; x++)
|
||||||
|
{
|
||||||
|
hr = DirectSoundCreate(&sound_device_guid[x], &g_lpDS, NULL);
|
||||||
|
if(SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
if(g_fh) fprintf(g_fh, "DSCreate succeeded for sound device #%d\n",x);
|
||||||
|
bCreatedOK = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(g_fh) fprintf(g_fh, "DSCreate failed for sound device #%d (%08X)\n",x,hr);
|
||||||
|
}
|
||||||
|
if(!bCreatedOK)
|
||||||
|
{
|
||||||
|
if(g_fh) fprintf(g_fh, "DSCreate failed for all sound devices\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = g_lpDS->SetCooperativeLevel(framewindow, DSSCL_NORMAL);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
if(g_fh) fprintf(g_fh, "SetCooperativeLevel failed (%08X)\n",hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
DSCAPS DSCaps;
|
||||||
|
ZeroMemory(&DSCaps, sizeof(DSBCAPS));
|
||||||
|
DSCaps.dwSize = sizeof(DSBCAPS);
|
||||||
|
hr = g_lpDS->GetCaps(&DSCaps);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
DirectSound_ErrorText(hr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
g_bDSAvailable = true;
|
||||||
|
|
||||||
|
g_uDSInitRefCount = 1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void DSUninit()
|
||||||
|
{
|
||||||
|
if(!g_bDSAvailable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_ASSERT(g_uDSInitRefCount);
|
||||||
|
|
||||||
|
if(g_uDSInitRefCount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_uDSInitRefCount--;
|
||||||
|
|
||||||
|
if(g_uDSInitRefCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
_ASSERT(g_uNumVoices == 0);
|
||||||
|
|
||||||
|
SAFE_RELEASE(g_lpDS);
|
||||||
|
g_bDSAvailable = false;
|
||||||
|
|
||||||
|
SoundCore_StopTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
LONG NewVolume(DWORD dwVolume, DWORD dwVolumeMax)
|
||||||
|
{
|
||||||
|
float fVol = (float) dwVolume / (float) dwVolumeMax; // 0.0=Max, 1.0=Min
|
||||||
|
|
||||||
|
return (LONG) ((float) DSBVOLUME_MIN * fVol);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
static DWORD g_dwAdviseToken;
|
||||||
|
static IReferenceClock *g_pRefClock = NULL;
|
||||||
|
static HANDLE g_hSemaphore = NULL;
|
||||||
|
static bool g_bRefClockTimerActive = false;
|
||||||
|
static DWORD g_dwLastUsecPeriod = 0;
|
||||||
|
|
||||||
|
|
||||||
|
void SysClk_InitTimer()
|
||||||
|
{
|
||||||
|
g_hSemaphore = CreateSemaphore(NULL, 0, 1, NULL); // Max count = 1
|
||||||
|
if (g_hSemaphore == NULL)
|
||||||
|
fprintf(stderr, "Error creating semaphore\n");
|
||||||
|
|
||||||
|
if (CoCreateInstance(CLSID_SystemClock, NULL, CLSCTX_INPROC,
|
||||||
|
IID_IReferenceClock, (LPVOID*)&g_pRefClock) != S_OK)
|
||||||
|
fprintf(stderr, "Error initialising COM\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysClk_UninitTimer()
|
||||||
|
{
|
||||||
|
SysClk_StopTimer();
|
||||||
|
|
||||||
|
SAFE_RELEASE(g_pRefClock);
|
||||||
|
|
||||||
|
if (CloseHandle(g_hSemaphore) == 0)
|
||||||
|
fprintf(stderr, "Error closing semaphore handle\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void SysClk_WaitTimer()
|
||||||
|
{
|
||||||
|
if(!g_bRefClockTimerActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
WaitForSingleObject(g_hSemaphore, INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
void SysClk_StartTimerUsec(DWORD dwUsecPeriod)
|
||||||
|
{
|
||||||
|
if(g_bRefClockTimerActive && (g_dwLastUsecPeriod == dwUsecPeriod))
|
||||||
|
return;
|
||||||
|
|
||||||
|
SysClk_StopTimer();
|
||||||
|
|
||||||
|
REFERENCE_TIME rtPeriod = (REFERENCE_TIME) (dwUsecPeriod * 10); // In units of 100ns
|
||||||
|
REFERENCE_TIME rtNow;
|
||||||
|
|
||||||
|
HRESULT hr = g_pRefClock->GetTime(&rtNow);
|
||||||
|
// S_FALSE : Returned time is the same as the previous value
|
||||||
|
|
||||||
|
if ((hr != S_OK) && (hr != S_FALSE))
|
||||||
|
{
|
||||||
|
_ASSERT(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_pRefClock->AdvisePeriodic(rtNow, rtPeriod, g_hSemaphore, &g_dwAdviseToken) != S_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error creating timer\n");
|
||||||
|
_ASSERT(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_dwLastUsecPeriod = dwUsecPeriod;
|
||||||
|
g_bRefClockTimerActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysClk_StopTimer()
|
||||||
|
{
|
||||||
|
if(!g_bRefClockTimerActive)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (g_pRefClock->Unadvise(g_dwAdviseToken) != S_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error deleting timer\n");
|
||||||
|
_ASSERT(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_bRefClockTimerActive = false;
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
|
||||||
|
|
||||||
|
// Define max 1 of these:
|
||||||
|
//#define RIFF_SPKR
|
||||||
|
//#define RIFF_MB
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
LPDIRECTSOUNDBUFFER lpDSBvoice;
|
||||||
|
LPDIRECTSOUNDNOTIFY lpDSNotify;
|
||||||
|
bool bActive; // Playback is active
|
||||||
|
bool bMute;
|
||||||
|
LONG nVolume; // Current volume (as used by DirectSound)
|
||||||
|
LONG nFadeVolume; // Current fade volume (as used by DirectSound)
|
||||||
|
DWORD dwUserVolume; // Volume from slider on Property Sheet (0=Max)
|
||||||
|
bool bIsSpeaker;
|
||||||
|
bool bRecentlyActive; // (Speaker only) false after 0.2s of speaker inactivity
|
||||||
|
} VOICE, *PVOICE;
|
||||||
|
|
||||||
|
|
||||||
|
bool DSGetLock(LPDIRECTSOUNDBUFFER pVoice, DWORD dwOffset, DWORD dwBytes,
|
||||||
|
SHORT** ppDSLockedBuffer0, DWORD* pdwDSLockedBufferSize0,
|
||||||
|
SHORT** ppDSLockedBuffer1, DWORD* pdwDSLockedBufferSize1);
|
||||||
|
|
||||||
|
HRESULT DSGetSoundBuffer(VOICE* pVoice, DWORD dwFlags, DWORD dwBufferSize, DWORD nSampleRate, int nChannels);
|
||||||
|
void DSReleaseSoundBuffer(VOICE* pVoice);
|
||||||
|
|
||||||
|
bool DSZeroVoiceBuffer(PVOICE Voice, char* pszDevName, DWORD dwBufferSize);
|
||||||
|
bool DSZeroVoiceWritableBuffer(PVOICE Voice, char* pszDevName, DWORD dwBufferSize);
|
||||||
|
|
||||||
|
enum eFADE {FADE_NONE, FADE_IN, FADE_OUT};
|
||||||
|
void SoundCore_SetFade(eFADE FadeType);
|
||||||
|
bool SoundCore_GetTimerState();
|
||||||
|
|
||||||
|
bool DSInit();
|
||||||
|
void DSUninit();
|
||||||
|
|
||||||
|
LONG NewVolume(DWORD dwVolume, DWORD dwVolumeMax);
|
||||||
|
|
||||||
|
void SysClk_WaitTimer();
|
||||||
|
void SysClk_InitTimer();
|
||||||
|
void SysClk_UninitTimer();
|
||||||
|
void SysClk_StartTimerUsec(DWORD dwUsecPeriod);
|
||||||
|
void SysClk_StopTimer();
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
extern bool g_bDSAvailable;
|
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern DWORD soundtype;
|
||||||
|
extern double g_fClksPerSpkrSample;
|
||||||
|
|
||||||
|
void SpkrDestroy ();
|
||||||
|
void SpkrInitialize ();
|
||||||
|
void SpkrReinitialize ();
|
||||||
|
void SpkrReset();
|
||||||
|
BOOL SpkrSetEmulationType (HWND,DWORD);
|
||||||
|
void SpkrUpdate (DWORD);
|
||||||
|
void SpkrUpdate_Timer();
|
||||||
|
DWORD SpkrGetVolume();
|
||||||
|
void SpkrSetVolume(DWORD dwVolume, DWORD dwVolumeMax);
|
||||||
|
void Spkr_Mute();
|
||||||
|
void Spkr_Demute();
|
||||||
|
bool Spkr_IsActive();
|
||||||
|
bool Spkr_DSInit();
|
||||||
|
void Spkr_DSUninit();
|
||||||
|
DWORD SpkrGetSnapshot(SS_IO_Speaker* pSS);
|
||||||
|
DWORD SpkrSetSnapshot(SS_IO_Speaker* pSS);
|
||||||
|
|
||||||
|
BYTE __stdcall SpkrToggle (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include <crtdbg.h>
|
||||||
|
#include <dsound.h>
|
||||||
|
#include <dshow.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <commctrl.h>
|
||||||
|
#include <ddraw.h>
|
||||||
|
#include <htmlhelp.h>
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "Structs.h"
|
||||||
|
|
||||||
|
#include "AppleWin.h"
|
||||||
|
#include "AY8910.h"
|
||||||
|
#include "CPU.h"
|
||||||
|
#include "Debug.h"
|
||||||
|
#include "Disk.h"
|
||||||
|
#include "DiskImage.h"
|
||||||
|
#include "Frame.h"
|
||||||
|
#include "Harddisk.h"
|
||||||
|
#include "Joystick.h"
|
||||||
|
#include "Keyboard.h"
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "Mockingboard.h"
|
||||||
|
#include "PropertySheetPage.h"
|
||||||
|
#include "Registry.h"
|
||||||
|
#include "Riff.h"
|
||||||
|
#include "SaveState.h"
|
||||||
|
#include "SerialComms.h"
|
||||||
|
#include "SoundCore.h"
|
||||||
|
#include "Speaker.h"
|
||||||
|
#include "Video.h"
|
|
@ -0,0 +1,273 @@
|
||||||
|
//
|
||||||
|
|
||||||
|
#define MAKE_VERSION(a,b,c,d) ((a<<24) | (b<<16) | (c<<8) | (d))
|
||||||
|
|
||||||
|
#define AW_SS_TAG 'SSWA' // 'AWSS' = AppleWin SnapShot
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
DWORD dwTag; // "AWSS"
|
||||||
|
DWORD dwVersion;
|
||||||
|
DWORD dwChecksum;
|
||||||
|
} SS_FILE_HDR;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
DWORD dwLength; // Byte length of this unit struct
|
||||||
|
DWORD dwVersion;
|
||||||
|
} SS_UNIT_HDR;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const UINT nMemMainSize = 64*1024;
|
||||||
|
const UINT nMemAuxSize = 64*1024;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
BYTE A;
|
||||||
|
BYTE X;
|
||||||
|
BYTE Y;
|
||||||
|
BYTE P;
|
||||||
|
BYTE S;
|
||||||
|
USHORT PC;
|
||||||
|
unsigned __int64 g_nCumulativeCycles;
|
||||||
|
// IRQ = OR-sum of all interrupt sources
|
||||||
|
} SS_CPU6502;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
DWORD baudrate;
|
||||||
|
BYTE bytesize;
|
||||||
|
BYTE commandbyte;
|
||||||
|
DWORD comminactivity; // If non-zero then COM port open
|
||||||
|
BYTE controlbyte;
|
||||||
|
BYTE parity;
|
||||||
|
BYTE recvbuffer[9];
|
||||||
|
DWORD recvbytes;
|
||||||
|
BYTE stopbits;
|
||||||
|
} SS_IO_Comms;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned __int64 g_nJoyCntrResetCycle;
|
||||||
|
} SS_IO_Joystick;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
DWORD keyboardqueries;
|
||||||
|
BYTE nLastKey;
|
||||||
|
} SS_IO_Keyboard;
|
||||||
|
|
||||||
|
//typedef struct
|
||||||
|
//{
|
||||||
|
//} SS_IO_Memory;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned __int64 g_nSpkrLastCycle;
|
||||||
|
} SS_IO_Speaker;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool bAltCharSet; // charoffs
|
||||||
|
DWORD dwVidMode;
|
||||||
|
} SS_IO_Video;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
DWORD dwMemMode;
|
||||||
|
BOOL bLastWriteRam;
|
||||||
|
BYTE nMemMain[nMemMainSize];
|
||||||
|
BYTE nMemAux[nMemAuxSize];
|
||||||
|
} SS_BaseMemory;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SS_UNIT_HDR UnitHdr;
|
||||||
|
SS_CPU6502 CPU6502;
|
||||||
|
SS_IO_Comms Comms;
|
||||||
|
SS_IO_Joystick Joystick;
|
||||||
|
SS_IO_Keyboard Keyboard;
|
||||||
|
// SS_IO_Memory Memory;
|
||||||
|
SS_IO_Speaker Speaker;
|
||||||
|
SS_IO_Video Video;
|
||||||
|
SS_BaseMemory Memory;
|
||||||
|
} SS_APPLE2_Unit;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
DWORD dwComputerEmulation;
|
||||||
|
bool bCustomSpeed;
|
||||||
|
DWORD dwEmulationSpeed;
|
||||||
|
bool bEnhancedDiskSpeed;
|
||||||
|
DWORD dwJoystickType[2];
|
||||||
|
bool bMockingboardEnabled;
|
||||||
|
DWORD dwMonochromeColor;
|
||||||
|
DWORD dwSerialPort;
|
||||||
|
DWORD dwSoundType; // Sound Emulation
|
||||||
|
DWORD dwVideoType; // Video Emulation
|
||||||
|
} SS_AW_CFG;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char StartingDir[MAX_PATH];
|
||||||
|
DWORD dwWindowXpos;
|
||||||
|
DWORD dwWindowYpos;
|
||||||
|
} SS_AW_PREFS;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SS_UNIT_HDR UnitHdr;
|
||||||
|
DWORD dwAppleWinVersion;
|
||||||
|
SS_AW_PREFS Prefs;
|
||||||
|
SS_AW_CFG Cfg;
|
||||||
|
} SS_APPLEWIN_CONFIG;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SS_UNIT_HDR UnitHdr;
|
||||||
|
DWORD dwType; // SS_CARDTYPE
|
||||||
|
DWORD dwSlot; // [1..7]
|
||||||
|
} SS_CARD_HDR;
|
||||||
|
|
||||||
|
enum SS_CARDTYPE
|
||||||
|
{
|
||||||
|
CT_Empty = 0,
|
||||||
|
CT_Disk2, // Apple Disk][
|
||||||
|
CT_SSC, // Apple Super Serial Card
|
||||||
|
CT_Mockingboard,
|
||||||
|
CT_GenericPrinter,
|
||||||
|
CT_GenericHDD, // Hard disk
|
||||||
|
CT_GenericClock,
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SS_CARD_HDR Hdr;
|
||||||
|
} SS_CARD_EMPTY;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
const UINT NIBBLES_PER_TRACK = 0x1A00;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char szFileName[MAX_PATH];
|
||||||
|
int track;
|
||||||
|
int phase;
|
||||||
|
int byte;
|
||||||
|
BOOL writeprotected;
|
||||||
|
BOOL trackimagedata;
|
||||||
|
BOOL trackimagedirty;
|
||||||
|
DWORD spinning;
|
||||||
|
DWORD writelight;
|
||||||
|
int nibbles;
|
||||||
|
BYTE nTrack[NIBBLES_PER_TRACK];
|
||||||
|
} DISK2_Unit;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SS_CARD_HDR Hdr;
|
||||||
|
DISK2_Unit Unit[2];
|
||||||
|
int currdrive;
|
||||||
|
BOOL diskaccessed;
|
||||||
|
BOOL enhancedisk;
|
||||||
|
BYTE floppylatch;
|
||||||
|
BOOL floppymotoron;
|
||||||
|
BOOL floppywritemode;
|
||||||
|
} SS_CARD_DISK2;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
BYTE l;
|
||||||
|
BYTE h;
|
||||||
|
};
|
||||||
|
USHORT w;
|
||||||
|
};
|
||||||
|
} IWORD;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
BYTE ORB; // $00 - Port B
|
||||||
|
BYTE ORA; // $01 - Port A (with handshaking)
|
||||||
|
BYTE DDRB; // $02 - Data Direction Register B
|
||||||
|
BYTE DDRA; // $03 - Data Direction Register A
|
||||||
|
//
|
||||||
|
// $04 - Read counter (L) / Write latch (L)
|
||||||
|
// $05 - Read / Write & initiate count (H)
|
||||||
|
// $06 - Read / Write & latch (L)
|
||||||
|
// $07 - Read / Write & latch (H)
|
||||||
|
// $08 - Read counter (L) / Write latch (L)
|
||||||
|
// $09 - Read counter (H) / Write latch (H)
|
||||||
|
IWORD TIMER1_COUNTER;
|
||||||
|
IWORD TIMER1_LATCH;
|
||||||
|
IWORD TIMER2_COUNTER;
|
||||||
|
IWORD TIMER2_LATCH;
|
||||||
|
//
|
||||||
|
BYTE SERIAL_SHIFT; // $0A
|
||||||
|
BYTE ACR; // $0B - Auxiliary Control Register
|
||||||
|
BYTE PCR; // $0C - Peripheral Control Register
|
||||||
|
BYTE IFR; // $0D - Interrupt Flag Register
|
||||||
|
BYTE IER; // $0E - Interrupt Enable Register
|
||||||
|
BYTE ORA_NO_HS; // $0F - Port A (without handshaking)
|
||||||
|
} SY6522;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
BYTE DurationPhonome;
|
||||||
|
BYTE Inflection; // I10..I3
|
||||||
|
BYTE RateInflection;
|
||||||
|
BYTE CtrlArtAmp;
|
||||||
|
BYTE FilterFreq;
|
||||||
|
//
|
||||||
|
BYTE CurrentMode;
|
||||||
|
} SSI263A;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SY6522 RegsSY6522;
|
||||||
|
BYTE RegsAY8910[16];
|
||||||
|
SSI263A RegsSSI263;
|
||||||
|
BYTE nAYCurrentRegister;
|
||||||
|
bool bTimer1IrqPending;
|
||||||
|
bool bTimer2IrqPending;
|
||||||
|
bool bSpeechIrqPending;
|
||||||
|
} MB_Unit;
|
||||||
|
|
||||||
|
const UINT MB_UNITS_PER_CARD = 2;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SS_CARD_HDR Hdr;
|
||||||
|
MB_Unit Unit[MB_UNITS_PER_CARD];
|
||||||
|
} SS_CARD_MOCKINGBOARD;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
SS_FILE_HDR Hdr;
|
||||||
|
SS_APPLE2_Unit Apple2Unit;
|
||||||
|
// SS_APPLEWIN_CONFIG AppleWinCfg;
|
||||||
|
SS_CARD_EMPTY Empty1; // Slot1
|
||||||
|
SS_CARD_EMPTY Empty2; // Slot2
|
||||||
|
SS_CARD_EMPTY Empty3; // Slot3
|
||||||
|
SS_CARD_MOCKINGBOARD Mockingboard1; // Slot4
|
||||||
|
SS_CARD_MOCKINGBOARD Mockingboard2; // Slot5
|
||||||
|
SS_CARD_DISK2 Disk2; // Slot6
|
||||||
|
SS_CARD_EMPTY Empty7; // Slot7
|
||||||
|
} APPLEWIN_SNAPSHOT;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum VIDEOTYPE {VT_MONO=0, VT_COLOR_STANDARD, VT_COLOR_TEXT_OPTIMIZED, VT_COLOR_TVEMU, VT_NUM_MODES};
|
||||||
|
|
||||||
|
extern BOOL graphicsmode;
|
||||||
|
extern COLORREF monochrome;
|
||||||
|
extern DWORD videotype;
|
||||||
|
|
||||||
|
void CreateColorMixMap();
|
||||||
|
|
||||||
|
BOOL VideoApparentlyDirty ();
|
||||||
|
void VideoBenchmark ();
|
||||||
|
void VideoCheckPage (BOOL);
|
||||||
|
void VideoChooseColor ();
|
||||||
|
void VideoDestroy ();
|
||||||
|
void VideoDisplayLogo ();
|
||||||
|
BOOL VideoHasRefreshed ();
|
||||||
|
void VideoInitialize ();
|
||||||
|
void VideoRealizePalette (HDC);
|
||||||
|
void VideoRedrawScreen ();
|
||||||
|
void VideoRefreshScreen ();
|
||||||
|
void VideoReinitialize ();
|
||||||
|
void VideoResetState ();
|
||||||
|
void VideoUpdateVbl (DWORD dwCyclesThisFrame);
|
||||||
|
void VideoUpdateFlash();
|
||||||
|
bool VideoGetSW80COL();
|
||||||
|
DWORD VideoGetSnapshot(SS_IO_Video* pSS);
|
||||||
|
DWORD VideoSetSnapshot(SS_IO_Video* pSS);
|
||||||
|
|
||||||
|
BYTE __stdcall VideoCheckMode (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall VideoCheckVbl (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|
||||||
|
BYTE __stdcall VideoSetMode (WORD pc, BYTE addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft);
|