*** empty log message ***

This commit is contained in:
tomch 2006-02-25 20:50:29 +00:00
parent 5140d14862
commit 312e86b4f9
73 changed files with 49282 additions and 1 deletions

386
AppleWin/Applewin.vcproj Normal file
View 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>

View 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.

View File

@ -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]
--------------

View File

@ -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

View File

@ -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))

Binary file not shown.

View File

@ -0,0 +1,4 @@
a65 -b -l HDDRVR.A65 >hddrvr.lst
@del HDDRVR.BIN
rename 6502.bin HDDRVR.BIN
copy HDDRVR.BIN ..\Resource

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
AppleWin/resource/COLOR.BMP Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
AppleWin/resource/DEBUG.BMP Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
AppleWin/resource/DISK.ICO Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
AppleWin/resource/HELP.BMP Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

BIN
AppleWin/resource/RUN.BMP Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
AppleWin/resource/SETUP.BMP Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View 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
View 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
View 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

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

32
AppleWin/source/CPU.h Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

1259
AppleWin/source/Debug.h Normal file

File diff suppressed because it is too large Load Diff

583
AppleWin/source/Disk.cpp Normal file
View 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
View 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);

View 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;
}
}

View 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

File diff suppressed because it is too large Load Diff

14
AppleWin/source/Frame.h Normal file
View 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 ();

View 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;
}

View 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);

View 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;
}

View 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);

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

33
AppleWin/source/Memory.h Normal file
View 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);

File diff suppressed because it is too large Load Diff

View 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);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
#pragma once
void PSP_Init();
DWORD PSP_GetVolumeMax();
bool PSP_SaveStateSelectImage(HWND hWindow, bool bSave);

View 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);
}

View 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
View 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
View 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);

File diff suppressed because it is too large Load Diff

View 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;
}

View 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();

View 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;
}

View 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);

View 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;
}

View 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

File diff suppressed because it is too large Load Diff

23
AppleWin/source/Speaker.h Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

32
AppleWin/source/Video.h Normal file
View 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);