*** empty log message ***
386
AppleWin/Applewin.vcproj
Normal file
@ -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>
|
340
AppleWin/GNU General Public License.txt
Normal file
@ -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
|
||||
for a moment. But if, after selecting Disk 1, I start the debugger and then issue the "G" command,
|
||||
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!)
|
||||
- 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
|
||||
----------------------
|
||||
- *** 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
|
||||
+ Symbol maintenance (main, user, source), source-level debugging, mini-calculator
|
||||
+ 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 emulation speed control (was only running at 1MHz)
|
||||
- Fixed internal ADC: was flagged as write to memory
|
||||
|
@ -8,6 +8,10 @@ Priority:
|
||||
. DONE: Shift+Ins to paste from clipboard
|
||||
. 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:
|
||||
- Light-gun support (if pixel under mouse is set, then set $C061.b7 (Richard Jackson))
|
||||
|
||||
|
BIN
AppleWin/firmware/HDD/HDDRVR.BIN
Normal file
4
AppleWin/firmware/HDD/build.bat
Normal file
@ -0,0 +1,4 @@
|
||||
a65 -b -l HDDRVR.A65 >hddrvr.lst
|
||||
@del HDDRVR.BIN
|
||||
rename 6502.bin HDDRVR.BIN
|
||||
copy HDDRVR.BIN ..\Resource
|
178
AppleWin/firmware/HDD/hddrvr.a65
Normal file
@ -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
|
BIN
AppleWin/resource/APPLEWIN.ICO
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
AppleWin/resource/Applewin.bmp
Normal file
After Width: | Height: | Size: 211 KiB |
302
AppleWin/resource/Applewin.rc
Normal file
@ -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
|
||||
|
BIN
AppleWin/resource/CAPSOFF.BMP
Normal file
After Width: | Height: | Size: 262 B |
BIN
AppleWin/resource/CAPSON.BMP
Normal file
After Width: | Height: | Size: 262 B |
BIN
AppleWin/resource/CHARSET4.BMP
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
AppleWin/resource/COLOR.BMP
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
AppleWin/resource/DEBUG.BMP
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
AppleWin/resource/DISK.ICO
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
AppleWin/resource/DISKOFF.BMP
Normal file
After Width: | Height: | Size: 190 B |
BIN
AppleWin/resource/DISKREAD.BMP
Normal file
After Width: | Height: | Size: 190 B |
BIN
AppleWin/resource/DISKWRIT.BMP
Normal file
After Width: | Height: | Size: 190 B |
BIN
AppleWin/resource/DRIVE1.BMP
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
AppleWin/resource/DRIVE2.BMP
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
AppleWin/resource/DriveSwap.bmp
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
AppleWin/resource/FULLSCR.BMP
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
AppleWin/resource/HELP.BMP
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
AppleWin/resource/Hddrvr.bin
Normal file
BIN
AppleWin/resource/RUN.BMP
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
AppleWin/resource/SETUP.BMP
Normal file
After Width: | Height: | Size: 1.1 KiB |
67
AppleWin/resource/resource.h
Normal file
@ -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
|
751
AppleWin/source/AY8910.cpp
Normal file
@ -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];
|
||||
}
|
15
AppleWin/source/AY8910.h
Normal file
@ -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
|
677
AppleWin/source/Applewin.cpp
Normal file
@ -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;
|
||||
}
|
25
AppleWin/source/Applewin.h
Normal file
@ -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();
|
1023
AppleWin/source/CPU.cpp
Normal file
32
AppleWin/source/CPU.h
Normal file
@ -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);
|
73
AppleWin/source/Common.h
Normal file
@ -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;
|
||||
|
11637
AppleWin/source/Debug.cpp
Normal file
1259
AppleWin/source/Debug.h
Normal file
583
AppleWin/source/Disk.cpp
Normal file
@ -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;
|
||||
}
|
33
AppleWin/source/Disk.h
Normal file
@ -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);
|
900
AppleWin/source/DiskImage.cpp
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
|
13
AppleWin/source/DiskImage.h
Normal file
@ -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);
|
1111
AppleWin/source/Frame.cpp
Normal file
14
AppleWin/source/Frame.h
Normal file
@ -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 ();
|
567
AppleWin/source/Harddisk.cpp
Normal file
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
12
AppleWin/source/Harddisk.h
Normal file
@ -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);
|
591
AppleWin/source/Joystick.cpp
Normal file
@ -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;
|
||||
}
|
22
AppleWin/source/Joystick.h
Normal file
@ -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);
|
396
AppleWin/source/Keyboard.cpp
Normal file
@ -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;
|
||||
}
|
18
AppleWin/source/Keyboard.h
Normal file
@ -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);
|
1242
AppleWin/source/Memory.cpp
Normal file
33
AppleWin/source/Memory.h
Normal file
@ -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);
|
1625
AppleWin/source/Mockingboard.cpp
Normal file
25
AppleWin/source/Mockingboard.h
Normal file
@ -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);
|
1006
AppleWin/source/PropertySheetPage.cpp
Normal file
5
AppleWin/source/PropertySheetPage.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void PSP_Init();
|
||||
DWORD PSP_GetVolumeMax();
|
||||
bool PSP_SaveStateSelectImage(HWND hWindow, bool bSave);
|
99
AppleWin/source/Registry.cpp
Normal file
@ -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);
|
||||
}
|
6
AppleWin/source/Registry.h
Normal file
@ -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);
|
139
AppleWin/source/Riff.cpp
Normal file
@ -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;
|
||||
}
|
5
AppleWin/source/Riff.h
Normal file
@ -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);
|
19615
AppleWin/source/SSI263Phonemes.h
Normal file
290
AppleWin/source/SaveState.cpp
Normal file
@ -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;
|
||||
}
|
10
AppleWin/source/SaveState.h
Normal file
@ -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();
|
301
AppleWin/source/SerialComms.cpp
Normal file
@ -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;
|
||||
}
|
17
AppleWin/source/SerialComms.h
Normal file
@ -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);
|
645
AppleWin/source/SoundCore.cpp
Normal file
@ -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;
|
||||
}
|
50
AppleWin/source/SoundCore.h
Normal file
@ -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;
|
1076
AppleWin/source/Speaker.cpp
Normal file
23
AppleWin/source/Speaker.h
Normal file
@ -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);
|
38
AppleWin/source/StdAfx.h
Normal file
@ -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"
|
273
AppleWin/source/Structs.h
Normal file
@ -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;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
1685
AppleWin/source/Video.cpp
Normal file
32
AppleWin/source/Video.h
Normal file
@ -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);
|