Updated Atari800 project (by Lubomyr)
This commit is contained in:
@@ -1,26 +1,34 @@
|
||||
# The application settings for Android libSDL port
|
||||
AppSettingVersion=9
|
||||
AppSettingVersion=16
|
||||
LibSdlVersion=1.2
|
||||
AppName="Atari800 emulator"
|
||||
AppName="Atari800"
|
||||
AppFullName=net.sourceforge.atari800
|
||||
ScreenOrientation=h
|
||||
AppDataDownloadUrl="Download Atari ROM, note that it is ILLEGAL to download it without owning Atari device!|https://sites.google.com/site/xpelyax/Home/atari800.zip?attredirects=0&d=1"
|
||||
InhibitSuspend=n
|
||||
AppDataDownloadUrl="Download Atari ROM, note that it is ILLEGAL to download it without owning Atari device!|atari800-data.zip"
|
||||
SdlVideoResize=y
|
||||
SdlVideoResizeKeepAspect=n
|
||||
NeedDepthBuffer=n
|
||||
AppUsesMouse=n
|
||||
AppNeedsTwoButtonMouse=n
|
||||
AppNeedsArrowKeys=y
|
||||
AppNeedsTextInput=y
|
||||
AppUsesJoystick=n
|
||||
AppHandlesJoystickSensitivity=y
|
||||
AppUsesMultitouch=n
|
||||
NonBlockingSwapBuffers=n
|
||||
RedefinedKeys="RETURN SPACE KP_PLUS KP_MINUS F1 ESCAPE F2 F3"
|
||||
RedefinedKeys="F6 RETURN F4 F3 F1 ESCAPE F6 F3 F4 F2 F6"
|
||||
AppTouchscreenKeyboardKeysAmount=6
|
||||
AppTouchscreenKeyboardKeysAmountAutoFire=2
|
||||
RedefinedKeysScreenKb="F6 F1 RETURN F4 F3 F2"
|
||||
MultiABI=n
|
||||
AppVersionCode=21001
|
||||
AppVersionName="2.1.0.01"
|
||||
CompiledLibraries="sdl_mixer png"
|
||||
CustomBuildScript=n
|
||||
AppCflags='-O2 -finline-functions -DSOUND'
|
||||
AppVersionCode=21003
|
||||
AppVersionName="2.2.0rc2.02"
|
||||
CompiledLibraries="jpeg png"
|
||||
CustomBuildScript=y
|
||||
AppCflags=''
|
||||
AppLdflags=''
|
||||
AppSubdirsBuild=''
|
||||
AppUseCrystaXToolchain=n
|
||||
AppCmdline='-audio16'
|
||||
ReadmeText='^You may press "Home" now - the data will be downloaded in background'
|
||||
|
||||
17
project/jni/application/atari800/AndroidBuild.sh
Executable file
17
project/jni/application/atari800/AndroidBuild.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
|
||||
LOCAL_PATH=`dirname $0`
|
||||
LOCAL_PATH=`cd $LOCAL_PATH && pwd`
|
||||
|
||||
ln -sf libsdl-1.2.so $LOCAL_PATH/../../../obj/local/armeabi/libSDL.so
|
||||
|
||||
if [ \! -f atari800/configure ] ; then
|
||||
sh -c "cd atari800/src && ./autogen.sh"
|
||||
fi
|
||||
|
||||
if [ \! -f atari800/src/Makefile ] ; then
|
||||
../setEnvironment.sh sh -c "cd atari800/src && ./configure --build=x86_64-unknown-linux-gnu --host=arm-linux-androideabi --target=sdl --without-x"
|
||||
fi
|
||||
|
||||
make -C atari800/src && mv -f atari800/src/atari800 libapplication.so
|
||||
BIN
project/jni/application/atari800/AndroidData/atari800-data.zip
Normal file
BIN
project/jni/application/atari800/AndroidData/atari800-data.zip
Normal file
Binary file not shown.
@@ -1,340 +0,0 @@
|
||||
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.
|
||||
@@ -1,34 +0,0 @@
|
||||
Atari800 emulator version 2.1.0
|
||||
-------------------------------
|
||||
|
||||
This is free and portable Atari800/XL/XE/5200 emulator, originally written
|
||||
by David Firth and now developed by the Atari800 Development Team (please
|
||||
see DOC/CREDITS). This program is copyrighted and released under the GPL
|
||||
(see COPYING).
|
||||
|
||||
Please read DOC/README, DOC/INSTALL and DOC/USAGE.
|
||||
|
||||
For news in this release please do read DOC/NEWS.
|
||||
|
||||
If you have a problem running this emulator please read DOC/FAQ first.
|
||||
If the problem persists then please ask in newsgroup comp.sys.atari.8bit
|
||||
or in the atari800-users mailing list (see below).
|
||||
|
||||
Look at DOC/BUGS before reporting something you consider a bug.
|
||||
|
||||
If you want to help developing Atari800 emulator you can subscribe to our
|
||||
mailing list (http://lists.sourceforge.net/lists/listinfo/atari800-users).
|
||||
DOC/TODO might point you in the right direction.
|
||||
|
||||
This version, and all versions back to 0.8.2 have been released by me (Petr
|
||||
Stehlik) and are now available at Sourceforge.net (URL below). Thanks
|
||||
go to David Firth and all the people that helped making this release.
|
||||
|
||||
EnJoy!
|
||||
|
||||
Petr Stehlik
|
||||
March 27, 2009
|
||||
|
||||
E-mail: pstehlik@sophics.cz
|
||||
|
||||
Project homepage: http://atari800.sourceforge.net/
|
||||
1
project/jni/application/atari800/atari800
Symbolic link
1
project/jni/application/atari800/atari800
Symbolic link
@@ -0,0 +1 @@
|
||||
/home/lubomyr/atari800/atari800
|
||||
71
project/jni/application/atari800/atari800-2.2.0rc2-cvs.diff
Normal file
71
project/jni/application/atari800/atari800-2.2.0rc2-cvs.diff
Normal file
@@ -0,0 +1,71 @@
|
||||
Only in atari800/atari800/src: config.h.in
|
||||
diff -ru orig/atari800/atari800/src/config.sub atari800/atari800/src/config.sub
|
||||
--- orig/atari800/atari800/src/config.sub 2006-04-08 08:07:36.000000000 -0400
|
||||
+++ atari800/atari800/src/config.sub 2011-02-03 10:28:16.000000000 -0500
|
||||
@@ -1206,7 +1206,7 @@
|
||||
| -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
|
||||
| -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||
- | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||
+ | -udi* | -eabi* | -androideabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||
| -chorusos* | -chorusrdb* \
|
||||
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
|
||||
| -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
|
||||
diff -ru orig/atari800/atari800/src/configure.ac atari800/atari800/src/configure.ac
|
||||
--- orig/atari800/atari800/src/configure.ac 2010-12-07 10:16:26.000000000 -0500
|
||||
+++ atari800/atari800/src/configure.ac 2011-02-03 10:45:32.000000000 -0500
|
||||
@@ -97,7 +97,7 @@
|
||||
AC_DEFINE(DOS_DRIVES,1,[Define to enable DOS style drives support.])
|
||||
AC_DEFINE(SYSTEM_WIDE_CFG_FILE,"c:\\atari800.cfg",[Alternate system-wide config file for non-Unix OS.])
|
||||
;;
|
||||
- linux | linux-gnu)
|
||||
+ linux | linux-gnu | androideabi)
|
||||
a8_host="linux"
|
||||
;;
|
||||
mint)
|
||||
@@ -301,7 +301,7 @@
|
||||
WANT_NTSC_FILTER=yes
|
||||
LIBS="$LIBS `sdl-config --libs`"
|
||||
OBJS="videomode.o sdl/main.o sdl/video.o sdl/video_sw.o sdl/input.o sdl/palette.o"
|
||||
- CFLAGS="$CFLAGS -ansi -pedantic -Waggregate-return -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Winline"
|
||||
+ CFLAGS="$CFLAGS -O3 -pedantic -Waggregate-return -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Winline"
|
||||
if [[ "$a8_host" != "beos" ]]; then
|
||||
dnl BeOS has a real issue with redundant-decls
|
||||
CFLAGS="$CFLAGS -Wredundant-decls"
|
||||
Only in atari800/atari800/src: configure.ac~
|
||||
diff -ru orig/atari800/atari800/src/sdl/input.c atari800/atari800/src/sdl/input.c
|
||||
--- orig/atari800/atari800/src/sdl/input.c 2010-12-07 10:16:26.000000000 -0500
|
||||
+++ atari800/atari800/src/sdl/input.c 2011-02-03 10:46:35.000000000 -0500
|
||||
@@ -22,9 +22,11 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
+#ifndef ANDROID
|
||||
#ifdef __linux__
|
||||
#define LPTJOY 1
|
||||
#endif
|
||||
+#endif
|
||||
|
||||
#ifdef LPTJOY
|
||||
#include <fcntl.h>
|
||||
@@ -1214,6 +1216,9 @@
|
||||
int stick0, stick1;
|
||||
stick0 = stick1 = INPUT_STICK_CENTRE;
|
||||
|
||||
+ if( !kbhits )
|
||||
+ return;
|
||||
+
|
||||
if (PLATFORM_kbd_joy_0_enabled) {
|
||||
if (kbhits[KBD_STICK_0_LEFT])
|
||||
stick0 = INPUT_STICK_LEFT;
|
||||
@@ -1281,6 +1286,9 @@
|
||||
int trig0, trig1, i;
|
||||
trig0 = trig1 = 1;
|
||||
|
||||
+ if( !kbhits )
|
||||
+ return;
|
||||
+
|
||||
if (PLATFORM_kbd_joy_0_enabled) {
|
||||
trig0 = kbhits[KBD_TRIG_0] ? 0 : 1;
|
||||
}
|
||||
Only in atari800/atari800/src/sdl: input.c~
|
||||
@@ -1,820 +0,0 @@
|
||||
.TH ATARI800 1 "March 26, 2009"
|
||||
|
||||
.SH NAME
|
||||
atari800 \- Atari 800 Emulator, Version 2.1.0
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBatari800\fP [options] [files...]
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fIatari800\fP emulates the Atari 800, Atari 800 XL, Atari 130 XE and
|
||||
Atari 5200 Games System.
|
||||
|
||||
.SS Options
|
||||
|
||||
.TP
|
||||
\fB-help
|
||||
Print complete and up-to-date list of command line switches
|
||||
.TP
|
||||
\fB-v
|
||||
Print emulator version
|
||||
.TP
|
||||
\fB-verbose
|
||||
Display framerate when exiting
|
||||
.TP
|
||||
\fB-config filename
|
||||
Specify an alternative configuration filename
|
||||
|
||||
.TP
|
||||
\fB-osa_rom filename
|
||||
Path to file containing Atari Rev.A Operating System.
|
||||
Used to override paths defined at compile time.
|
||||
.TP
|
||||
\fB-osb_rom filename
|
||||
Path to file containing Atari Rev.B Operating System.
|
||||
Used to override paths defined at compile time.
|
||||
.TP
|
||||
\fB-xlxe_rom filename
|
||||
Path to file containing Atari XL/XE Operating System.
|
||||
Used to override paths defined at compile time.
|
||||
.TP
|
||||
\fB-5200_rom filename
|
||||
Path to file containing Atari 5200 Games System ROM.
|
||||
Used to override paths defined at compile time.
|
||||
.TP
|
||||
\fB-basic_rom filename
|
||||
Path to file containing Atari BASIC ROM.
|
||||
Used to override paths defined at compile time.
|
||||
|
||||
.TP
|
||||
\fB-atari
|
||||
Emulate Atari 800
|
||||
.TP
|
||||
\fB-xl
|
||||
Emulate Atari 800 XL
|
||||
.TP
|
||||
\fB-xe
|
||||
Emulate Atari 130 XE
|
||||
.TP
|
||||
\fB-320xe
|
||||
Emulate Atari 320 XE (Compy Shop)
|
||||
.TP
|
||||
\fB-rambo
|
||||
Emulate Atari 320 XE (Rambo)
|
||||
.TP
|
||||
\fB-5200
|
||||
Emulate Atari 5200
|
||||
.TP
|
||||
\fB-emuos
|
||||
Use EmuOS
|
||||
|
||||
.TP
|
||||
\fB-a
|
||||
Use Atari OS/A for Atari 800
|
||||
.TP
|
||||
\fB-b
|
||||
Use Atari OS/B for Atari 800
|
||||
.TP
|
||||
\fB-c
|
||||
Enable RAM between 0xc000 and 0xcfff in Atari 800
|
||||
|
||||
.TP
|
||||
\fB-axlon <n>
|
||||
Use Atari 800 Axlon memory expansion: <n> k total RAM
|
||||
.TP
|
||||
\fB-axlon0f
|
||||
Use Axlon shadow at 0x0fc0-0x0fff
|
||||
.TP
|
||||
\fB-mosaic <n>
|
||||
Use 400/800 Mosaic memory expansion: <n> k total RAM
|
||||
|
||||
.TP
|
||||
\fB-pal
|
||||
Emulate PAL TV mode
|
||||
.TP
|
||||
\fB-ntsc
|
||||
Emulate NTSC TV mode
|
||||
|
||||
.TP
|
||||
\fB-nobasic
|
||||
Used to disable Basic when starting the emulator in XL/XE mode.
|
||||
Simulates the Option key being held down during system boot.
|
||||
.TP
|
||||
\fB-basic
|
||||
Turn on Atari BASIC ROM
|
||||
|
||||
.TP
|
||||
\fB-cart <filename>
|
||||
Insert cartridge (CART or raw format)
|
||||
.TP
|
||||
\fB-run <filename>
|
||||
Run Atari program (EXE, COM, XEX, BAS, LST)
|
||||
.TP
|
||||
\fB-state <filename>
|
||||
Load saved-state file
|
||||
.TP
|
||||
\fB-tape <filename>
|
||||
Attach cassette image (CAS format or raw file)
|
||||
.TP
|
||||
\fB-boottape <filename>
|
||||
Attach cassette image and boot it
|
||||
|
||||
.TP
|
||||
\fB-1400
|
||||
Emulate the Atari 1400XL
|
||||
.TP
|
||||
\fB-xld
|
||||
Emulate the Atari 1450XLD
|
||||
.TP
|
||||
\fB-bb
|
||||
Emulate the CSS Black Box
|
||||
.TP
|
||||
\fB-mio
|
||||
Emulate the ICD MIO board
|
||||
|
||||
.TP
|
||||
\fB-nopatch
|
||||
Normally the OS is patched giving very fast I/O. This options prevents
|
||||
the patch from being applied so that the OS accesses the serial port
|
||||
hardware directly. This option will probably never be needed since
|
||||
programs that access the serial hardware should work even if the OS
|
||||
has been patched.
|
||||
.TP
|
||||
\fB-nopatchall
|
||||
Don't patch OS at all, H:, P: and R: devices won't work
|
||||
|
||||
.TP
|
||||
\fB-H1 <path>
|
||||
Set path for H1: device
|
||||
.TP
|
||||
\fB-H2 <path>
|
||||
Set path for H2: device
|
||||
.TP
|
||||
\fB-H3 <path>
|
||||
Set path for H3: device
|
||||
.TP
|
||||
\fB-H4 <path>
|
||||
Set path for H4: device
|
||||
.TP
|
||||
\fB-Hpath <path>
|
||||
Set path for Atari executables on the H: device
|
||||
.TP
|
||||
\fB-hreadonly
|
||||
Enable read-only mode for H: device
|
||||
.TP
|
||||
\fB-hreadwrite
|
||||
Disable read-only mode for H: device
|
||||
.TP
|
||||
\fB-devbug
|
||||
Put debugging messages for H: and P: devices in log file
|
||||
|
||||
.TP
|
||||
\fB-rtime
|
||||
Enable R-Time 8 emulation
|
||||
.TP
|
||||
\fB-nortime
|
||||
Disable R-Time 8 emulation
|
||||
|
||||
.TP
|
||||
\fBrdevice [<dev>]
|
||||
Enable R: device. If <dev> is specified then it's used as host serial device
|
||||
name (e.g. /dev/ttyS0 on linux). If there is no <dev> specified then R:
|
||||
is directed to network.
|
||||
|
||||
.TP
|
||||
\fB-mouse off
|
||||
Do not use mouse
|
||||
.TP
|
||||
\fB-mouse pad
|
||||
Emulate paddles
|
||||
.TP
|
||||
\fB-mouse touch
|
||||
Emulate Atari Touch Tablet
|
||||
.TP
|
||||
\fB-mouse koala
|
||||
Emulate Koala Pad
|
||||
.TP
|
||||
\fB-mouse pen
|
||||
Emulate Light Pen
|
||||
.TP
|
||||
\fB-mouse gun
|
||||
Emulate Light Gun
|
||||
.TP
|
||||
\fB-mouse amiga
|
||||
Emulate Amiga mouse
|
||||
.TP
|
||||
\fB-mouse st
|
||||
Emulate Atari ST mouse
|
||||
.TP
|
||||
\fB-mouse trak
|
||||
Emulate Atari Trak-Ball
|
||||
.TP
|
||||
\fB-mouse joy
|
||||
Emulate joystick using mouse
|
||||
.TP
|
||||
\fB-mouseport <num>
|
||||
Set mouse port 1-4 (default 1)
|
||||
.TP
|
||||
\fB-mousespeed <num>
|
||||
Set mouse speed 1-9 (default 3)
|
||||
.TP
|
||||
\fB-multijoy
|
||||
Emulate MultiJoy4 interface
|
||||
.TP
|
||||
\fB-directmouse
|
||||
Use mouse's absolute position
|
||||
.TP
|
||||
\fB-cx85 <num>
|
||||
Emulate CX85 numeric keypad on port <num>
|
||||
.TP
|
||||
\fB-grabmouse
|
||||
SDL only, prevent mouse pointer from leaving the window
|
||||
|
||||
.TP
|
||||
\fB-record <filename>
|
||||
Record all input events to <filename>. Can be used for gaming contests
|
||||
(highest score etc).
|
||||
.TP
|
||||
\fB-playback <filename>
|
||||
Playback input events from <filename>. Watch an expert play the game.
|
||||
|
||||
.TP
|
||||
\fB-refresh
|
||||
Controls screen refresh rate. A numerical value follows this option
|
||||
which specifies how many emulated screen updates are required before
|
||||
the actual screen is updated. This value effects the speed of the
|
||||
emulation: A higher value results in faster CPU emulation but a
|
||||
less frequently updated screen.
|
||||
|
||||
.TP
|
||||
\fB-artif <mode>
|
||||
Set artifacting mode 0-4 (0 = disable)
|
||||
.TP
|
||||
\fB-paletten/p <filename>
|
||||
Read Atari NTSC/PAL colors from ACT file
|
||||
.TP
|
||||
\fB-blackn/p <num>
|
||||
Set NTSC/PAL black level 0-255
|
||||
.TP
|
||||
\fB-whiten/p <num>
|
||||
Set NTSC/PAL white level 0-255
|
||||
.TP
|
||||
\fB-colorsn/p <num>
|
||||
Set NTSC/PAL color intensity
|
||||
.TP
|
||||
\fB-genpaln/p
|
||||
Generate artifical NTSC/PAL palette
|
||||
.TP
|
||||
\fB-colshiftn/p <num>
|
||||
Set color shift (-genpal only)
|
||||
.TP
|
||||
\fB-screenshots <pattern>
|
||||
Set filename pattern for screenshots. Use to override the default
|
||||
atari000.png, atari001.png etc. filenames. Hashes are replaced with
|
||||
raising numbers. Existing files are overwritten only if all the files
|
||||
defined by the pattern exist.
|
||||
|
||||
.TP
|
||||
\fB-showspeed
|
||||
Show percentage of actual speed
|
||||
|
||||
.TP
|
||||
\fB-sound
|
||||
Enable sound
|
||||
.TP
|
||||
\fB-nosound
|
||||
Disable sound
|
||||
.TP
|
||||
\fB-dsprate <freq>
|
||||
Set mixing frequency (Hz)
|
||||
.TP
|
||||
\fB-snddelay <time>
|
||||
Set sound delay (milliseconds)
|
||||
|
||||
.SS Curses Options
|
||||
|
||||
.TP
|
||||
\fB-left
|
||||
Use columns 0 to 39
|
||||
.TP
|
||||
\fB-central
|
||||
Use columns 20 to 59
|
||||
.TP
|
||||
\fB-right
|
||||
Use columns 40 to 79
|
||||
.TP
|
||||
\fB-wide1
|
||||
Use columns 0 to 79. In this mode only the even character positions
|
||||
are used. The odd locations are filled with spaces.
|
||||
.TP
|
||||
\fB-wide2
|
||||
Use columns 0 to 79. This mode is similar to \fB-wide1\fP except that
|
||||
the spaces are in reverse video if the previous character was also
|
||||
in reverse video.
|
||||
|
||||
.SS Falcon Options
|
||||
|
||||
.TP
|
||||
\fB-interlace <x>
|
||||
Generate Falcon screen only every x frame
|
||||
.TP
|
||||
\fB-videl
|
||||
Direct VIDEL programming (Falcon/VGA only)
|
||||
.TP
|
||||
\fB-double
|
||||
Double the screen size on NOVA
|
||||
.TP
|
||||
\fB-delta
|
||||
Delta screen output (differences only)
|
||||
.TP
|
||||
\fB-joyswap
|
||||
Swap joysticks
|
||||
|
||||
.SS Java NestedVM
|
||||
|
||||
.TP
|
||||
\fB-scale <n>
|
||||
Scale width and height by <n>
|
||||
|
||||
.SS SDL Options
|
||||
|
||||
.TP
|
||||
\fB-fullscreen
|
||||
Start in fullscreen mode (tries to switch to 336x240 resolution)
|
||||
.TP
|
||||
\fB-windowed
|
||||
Start in a window (does not change your working resolution)
|
||||
.TP
|
||||
\fB-rotate90
|
||||
Run the emulator with rotated display (useful for devices with 240x320
|
||||
screen)
|
||||
.TP
|
||||
\fB-width number-of-pixels
|
||||
Host horizontal resolution for fullscreen
|
||||
.TP
|
||||
\fB-height number-of-pixels
|
||||
Host vertical resolution for fullscreen
|
||||
.TP
|
||||
\fB-bpp number-of-bits
|
||||
Host color depth for running in fullscreen
|
||||
|
||||
.TP
|
||||
\fB-audio16
|
||||
Enable 16-bit sound output
|
||||
|
||||
.TP
|
||||
\fB-nojoystick
|
||||
Do not initialize SDL joysticks
|
||||
.TP
|
||||
\fB-joy0 path-to-device
|
||||
Define path to device used in LPTjoy 0. Available on linux-ia32 only.
|
||||
.TP
|
||||
\fB-joy1 path-to-device
|
||||
Define path to device used in LPTjoy 1. Available on linux-ia32 only.
|
||||
|
||||
.TP
|
||||
\fB-ntscemu
|
||||
Emulate NTSC composite video (640x480x16 only)
|
||||
This includes NTSC TV artifacts. "-artif" is not needed in this mode and will
|
||||
not work. This mode does not use a palette. The video signal is emulated
|
||||
instead. Palette options such as -genpaln have no effect in this mode.
|
||||
The following items are for -ntscemu only:
|
||||
|
||||
.TP
|
||||
\fB-ntsc_hue <n>
|
||||
Set NTSC hue -1..1 (like TV Tint control)
|
||||
.TP
|
||||
\fB-ntsc_sat <n>
|
||||
Set NTSC saturation (like TV Colour control)
|
||||
.TP
|
||||
\fB-ntsc_cont <n>
|
||||
Set NTSC contrast (also called white level)
|
||||
.TP
|
||||
\fB-ntsc_bright <n>
|
||||
Set NTSC brightness (also called black level)
|
||||
.TP
|
||||
\fB-ntsc_sharp <n>
|
||||
Set NTSC sharpness
|
||||
.TP
|
||||
\fB-ntsc_burst <n>
|
||||
Set NTSC burst phase (artificating colours) (CTIA?) Drol, Choplifter,
|
||||
Ultima: 0.70
|
||||
.TP
|
||||
\fB-ntsc_gauss <n>
|
||||
Set NTSC Gaussian factor (can affect artifacting colours, sharpness and
|
||||
ghosting)
|
||||
.TP
|
||||
\fB-ntsc_gamma <n>
|
||||
Set NTSC gamma adjustment
|
||||
.TP
|
||||
\fB-ntsc_ramp <n>
|
||||
Set NTSC saturation ramp factor (amount by which bright colours become
|
||||
desaturated or washed out)
|
||||
.TP
|
||||
\fB-scanlines <n>
|
||||
Set scanlines percentage (ntscemu only)
|
||||
.TP
|
||||
\fB-scanlinesnoint
|
||||
Disable scanlines interpolation (ntscemu only)
|
||||
.TP
|
||||
\fB-proto80
|
||||
Emulate a prototype 80 column board for the 1090
|
||||
.TP
|
||||
\fB-xep80
|
||||
Emulate the XEP80
|
||||
.TP
|
||||
\fB-xep80port <n>
|
||||
Use XEP80 on joystick port <n>
|
||||
|
||||
|
||||
.SS X11 Options
|
||||
|
||||
.TP
|
||||
\fB-small
|
||||
Run the emulator in a small window where each Atari 800 pixel is
|
||||
represented by one X Window pixel
|
||||
.TP
|
||||
\fB-large
|
||||
Runs the emulator in a large window where each Atari 800 pixel is
|
||||
represented by a 2x2 X Window rectange. This mode is selected by
|
||||
default.
|
||||
.TP
|
||||
\fB-huge
|
||||
Runs the emulator in a huge window where each Atari 800 pixel is
|
||||
represented by a 3x3 X Window rectange
|
||||
.TP
|
||||
\fB-clip_x number-of-pixels
|
||||
Set left offset for clipping
|
||||
.TP
|
||||
\fB-clip_width number-of-pixels
|
||||
Set the width of the clipping-area
|
||||
.TP
|
||||
\fB-clip_y number-of-pixels
|
||||
Set top offset for clipping
|
||||
.TP
|
||||
\fB-clip_height number-of-pixels
|
||||
Set the height of the clipping-area
|
||||
.TP
|
||||
\fB-private_cmap
|
||||
Use private colormap
|
||||
.TP
|
||||
\fB-sio
|
||||
Show SIO monitor
|
||||
.TP
|
||||
\fB-x11bug
|
||||
Enable debug code in atari_x11.c
|
||||
|
||||
.TP
|
||||
\fB-keypad
|
||||
Keypad mode
|
||||
|
||||
.PD 0
|
||||
|
||||
.SH KEYBOARD, JOYSTICK AND OTHER CONTROLLERS
|
||||
|
||||
.TP
|
||||
\fBF1
|
||||
Built in user interface
|
||||
.TP
|
||||
\fBF2
|
||||
Option key
|
||||
.TP
|
||||
\fBF3
|
||||
Select key
|
||||
.TP
|
||||
\fBF4
|
||||
Start key
|
||||
.TP
|
||||
\fBF5
|
||||
Reset key ("warm reset")
|
||||
.TP
|
||||
\fBShift+F5
|
||||
Reboot ("cold reset")
|
||||
.TP
|
||||
\fBF6
|
||||
Help key (XL/XE only)
|
||||
.TP
|
||||
\fBF7
|
||||
Break key
|
||||
.TP
|
||||
\fBF8
|
||||
Enter monitor
|
||||
.TP
|
||||
\fBF9
|
||||
Exit emulator
|
||||
.TP
|
||||
\fBF10
|
||||
Save screenshot
|
||||
.TP
|
||||
\fBShift+F10
|
||||
Save interlaced screenshot
|
||||
.TP
|
||||
\fBAlt+R
|
||||
Run Atari program
|
||||
.TP
|
||||
\fBAlt+D
|
||||
Disk management
|
||||
.TP
|
||||
\fBAlt+C
|
||||
Cartridge management
|
||||
.TP
|
||||
\fBAlt+Y
|
||||
Select system
|
||||
.TP
|
||||
\fBAlt+O
|
||||
Sound settings
|
||||
.TP
|
||||
\fBAlt+W
|
||||
Sound recording start/stop
|
||||
.TP
|
||||
\fBAlt+S
|
||||
Save state file
|
||||
.TP
|
||||
\fBAlt+L
|
||||
Load state file
|
||||
.TP
|
||||
\fBAlt+A
|
||||
About the emulator
|
||||
.TP
|
||||
\fBInsert
|
||||
Insert line (Atari Shift+'>')
|
||||
.TP
|
||||
\fBCtrl+Insert
|
||||
Insert character (Atari Ctrl+'>')
|
||||
.TP
|
||||
\fBShift+Ctrl+Insert
|
||||
Shift+Ctrl+'>'
|
||||
.TP
|
||||
\fBDelete
|
||||
Delete line (Atari Shift+Backspace)
|
||||
.TP
|
||||
\fBShift+Backspace
|
||||
Delete line (Atari Shift+Backspace)
|
||||
.TP
|
||||
\fBCtrl+Delete
|
||||
Delete character (Atari Ctrl+Backspace)
|
||||
.TP
|
||||
\fBCtrl+Backspace
|
||||
Delete character (Atari Ctrl+Backspace)
|
||||
.TP
|
||||
\fBShift+Ctrl+Delete
|
||||
Shift+Ctrl+Backspace
|
||||
.TP
|
||||
\fBShift+Ctrl+Backspace
|
||||
Shift+Ctrl+Backspace
|
||||
.TP
|
||||
\fBHome
|
||||
Clear (Atari Shift+'<')
|
||||
.TP
|
||||
\fBCtrl+Home
|
||||
Ctrl+'<' (also clears screen)
|
||||
.TP
|
||||
\fBShift+Ctrl+Home
|
||||
Shift+Ctrl+'<'
|
||||
.TP
|
||||
\fB~
|
||||
Inverse video
|
||||
.TP
|
||||
\fBUp
|
||||
Up (Atari Ctrl+'-')
|
||||
.TP
|
||||
\fBDown
|
||||
Down (Atari Ctrl+'=')
|
||||
.TP
|
||||
\fBLeft
|
||||
Left (Atari ctrl+'+')
|
||||
.TP
|
||||
\fBRight
|
||||
Right (Atari ctrl+'*')
|
||||
.TP
|
||||
\fBCtrl+Up
|
||||
-
|
||||
.TP
|
||||
\fBCtrl+Down
|
||||
=
|
||||
.TP
|
||||
\fBCtrl+Left
|
||||
+
|
||||
.TP
|
||||
\fBCtrl+Right
|
||||
*
|
||||
.TP
|
||||
\fBShift+Up
|
||||
_ (Atari Shift+'-')
|
||||
.TP
|
||||
\fBShift+Down
|
||||
| (Atari Shift+'=')
|
||||
.TP
|
||||
\fBShift+Left
|
||||
\ (Atari Shift+'+')
|
||||
.TP
|
||||
\fBShift+Right
|
||||
^ (Atari Shift+'*')
|
||||
.TP
|
||||
\fBShift+Ctrl+Up
|
||||
Shift+Ctrl+-
|
||||
.TP
|
||||
\fBShift+Ctrl+Down
|
||||
Shift+Ctrl+=
|
||||
.TP
|
||||
\fBCtrl+'\\'
|
||||
Ctrl+Esc (Workaround for Windows)
|
||||
.TP
|
||||
\fBShift+Ctrl+'\\'
|
||||
Shift+Ctrl+Esc (Workaround for Windows)
|
||||
|
||||
.PP
|
||||
CX85 Keypad (if enabled):
|
||||
.TP
|
||||
\fBhost keypad 0123456789-.
|
||||
0123456789-.
|
||||
.TP
|
||||
\fBhost keypad /
|
||||
NO
|
||||
.TP
|
||||
\fBhost keypad Ctrl+/
|
||||
ESCAPE
|
||||
.TP
|
||||
\fBhost keypad *
|
||||
DELETE
|
||||
.TP
|
||||
\fBhost keypad +
|
||||
YES
|
||||
.TP
|
||||
\fBhost keypad Enter
|
||||
+ENTER
|
||||
|
||||
.PP
|
||||
Paddles, Atari touch tablet, Koala pad, light pen, light gun,
|
||||
ST/Amiga mouse, Atari trak-ball, joystick and Atari 5200 analog
|
||||
controller are emulated using mouse on ports that support it.
|
||||
See the options above for how to enable mouse.
|
||||
|
||||
.SS Basic
|
||||
|
||||
No function keys or Alt+letter shortcuts.
|
||||
Use Ctrl+C to enter the monitor.
|
||||
Controllers not supported in this version.
|
||||
|
||||
.SS Curses
|
||||
|
||||
F10 (Save screenshot) does not work in the default CURSES_BASIC build.
|
||||
Shift+F5 and Shift+F10 don't work at all.
|
||||
Avoid Ctrl + C, H, J, M, Q, S and Z. The remaining control characters
|
||||
can be typed. Control characters are displayed on the screen
|
||||
with the associated upper case character in bold.
|
||||
|
||||
Controllers not supported in this version.
|
||||
|
||||
.SS Falcon
|
||||
|
||||
.TP
|
||||
\fBHelp
|
||||
Help key (XL/XE)
|
||||
|
||||
.PP
|
||||
Joystick 0 is operated by the numeric keypad (make sure that the numeric
|
||||
keypad has been enabled).
|
||||
|
||||
7 8 9
|
||||
\\|/
|
||||
4 5 6
|
||||
/|\\
|
||||
1 2 3
|
||||
|
||||
And 0 is the fire key.
|
||||
|
||||
Mouse not supported in this version.
|
||||
|
||||
.SS SDL
|
||||
|
||||
.TP
|
||||
\fB`
|
||||
Atari/Inverse key
|
||||
.TP
|
||||
\fBLSUPER
|
||||
Atari/Inverse key (unusable under Windows)
|
||||
.TP
|
||||
\fBRSUPER
|
||||
CapsToggle (+Shift = CapsLock)
|
||||
|
||||
.TP
|
||||
\fBLAlt+F
|
||||
Switch fullscreen (probably doesn't work in Windows)
|
||||
.TP
|
||||
\fBLAlt+G
|
||||
Switch WIDTH_MODE (so you can set 320x240)
|
||||
.TP
|
||||
\fBLAlt+B
|
||||
Switch BLACK-AND-WHITE
|
||||
.TP
|
||||
\fBLAlt+J
|
||||
Swap \fBkeyboard_emulated\fP joysticks
|
||||
.TP
|
||||
\fBLAlt+E
|
||||
Switch bpp (for debug only, will be removed soon)
|
||||
.TP
|
||||
\fBLAlt+M
|
||||
Grab mouse (prevents mouse pointer from leaving the window)
|
||||
|
||||
These keys work with the NTSC composite video emualtion (-ntscemu):
|
||||
(This interface should be considered experimental and is subject to change)
|
||||
.TP
|
||||
\fBLAlt+1
|
||||
Decrease NTSC sharpness
|
||||
.TP
|
||||
\fBLAlt+2
|
||||
Increase NTSC sharpness
|
||||
.TP
|
||||
\fBLAlt+3
|
||||
Decrease NTSC saturation (like TV Colour control)
|
||||
.TP
|
||||
\fBLAlt+4
|
||||
Increase NTSC saturation
|
||||
.TP
|
||||
\fBLAlt+5
|
||||
Decrease NTSC brightness (also called black level)
|
||||
.TP
|
||||
\fBLAlt+6
|
||||
Increase NTSC brightness
|
||||
.TP
|
||||
\fBLAlt+7
|
||||
Decrease NTSC contrast (also called white level)
|
||||
.TP
|
||||
\fBLAlt+8
|
||||
Increase NTSC contrast
|
||||
.TP
|
||||
\fBLAlt+9
|
||||
Decrease NTSC burst phase (use this to change artifacting colours)
|
||||
.TP
|
||||
\fBLAlt+0
|
||||
Increase NTSC burst phase
|
||||
.TP
|
||||
\fBLAlt+-
|
||||
Decrease NTSC Gaussian factor (ghosting, sharpness, artif colours)
|
||||
.TP
|
||||
\fBLAlt+=
|
||||
Increase NTSC Gaussian factor (ghosting, sharpness, artif colours)
|
||||
.TP
|
||||
\fBLAlt+[
|
||||
Decrease scanlines percentage (NTSC mode only)
|
||||
.TP
|
||||
\fBLAlt+]
|
||||
Increase scanlines percentage (NTSC mode only)
|
||||
.TP
|
||||
\fBLAlt+;
|
||||
Decrease NTSC hue (like TV Tint control)
|
||||
.TP
|
||||
\fBLAlt+'
|
||||
Increase NTSC hue (like TV Tint control)
|
||||
.TP
|
||||
\fBLAlt+Ins
|
||||
Decrease NTSC saturation ramp(reduce saturation for bright colours)
|
||||
.TP
|
||||
\fBLAlt+Ins
|
||||
Increase NTSC saturation ramp(reduce saturation for bright colours)
|
||||
.TP
|
||||
\fBLAlt+Shift+X
|
||||
Enable/disable XEP80 screen (use with -xep80)
|
||||
|
||||
|
||||
.PP
|
||||
Apart from standard joysticks (handled by the SDL) up to two keyboard joysticks
|
||||
are supported. The keys used for joystick directions and the trigger can be
|
||||
freely defined in the config UI (Controller Config -> Define layout).
|
||||
Keyboard joystick emulation can be enabled/disabled in the Controller Config.
|
||||
By default, joy 0 is enabled and joy 1 is disabled (to not steal normal
|
||||
AWDS keys in the emulator).
|
||||
|
||||
.SS X11
|
||||
|
||||
.TP
|
||||
\fBAlt
|
||||
Atari key (either Alt key will work)
|
||||
|
||||
.PP
|
||||
Joystick 0 is operated by the mouse position relative to the center of
|
||||
the screen. The mouse button acts as the trigger. On Linux, standard
|
||||
joysticks are also supported.
|
||||
|
||||
.PD 1
|
||||
|
||||
.SH FILES
|
||||
.TP
|
||||
\fI/usr/share/atari800/ATARIOSA.ROM\fR
|
||||
Atari O/S A
|
||||
.TP
|
||||
\fI/usr/share/atari800/ATARIOSB.ROM\fR
|
||||
Atari O/S B
|
||||
.TP
|
||||
\fI/usr/share/atari800/ATARIXL.ROM\fR
|
||||
Atari 800 XL O/S
|
||||
.TP
|
||||
\fI/usr/share/atari800/ATARI5200.ROM\fR
|
||||
Atari 5200 O/S
|
||||
.TP
|
||||
\fI/usr/share/atari800/ATARIBAS.ROM\fR
|
||||
Atari Basic
|
||||
|
||||
.SH BUGS
|
||||
See the BUGS file.
|
||||
12
project/jni/application/atari800/build_instructions.txt
Normal file
12
project/jni/application/atari800/build_instructions.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Build instructions
|
||||
|
||||
unpack atari800-cfg-pelyaSDL.tar.gz into ~/commandergenius/project/jni/application
|
||||
Download latest atari800 source from http://atari800.cvs.sourceforge.net/atari800
|
||||
unpack atari800.tar.gz into ~/commandergenius/project/jni/application/atari800
|
||||
apply patch atari800-2.2.0rc2-cvs.diff
|
||||
|
||||
cd ~/commandergenius/project/jni/application
|
||||
rm src
|
||||
ln -s atari800 src
|
||||
cd ~/commandergenius
|
||||
./build.sh
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 9.5 KiB |
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* afile.c - Detection and opening of different Atari file types.
|
||||
*
|
||||
* Copyright (c) 1998-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "atari.h"
|
||||
#include "afile.h"
|
||||
#include "binload.h"
|
||||
#include "cartridge.h"
|
||||
#include "cassette.h"
|
||||
#include "gtia.h"
|
||||
#include "log.h"
|
||||
#include "sio.h"
|
||||
#include "statesav.h"
|
||||
#include "util.h"
|
||||
#ifdef HAVE_LIBZ
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
int AFILE_DetectFileType(const char *filename)
|
||||
{
|
||||
UBYTE header[4];
|
||||
int file_length;
|
||||
FILE *fp = fopen(filename, "rb");
|
||||
if (fp == NULL)
|
||||
return AFILE_ERROR;
|
||||
if (fread(header, 1, 4, fp) != 4) {
|
||||
fclose(fp);
|
||||
return AFILE_ERROR;
|
||||
}
|
||||
switch (header[0]) {
|
||||
case 0:
|
||||
if (header[1] == 0 && (header[2] != 0 || header[3] != 0) /* && file_length < 37 * 1024 */) {
|
||||
fclose(fp);
|
||||
return AFILE_BAS;
|
||||
}
|
||||
break;
|
||||
case 0x1f:
|
||||
if (header[1] == 0x8b) {
|
||||
#ifndef HAVE_LIBZ
|
||||
fclose(fp);
|
||||
Log_print("\"%s\" is a compressed file.", filename);
|
||||
Log_print("This executable does not support compressed files. You can uncompress this file");
|
||||
Log_print("with an external program that supports gzip (*.gz) files (e.g. gunzip)");
|
||||
Log_print("and then load into this emulator.");
|
||||
return AFILE_ERROR;
|
||||
#else /* HAVE_LIBZ */
|
||||
gzFile gzf;
|
||||
fclose(fp);
|
||||
gzf = gzopen(filename, "rb");
|
||||
if (gzf == NULL)
|
||||
return AFILE_ERROR;
|
||||
if (gzread(gzf, header, 4) != 4) {
|
||||
gzclose(gzf);
|
||||
return AFILE_ERROR;
|
||||
}
|
||||
gzclose(gzf);
|
||||
if (header[0] == 0x96 && header[1] == 0x02)
|
||||
return AFILE_ATR_GZ;
|
||||
if (header[0] == 'A' && header[1] == 'T' && header[2] == 'A' && header[3] == 'R')
|
||||
return AFILE_STATE_GZ;
|
||||
return AFILE_XFD_GZ;
|
||||
#endif /* HAVE_LIBZ */
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if ((header[1] >= '0' && header[1] <= '9') || header[1] == ' ') {
|
||||
fclose(fp);
|
||||
return AFILE_LST;
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
if (header[1] == 'T' && header[2] == 'A' && header[3] == 'R') {
|
||||
fclose(fp);
|
||||
return AFILE_STATE;
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
if (header[1] == 'A' && header[2] == 'R' && header[3] == 'T') {
|
||||
fclose(fp);
|
||||
return AFILE_CART;
|
||||
}
|
||||
break;
|
||||
case 'F':
|
||||
if (header[1] == 'U' && header[2] == 'J' && header[3] == 'I') {
|
||||
fclose(fp);
|
||||
return AFILE_CAS;
|
||||
}
|
||||
break;
|
||||
case 0x96:
|
||||
if (header[1] == 0x02) {
|
||||
fclose(fp);
|
||||
return AFILE_ATR;
|
||||
}
|
||||
break;
|
||||
case 0xf9:
|
||||
case 0xfa:
|
||||
fclose(fp);
|
||||
return AFILE_DCM;
|
||||
case 0xff:
|
||||
if (header[1] == 0xff && (header[2] != 0xff || header[3] != 0xff)) {
|
||||
fclose(fp);
|
||||
return AFILE_XEX;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
file_length = Util_flen(fp);
|
||||
fclose(fp);
|
||||
/* Detect .pro images */
|
||||
/* # of sectors is in header */
|
||||
if ((file_length-16)%(128+12) == 0 &&
|
||||
header[0]*256 + header[1] == (file_length-16)/(128+12) &&
|
||||
header[2] == 'P') {
|
||||
#ifdef DEBUG_PRO
|
||||
Log_print(".pro file detected");
|
||||
#endif
|
||||
return AFILE_PRO;
|
||||
}
|
||||
/* 40K or a-power-of-two between 4K and CARTRIDGE_MAX_SIZE */
|
||||
if (file_length >= 4 * 1024 && file_length <= CARTRIDGE_MAX_SIZE
|
||||
&& ((file_length & (file_length - 1)) == 0 || file_length == 40 * 1024))
|
||||
return AFILE_ROM;
|
||||
/* BOOT_TAPE is a raw file containing a program booted from a tape */
|
||||
if ((header[1] << 7) == file_length)
|
||||
return AFILE_BOOT_TAPE;
|
||||
if ((file_length & 0x7f) == 0)
|
||||
return AFILE_XFD;
|
||||
return AFILE_ERROR;
|
||||
}
|
||||
|
||||
int AFILE_OpenFile(const char *filename, int reboot, int diskno, int readonly)
|
||||
{
|
||||
int type = AFILE_DetectFileType(filename);
|
||||
switch (type) {
|
||||
case AFILE_ATR:
|
||||
case AFILE_XFD:
|
||||
case AFILE_ATR_GZ:
|
||||
case AFILE_XFD_GZ:
|
||||
case AFILE_DCM:
|
||||
case AFILE_PRO:
|
||||
if (!SIO_Mount(diskno, filename, readonly))
|
||||
return AFILE_ERROR;
|
||||
if (reboot)
|
||||
Atari800_Coldstart();
|
||||
break;
|
||||
case AFILE_XEX:
|
||||
case AFILE_BAS:
|
||||
case AFILE_LST:
|
||||
if (!BINLOAD_Loader(filename))
|
||||
return AFILE_ERROR;
|
||||
break;
|
||||
case AFILE_CART:
|
||||
case AFILE_ROM:
|
||||
/* TODO: select format for ROMs; switch 5200 ? */
|
||||
if (CARTRIDGE_Insert(filename) != 0)
|
||||
return AFILE_ERROR;
|
||||
if (reboot)
|
||||
Atari800_Coldstart();
|
||||
break;
|
||||
case AFILE_CAS:
|
||||
case AFILE_BOOT_TAPE:
|
||||
if (!CASSETTE_Insert(filename))
|
||||
return AFILE_ERROR;
|
||||
if (reboot) {
|
||||
CASSETTE_hold_start = TRUE;
|
||||
Atari800_Coldstart();
|
||||
}
|
||||
break;
|
||||
case AFILE_STATE:
|
||||
case AFILE_STATE_GZ:
|
||||
#ifdef BASIC
|
||||
Log_print("State files are not supported in BASIC version");
|
||||
return AFILE_ERROR;
|
||||
#else
|
||||
if (!StateSav_ReadAtariState(filename, "rb"))
|
||||
return AFILE_ERROR;
|
||||
/* Don't press Option */
|
||||
GTIA_consol_table[1] = GTIA_consol_table[2] = 0xf;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#ifndef AFILE_H_
|
||||
#define AFILE_H_
|
||||
|
||||
/* File types returned by AFILE_DetectFileType() and AFILE_OpenFile(). */
|
||||
#define AFILE_ERROR 0
|
||||
#define AFILE_ATR 1
|
||||
#define AFILE_XFD 2
|
||||
#define AFILE_ATR_GZ 3
|
||||
#define AFILE_XFD_GZ 4
|
||||
#define AFILE_DCM 5
|
||||
#define AFILE_XEX 6
|
||||
#define AFILE_BAS 7
|
||||
#define AFILE_LST 8
|
||||
#define AFILE_CART 9
|
||||
#define AFILE_ROM 10
|
||||
#define AFILE_CAS 11
|
||||
#define AFILE_BOOT_TAPE 12
|
||||
#define AFILE_STATE 13
|
||||
#define AFILE_STATE_GZ 14
|
||||
#define AFILE_PRO 15
|
||||
|
||||
/* ATR format header */
|
||||
struct AFILE_ATR_Header {
|
||||
unsigned char magic1;
|
||||
unsigned char magic2;
|
||||
unsigned char seccountlo;
|
||||
unsigned char seccounthi;
|
||||
unsigned char secsizelo;
|
||||
unsigned char secsizehi;
|
||||
unsigned char hiseccountlo;
|
||||
unsigned char hiseccounthi;
|
||||
unsigned char gash[7];
|
||||
unsigned char writeprotect;
|
||||
};
|
||||
|
||||
/* First two bytes of an ATR file. */
|
||||
#define AFILE_ATR_MAGIC1 0x96
|
||||
#define AFILE_ATR_MAGIC2 0x02
|
||||
|
||||
/* Auto-detects file type and returns one of AFILE_* values. */
|
||||
int AFILE_DetectFileType(const char *filename);
|
||||
|
||||
/* Auto-detects file type and mounts the file in the emulator.
|
||||
reboot: Atari800_Coldstart() for disks, cartridges and tapes
|
||||
diskno: drive number for disks (1-8)
|
||||
readonly: mount disks as read-only */
|
||||
int AFILE_OpenFile(const char *filename, int reboot, int diskno, int readonly);
|
||||
|
||||
#endif /* AFILE_H_ */
|
||||
@@ -1,246 +0,0 @@
|
||||
#ifndef AKEY_H_
|
||||
#define AKEY_H_
|
||||
/* akey.h: Atari key codes */
|
||||
|
||||
/* INPUT_key_code values */
|
||||
#define AKEY_NONE -1
|
||||
|
||||
/* Special key codes. */
|
||||
#define AKEY_WARMSTART -2
|
||||
#define AKEY_COLDSTART -3
|
||||
#define AKEY_EXIT -4
|
||||
#define AKEY_BREAK -5
|
||||
#define AKEY_UI -7
|
||||
#define AKEY_SCREENSHOT -8
|
||||
#define AKEY_SCREENSHOT_INTERLACE -9
|
||||
#define AKEY_START -10
|
||||
#define AKEY_SELECT -11
|
||||
#define AKEY_OPTION -12
|
||||
#define AKEY_PBI_BB_MENU -13
|
||||
#define AKEY_CX85_1 -14
|
||||
#define AKEY_CX85_2 -15
|
||||
#define AKEY_CX85_3 -16
|
||||
#define AKEY_CX85_4 -17
|
||||
#define AKEY_CX85_5 -18
|
||||
#define AKEY_CX85_6 -19
|
||||
#define AKEY_CX85_7 -20
|
||||
#define AKEY_CX85_8 -21
|
||||
#define AKEY_CX85_9 -22
|
||||
#define AKEY_CX85_0 -23
|
||||
#define AKEY_CX85_PERIOD -24
|
||||
#define AKEY_CX85_MINUS -25
|
||||
#define AKEY_CX85_PLUS_ENTER -26
|
||||
#define AKEY_CX85_ESCAPE -27
|
||||
#define AKEY_CX85_NO -28
|
||||
#define AKEY_CX85_DELETE -29
|
||||
#define AKEY_CX85_YES -30
|
||||
|
||||
#define AKEY_SHFT 0x40
|
||||
#define AKEY_CTRL 0x80
|
||||
#define AKEY_SHFTCTRL 0xc0
|
||||
|
||||
#define AKEY_0 0x32
|
||||
#define AKEY_1 0x1f
|
||||
#define AKEY_2 0x1e
|
||||
#define AKEY_3 0x1a
|
||||
#define AKEY_4 0x18
|
||||
#define AKEY_5 0x1d
|
||||
#define AKEY_6 0x1b
|
||||
#define AKEY_7 0x33
|
||||
#define AKEY_8 0x35
|
||||
#define AKEY_9 0x30
|
||||
|
||||
#define AKEY_CTRL_0 (AKEY_CTRL | AKEY_0)
|
||||
#define AKEY_CTRL_1 (AKEY_CTRL | AKEY_1)
|
||||
#define AKEY_CTRL_2 (AKEY_CTRL | AKEY_2)
|
||||
#define AKEY_CTRL_3 (AKEY_CTRL | AKEY_3)
|
||||
#define AKEY_CTRL_4 (AKEY_CTRL | AKEY_4)
|
||||
#define AKEY_CTRL_5 (AKEY_CTRL | AKEY_5)
|
||||
#define AKEY_CTRL_6 (AKEY_CTRL | AKEY_6)
|
||||
#define AKEY_CTRL_7 (AKEY_CTRL | AKEY_7)
|
||||
#define AKEY_CTRL_8 (AKEY_CTRL | AKEY_8)
|
||||
#define AKEY_CTRL_9 (AKEY_CTRL | AKEY_9)
|
||||
|
||||
#define AKEY_a 0x3f
|
||||
#define AKEY_b 0x15
|
||||
#define AKEY_c 0x12
|
||||
#define AKEY_d 0x3a
|
||||
#define AKEY_e 0x2a
|
||||
#define AKEY_f 0x38
|
||||
#define AKEY_g 0x3d
|
||||
#define AKEY_h 0x39
|
||||
#define AKEY_i 0x0d
|
||||
#define AKEY_j 0x01
|
||||
#define AKEY_k 0x05
|
||||
#define AKEY_l 0x00
|
||||
#define AKEY_m 0x25
|
||||
#define AKEY_n 0x23
|
||||
#define AKEY_o 0x08
|
||||
#define AKEY_p 0x0a
|
||||
#define AKEY_q 0x2f
|
||||
#define AKEY_r 0x28
|
||||
#define AKEY_s 0x3e
|
||||
#define AKEY_t 0x2d
|
||||
#define AKEY_u 0x0b
|
||||
#define AKEY_v 0x10
|
||||
#define AKEY_w 0x2e
|
||||
#define AKEY_x 0x16
|
||||
#define AKEY_y 0x2b
|
||||
#define AKEY_z 0x17
|
||||
|
||||
#define AKEY_A (AKEY_SHFT | AKEY_a)
|
||||
#define AKEY_B (AKEY_SHFT | AKEY_b)
|
||||
#define AKEY_C (AKEY_SHFT | AKEY_c)
|
||||
#define AKEY_D (AKEY_SHFT | AKEY_d)
|
||||
#define AKEY_E (AKEY_SHFT | AKEY_e)
|
||||
#define AKEY_F (AKEY_SHFT | AKEY_f)
|
||||
#define AKEY_G (AKEY_SHFT | AKEY_g)
|
||||
#define AKEY_H (AKEY_SHFT | AKEY_h)
|
||||
#define AKEY_I (AKEY_SHFT | AKEY_i)
|
||||
#define AKEY_J (AKEY_SHFT | AKEY_j)
|
||||
#define AKEY_K (AKEY_SHFT | AKEY_k)
|
||||
#define AKEY_L (AKEY_SHFT | AKEY_l)
|
||||
#define AKEY_M (AKEY_SHFT | AKEY_m)
|
||||
#define AKEY_N (AKEY_SHFT | AKEY_n)
|
||||
#define AKEY_O (AKEY_SHFT | AKEY_o)
|
||||
#define AKEY_P (AKEY_SHFT | AKEY_p)
|
||||
#define AKEY_Q (AKEY_SHFT | AKEY_q)
|
||||
#define AKEY_R (AKEY_SHFT | AKEY_r)
|
||||
#define AKEY_S (AKEY_SHFT | AKEY_s)
|
||||
#define AKEY_T (AKEY_SHFT | AKEY_t)
|
||||
#define AKEY_U (AKEY_SHFT | AKEY_u)
|
||||
#define AKEY_V (AKEY_SHFT | AKEY_v)
|
||||
#define AKEY_W (AKEY_SHFT | AKEY_w)
|
||||
#define AKEY_X (AKEY_SHFT | AKEY_x)
|
||||
#define AKEY_Y (AKEY_SHFT | AKEY_y)
|
||||
#define AKEY_Z (AKEY_SHFT | AKEY_z)
|
||||
|
||||
#define AKEY_CTRL_a (AKEY_CTRL | AKEY_a)
|
||||
#define AKEY_CTRL_b (AKEY_CTRL | AKEY_b)
|
||||
#define AKEY_CTRL_c (AKEY_CTRL | AKEY_c)
|
||||
#define AKEY_CTRL_d (AKEY_CTRL | AKEY_d)
|
||||
#define AKEY_CTRL_e (AKEY_CTRL | AKEY_e)
|
||||
#define AKEY_CTRL_f (AKEY_CTRL | AKEY_f)
|
||||
#define AKEY_CTRL_g (AKEY_CTRL | AKEY_g)
|
||||
#define AKEY_CTRL_h (AKEY_CTRL | AKEY_h)
|
||||
#define AKEY_CTRL_i (AKEY_CTRL | AKEY_i)
|
||||
#define AKEY_CTRL_j (AKEY_CTRL | AKEY_j)
|
||||
#define AKEY_CTRL_k (AKEY_CTRL | AKEY_k)
|
||||
#define AKEY_CTRL_l (AKEY_CTRL | AKEY_l)
|
||||
#define AKEY_CTRL_m (AKEY_CTRL | AKEY_m)
|
||||
#define AKEY_CTRL_n (AKEY_CTRL | AKEY_n)
|
||||
#define AKEY_CTRL_o (AKEY_CTRL | AKEY_o)
|
||||
#define AKEY_CTRL_p (AKEY_CTRL | AKEY_p)
|
||||
#define AKEY_CTRL_q (AKEY_CTRL | AKEY_q)
|
||||
#define AKEY_CTRL_r (AKEY_CTRL | AKEY_r)
|
||||
#define AKEY_CTRL_s (AKEY_CTRL | AKEY_s)
|
||||
#define AKEY_CTRL_t (AKEY_CTRL | AKEY_t)
|
||||
#define AKEY_CTRL_u (AKEY_CTRL | AKEY_u)
|
||||
#define AKEY_CTRL_v (AKEY_CTRL | AKEY_v)
|
||||
#define AKEY_CTRL_w (AKEY_CTRL | AKEY_w)
|
||||
#define AKEY_CTRL_x (AKEY_CTRL | AKEY_x)
|
||||
#define AKEY_CTRL_y (AKEY_CTRL | AKEY_y)
|
||||
#define AKEY_CTRL_z (AKEY_CTRL | AKEY_z)
|
||||
|
||||
#define AKEY_CTRL_A (AKEY_CTRL | AKEY_A)
|
||||
#define AKEY_CTRL_B (AKEY_CTRL | AKEY_B)
|
||||
#define AKEY_CTRL_C (AKEY_CTRL | AKEY_C)
|
||||
#define AKEY_CTRL_D (AKEY_CTRL | AKEY_D)
|
||||
#define AKEY_CTRL_E (AKEY_CTRL | AKEY_E)
|
||||
#define AKEY_CTRL_F (AKEY_CTRL | AKEY_F)
|
||||
#define AKEY_CTRL_G (AKEY_CTRL | AKEY_G)
|
||||
#define AKEY_CTRL_H (AKEY_CTRL | AKEY_H)
|
||||
#define AKEY_CTRL_I (AKEY_CTRL | AKEY_I)
|
||||
#define AKEY_CTRL_J (AKEY_CTRL | AKEY_J)
|
||||
#define AKEY_CTRL_K (AKEY_CTRL | AKEY_K)
|
||||
#define AKEY_CTRL_L (AKEY_CTRL | AKEY_L)
|
||||
#define AKEY_CTRL_M (AKEY_CTRL | AKEY_M)
|
||||
#define AKEY_CTRL_N (AKEY_CTRL | AKEY_N)
|
||||
#define AKEY_CTRL_O (AKEY_CTRL | AKEY_O)
|
||||
#define AKEY_CTRL_P (AKEY_CTRL | AKEY_P)
|
||||
#define AKEY_CTRL_Q (AKEY_CTRL | AKEY_Q)
|
||||
#define AKEY_CTRL_R (AKEY_CTRL | AKEY_R)
|
||||
#define AKEY_CTRL_S (AKEY_CTRL | AKEY_S)
|
||||
#define AKEY_CTRL_T (AKEY_CTRL | AKEY_T)
|
||||
#define AKEY_CTRL_U (AKEY_CTRL | AKEY_U)
|
||||
#define AKEY_CTRL_V (AKEY_CTRL | AKEY_V)
|
||||
#define AKEY_CTRL_W (AKEY_CTRL | AKEY_W)
|
||||
#define AKEY_CTRL_X (AKEY_CTRL | AKEY_X)
|
||||
#define AKEY_CTRL_Y (AKEY_CTRL | AKEY_Y)
|
||||
#define AKEY_CTRL_Z (AKEY_CTRL | AKEY_Z)
|
||||
|
||||
#define AKEY_HELP 0x11
|
||||
#define AKEY_DOWN 0x8f
|
||||
#define AKEY_LEFT 0x86
|
||||
#define AKEY_RIGHT 0x87
|
||||
#define AKEY_UP 0x8e
|
||||
#define AKEY_BACKSPACE 0x34
|
||||
#define AKEY_DELETE_CHAR 0xb4
|
||||
#define AKEY_DELETE_LINE 0x74
|
||||
#define AKEY_INSERT_CHAR 0xb7
|
||||
#define AKEY_INSERT_LINE 0x77
|
||||
#define AKEY_ESCAPE 0x1c
|
||||
#define AKEY_ATARI 0x27
|
||||
#define AKEY_CAPSLOCK 0x7c
|
||||
#define AKEY_CAPSTOGGLE 0x3c
|
||||
#define AKEY_TAB 0x2c
|
||||
#define AKEY_SETTAB 0x6c
|
||||
#define AKEY_CLRTAB 0xac
|
||||
#define AKEY_RETURN 0x0c
|
||||
#define AKEY_SPACE 0x21
|
||||
#define AKEY_EXCLAMATION 0x5f
|
||||
#define AKEY_DBLQUOTE 0x5e
|
||||
#define AKEY_HASH 0x5a
|
||||
#define AKEY_DOLLAR 0x58
|
||||
#define AKEY_PERCENT 0x5d
|
||||
#define AKEY_AMPERSAND 0x5b
|
||||
#define AKEY_QUOTE 0x73
|
||||
#define AKEY_AT 0x75
|
||||
#define AKEY_PARENLEFT 0x70
|
||||
#define AKEY_PARENRIGHT 0x72
|
||||
#define AKEY_LESS 0x36
|
||||
#define AKEY_GREATER 0x37
|
||||
#define AKEY_EQUAL 0x0f
|
||||
#define AKEY_QUESTION 0x66
|
||||
#define AKEY_MINUS 0x0e
|
||||
#define AKEY_PLUS 0x06
|
||||
#define AKEY_ASTERISK 0x07
|
||||
#define AKEY_SLASH 0x26
|
||||
#define AKEY_COLON 0x42
|
||||
#define AKEY_SEMICOLON 0x02
|
||||
#define AKEY_COMMA 0x20
|
||||
#define AKEY_FULLSTOP 0x22
|
||||
#define AKEY_UNDERSCORE 0x4e
|
||||
#define AKEY_BRACKETLEFT 0x60
|
||||
#define AKEY_BRACKETRIGHT 0x62
|
||||
#define AKEY_CIRCUMFLEX 0x47
|
||||
#define AKEY_BACKSLASH 0x46
|
||||
#define AKEY_BAR 0x4f
|
||||
#define AKEY_CLEAR (AKEY_SHFT | AKEY_LESS)
|
||||
#define AKEY_CARET (AKEY_SHFT | AKEY_ASTERISK)
|
||||
#define AKEY_F1 0x03
|
||||
#define AKEY_F2 0x04
|
||||
#define AKEY_F3 0x13
|
||||
#define AKEY_F4 0x14
|
||||
|
||||
/* Following keys cannot be read with both shift and control pressed:
|
||||
J K L ; + * Z X C V B F1 F2 F3 F4 HELP */
|
||||
|
||||
/* 5200 key codes */
|
||||
#define AKEY_5200_START 0x39
|
||||
#define AKEY_5200_PAUSE 0x31
|
||||
#define AKEY_5200_RESET 0x29
|
||||
#define AKEY_5200_0 0x25
|
||||
#define AKEY_5200_1 0x3f
|
||||
#define AKEY_5200_2 0x3d
|
||||
#define AKEY_5200_3 0x3b
|
||||
#define AKEY_5200_4 0x37
|
||||
#define AKEY_5200_5 0x35
|
||||
#define AKEY_5200_6 0x33
|
||||
#define AKEY_5200_7 0x2f
|
||||
#define AKEY_5200_8 0x2d
|
||||
#define AKEY_5200_9 0x2b
|
||||
#define AKEY_5200_HASH 0x23
|
||||
#define AKEY_5200_ASTERISK 0x27
|
||||
|
||||
#endif /* AKEY_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,137 +0,0 @@
|
||||
#ifndef ANTIC_H_
|
||||
#define ANTIC_H_
|
||||
|
||||
#include "atari.h"
|
||||
|
||||
/*
|
||||
* Offset to registers in custom relative to start of antic memory addresses.
|
||||
*/
|
||||
|
||||
#define ANTIC_OFFSET_DMACTL 0x00
|
||||
#define ANTIC_OFFSET_CHACTL 0x01
|
||||
#define ANTIC_OFFSET_DLISTL 0x02
|
||||
#define ANTIC_OFFSET_DLISTH 0x03
|
||||
#define ANTIC_OFFSET_HSCROL 0x04
|
||||
#define ANTIC_OFFSET_VSCROL 0x05
|
||||
#define ANTIC_OFFSET_PMBASE 0x07
|
||||
#define ANTIC_OFFSET_CHBASE 0x09
|
||||
#define ANTIC_OFFSET_WSYNC 0x0a
|
||||
#define ANTIC_OFFSET_VCOUNT 0x0b
|
||||
#define ANTIC_OFFSET_PENH 0x0c
|
||||
#define ANTIC_OFFSET_PENV 0x0d
|
||||
#define ANTIC_OFFSET_NMIEN 0x0e
|
||||
#define ANTIC_OFFSET_NMIRES 0x0f
|
||||
#define ANTIC_OFFSET_NMIST 0x0f
|
||||
|
||||
extern UBYTE ANTIC_CHACTL;
|
||||
extern UBYTE ANTIC_CHBASE;
|
||||
extern UWORD ANTIC_dlist;
|
||||
extern UBYTE ANTIC_DMACTL;
|
||||
extern UBYTE ANTIC_HSCROL;
|
||||
extern UBYTE ANTIC_NMIEN;
|
||||
extern UBYTE ANTIC_NMIST;
|
||||
extern UBYTE ANTIC_PMBASE;
|
||||
extern UBYTE ANTIC_VSCROL;
|
||||
|
||||
extern int ANTIC_break_ypos;
|
||||
extern int ANTIC_ypos;
|
||||
extern int ANTIC_wsync_halt;
|
||||
|
||||
/* Current clock cycle in a scanline.
|
||||
Normally 0 <= ANTIC_xpos && ANTIC_xpos < ANTIC_LINE_C, but in some cases ANTIC_xpos >= ANTIC_LINE_C,
|
||||
which means that we are already in line (ypos + 1). */
|
||||
extern int ANTIC_xpos;
|
||||
|
||||
/* ANTIC_xpos limit for the currently running 6502 emulation. */
|
||||
extern int ANTIC_xpos_limit;
|
||||
|
||||
/* Main clock value at the beginning of the current scanline. */
|
||||
extern unsigned int ANTIC_screenline_cpu_clock;
|
||||
|
||||
/* Current main clock value. */
|
||||
#define ANTIC_CPU_CLOCK (ANTIC_screenline_cpu_clock + ANTIC_xpos)
|
||||
|
||||
#define ANTIC_NMIST_C 6
|
||||
#define ANTIC_NMI_C 12
|
||||
|
||||
/* Number of cycles per scanline. */
|
||||
#define ANTIC_LINE_C 114
|
||||
|
||||
/* STA WSYNC resumes here. */
|
||||
#define ANTIC_WSYNC_C 106
|
||||
|
||||
/* Number of memory refresh cycles per scanline.
|
||||
In the first scanline of a font mode there are actually less than ANTIC_DMAR
|
||||
memory refresh cycles. */
|
||||
#define ANTIC_DMAR 9
|
||||
|
||||
extern int ANTIC_artif_mode;
|
||||
extern int ANTIC_artif_new;
|
||||
|
||||
extern UBYTE ANTIC_PENH_input;
|
||||
extern UBYTE ANTIC_PENV_input;
|
||||
|
||||
int ANTIC_Initialise(int *argc, char *argv[]);
|
||||
void ANTIC_Reset(void);
|
||||
void ANTIC_Frame(int draw_display);
|
||||
UBYTE ANTIC_GetByte(UWORD addr);
|
||||
void ANTIC_PutByte(UWORD addr, UBYTE byte);
|
||||
|
||||
UBYTE ANTIC_GetDLByte(UWORD *paddr);
|
||||
UWORD ANTIC_GetDLWord(UWORD *paddr);
|
||||
|
||||
/* always call ANTIC_UpdateArtifacting after changing ANTIC_artif_mode */
|
||||
void ANTIC_UpdateArtifacting(void);
|
||||
|
||||
/* Video memory access */
|
||||
void ANTIC_VideoMemset(UBYTE *ptr, UBYTE val, ULONG size);
|
||||
void ANTIC_VideoPutByte(UBYTE *ptr, UBYTE val);
|
||||
|
||||
/* GTIA calls it on a write to PRIOR */
|
||||
void ANTIC_SetPrior(UBYTE prior);
|
||||
|
||||
/* Saved states */
|
||||
void ANTIC_StateSave(void);
|
||||
void ANTIC_StateRead(void);
|
||||
|
||||
/* Pointer to 16 KB seen by ANTIC in 0x4000-0x7fff.
|
||||
If it's the same what the CPU sees (and what's in memory[0x4000..0x7fff],
|
||||
then NULL. */
|
||||
extern const UBYTE *ANTIC_xe_ptr;
|
||||
|
||||
/* PM graphics for GTIA */
|
||||
extern int ANTIC_player_dma_enabled;
|
||||
extern int ANTIC_missile_dma_enabled;
|
||||
extern int ANTIC_player_gra_enabled;
|
||||
extern int ANTIC_missile_gra_enabled;
|
||||
extern int ANTIC_player_flickering;
|
||||
extern int ANTIC_missile_flickering;
|
||||
|
||||
/* ANTIC colour lookup tables, used by GTIA */
|
||||
extern UWORD ANTIC_cl[128];
|
||||
extern ULONG ANTIC_lookup_gtia9[16];
|
||||
extern ULONG ANTIC_lookup_gtia11[16];
|
||||
extern UWORD ANTIC_hires_lookup_l[128];
|
||||
|
||||
#ifdef NEW_CYCLE_EXACT
|
||||
#define ANTIC_NOT_DRAWING -999
|
||||
#define ANTIC_DRAWING_SCREEN (ANTIC_cur_screen_pos!=ANTIC_NOT_DRAWING)
|
||||
extern int ANTIC_delayed_wsync;
|
||||
extern int ANTIC_cur_screen_pos;
|
||||
extern const int *ANTIC_cpu2antic_ptr;
|
||||
extern const int *ANTIC_antic2cpu_ptr;
|
||||
void ANTIC_UpdateScanline(void);
|
||||
void ANTIC_UpdateScanlinePrior(UBYTE byte);
|
||||
#ifndef NO_GTIA11_DELAY
|
||||
extern int ANTIC_prior_curpos;
|
||||
#define ANTIC_PRIOR_BUF_SIZE 40
|
||||
extern UBYTE ANTIC_prior_val_buf[ANTIC_PRIOR_BUF_SIZE];
|
||||
extern int ANTIC_prior_pos_buf[ANTIC_PRIOR_BUF_SIZE];
|
||||
#endif /* NO_GTIA11_DELAY */
|
||||
|
||||
#define ANTIC_XPOS ( ANTIC_DRAWING_SCREEN ? ANTIC_cpu2antic_ptr[ANTIC_xpos] : ANTIC_xpos )
|
||||
#else
|
||||
#define ANTIC_XPOS ANTIC_xpos
|
||||
#endif /* NEW_CYCLE_EXACT */
|
||||
|
||||
#endif /* ANTIC_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,135 +0,0 @@
|
||||
#ifndef ATARI_H_
|
||||
#define ATARI_H_
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h> /* FILENAME_MAX */
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
/* Fundamental declarations ---------------------------------------------- */
|
||||
|
||||
#define Atari800_TITLE "Atari 800 Emulator, Version 2.1.0"
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
/* SBYTE and UBYTE must be exactly 1 byte long. */
|
||||
/* SWORD and UWORD must be exactly 2 bytes long. */
|
||||
/* SLONG and ULONG must be exactly 4 bytes long. */
|
||||
#define SBYTE signed char
|
||||
#define SWORD signed short
|
||||
#define SLONG signed int
|
||||
#define UBYTE unsigned char
|
||||
#define UWORD unsigned short
|
||||
#ifndef WIN32
|
||||
/* Windows headers typedef ULONG */
|
||||
#define ULONG unsigned int
|
||||
#endif
|
||||
/* Note: in various parts of the emulator we assume that char is 1 byte
|
||||
and int is 4 bytes. */
|
||||
|
||||
|
||||
/* Public interface ------------------------------------------------------ */
|
||||
|
||||
/* Machine type. */
|
||||
#define Atari800_MACHINE_OSA 0
|
||||
#define Atari800_MACHINE_OSB 1
|
||||
#define Atari800_MACHINE_XLXE 2
|
||||
#define Atari800_MACHINE_5200 3
|
||||
extern int Atari800_machine_type;
|
||||
|
||||
/* Always call Atari800_InitialiseMachine() after changing Atari800_machine_type
|
||||
or MEMORY_ram_size! */
|
||||
|
||||
/* Video system. */
|
||||
#define Atari800_TV_UNSET 0
|
||||
#define Atari800_TV_PAL 312
|
||||
#define Atari800_TV_NTSC 262
|
||||
|
||||
/* Video system / Number of scanlines per frame. */
|
||||
extern int Atari800_tv_mode;
|
||||
|
||||
/* TRUE to disable Atari BASIC when booting Atari (hold Option in XL/XE). */
|
||||
extern int Atari800_disable_basic;
|
||||
|
||||
/* If Atari800_Frame() sets it to TRUE, then the current contents
|
||||
of Screen_atari should be displayed. */
|
||||
extern int Atari800_display_screen;
|
||||
|
||||
/* Simply incremented by Atari800_Frame(). */
|
||||
extern int Atari800_nframes;
|
||||
|
||||
/* How often the screen is updated (1 = every Atari frame). */
|
||||
extern int Atari800_refresh_rate;
|
||||
|
||||
/* Set to TRUE for faster emulation with Atari800_refresh_rate > 1.
|
||||
Set to FALSE for accurate emulation with Atari800_refresh_rate > 1. */
|
||||
extern int Atari800_collisions_in_skipped_frames;
|
||||
|
||||
/* Initializes Atari800 emulation core. */
|
||||
int Atari800_Initialise(int *argc, char *argv[]);
|
||||
|
||||
/* Emulates one frame (1/50sec for PAL, 1/60sec for NTSC). */
|
||||
void Atari800_Frame(void);
|
||||
|
||||
/* Reboots the emulated Atari. */
|
||||
void Atari800_Coldstart(void);
|
||||
|
||||
/* Presses the Reset key in the emulated Atari. */
|
||||
void Atari800_Warmstart(void);
|
||||
|
||||
/* Reinitializes after Atari800_machine_type or ram_size change.
|
||||
You should call Atari800_Coldstart() after it. */
|
||||
int Atari800_InitialiseMachine(void);
|
||||
|
||||
/* Shuts down Atari800 emulation core. */
|
||||
int Atari800_Exit(int run_monitor);
|
||||
|
||||
|
||||
/* Private interface ----------------------------------------------------- */
|
||||
/* Don't use outside the emulation core! */
|
||||
|
||||
/* STAT_UNALIGNED_WORDS is solely for benchmarking purposes.
|
||||
8-element arrays (stat_arr) represent number of accesses with the given
|
||||
value of 3 least significant bits of address. This gives us information
|
||||
about the ratio of aligned vs unaligned accesses. */
|
||||
#ifdef STAT_UNALIGNED_WORDS
|
||||
#define UNALIGNED_STAT_DEF(stat_arr) unsigned int stat_arr[8];
|
||||
#define UNALIGNED_STAT_DECL(stat_arr) extern unsigned int stat_arr[8];
|
||||
#define UNALIGNED_GET_WORD(ptr, stat_arr) (stat_arr[(unsigned int) (ptr) & 7]++, *(const UWORD *) (ptr))
|
||||
#define UNALIGNED_PUT_WORD(ptr, value, stat_arr) (stat_arr[(unsigned int) (ptr) & 7]++, *(UWORD *) (ptr) = (value))
|
||||
#define UNALIGNED_GET_LONG(ptr, stat_arr) (stat_arr[(unsigned int) (ptr) & 7]++, *(const ULONG *) (ptr))
|
||||
#define UNALIGNED_PUT_LONG(ptr, value, stat_arr) (stat_arr[(unsigned int) (ptr) & 7]++, *(ULONG *) (ptr) = (value))
|
||||
UNALIGNED_STAT_DECL(Screen_atari_write_long_stat)
|
||||
UNALIGNED_STAT_DECL(pm_scanline_read_long_stat)
|
||||
UNALIGNED_STAT_DECL(memory_read_word_stat)
|
||||
UNALIGNED_STAT_DECL(memory_write_word_stat)
|
||||
UNALIGNED_STAT_DECL(memory_read_aligned_word_stat)
|
||||
UNALIGNED_STAT_DECL(memory_write_aligned_word_stat)
|
||||
#else
|
||||
#define UNALIGNED_STAT_DEF(stat_arr)
|
||||
#define UNALIGNED_STAT_DECL(stat_arr)
|
||||
#define UNALIGNED_GET_WORD(ptr, stat_arr) (*(const UWORD *) (ptr))
|
||||
#define UNALIGNED_PUT_WORD(ptr, value, stat_arr) (*(UWORD *) (ptr) = (value))
|
||||
#define UNALIGNED_GET_LONG(ptr, stat_arr) (*(const ULONG *) (ptr))
|
||||
#define UNALIGNED_PUT_LONG(ptr, value, stat_arr) (*(ULONG *) (ptr) = (value))
|
||||
#endif
|
||||
|
||||
/* Sleeps until it's time to emulate next Atari frame. */
|
||||
void Atari800_Sync(void);
|
||||
|
||||
/* Load a ROM image filename of size nbytes into buffer */
|
||||
int Atari800_LoadImage(const char *filename, UBYTE *buffer, int nbytes);
|
||||
|
||||
/* Save State */
|
||||
void Atari800_StateSave(void);
|
||||
|
||||
/* Read State */
|
||||
void Atari800_StateRead(void);
|
||||
|
||||
#endif /* ATARI_H_ */
|
||||
@@ -1,487 +0,0 @@
|
||||
|
||||
/* http://www.slack.net/~ant/ */
|
||||
|
||||
/* compilable in C or C++; just change the file extension */
|
||||
|
||||
#include "atari_ntsc.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
/* Based on algorithm by NewRisingSun */
|
||||
/* License note by Perry: Expat License.
|
||||
* http://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses
|
||||
* "This is a simple, permissive non-copyleft free software license, compatible with the GNU GPL."*/
|
||||
/* Copyright (C) 2006 Shay Green. Permission is hereby granted, free of
|
||||
charge, to any person obtaining a copy of this software module and associated
|
||||
documentation files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use, copy, modify,
|
||||
merge, publish, distribute, sublicense, and/or sell copies of the Software, and
|
||||
to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions: The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions of the Software. THE
|
||||
SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
|
||||
enum { composite_border = 6 };
|
||||
enum { center_offset = 1 };
|
||||
enum { alignment_count = 4 }; /* different pixel alignments with respect to yiq quads */
|
||||
enum { rgb_kernel_size = atari_ntsc_entry_size / alignment_count };
|
||||
|
||||
/* important to use + and not | since values are signed */
|
||||
#define MAKE_KRGB( r, g, b ) \
|
||||
( ((r + 16) >> 5 << 20) + ((g + 16) >> 5 << 10) + ((b + 16) >> 5) )
|
||||
static float const rgb_unit = 0x1000;
|
||||
|
||||
#define MAKE_KMASK( x ) (((x) << 20) | ((x) << 10) | (x))
|
||||
|
||||
/* clamp each RGB component to 0 to 0x7F range (low two bits are trashed) */
|
||||
#define CLAMP_RGB( io, adj ) {\
|
||||
ntsc_rgb_t sub = (io) >> (7 + adj) & MAKE_KMASK( 3 );\
|
||||
ntsc_rgb_t clamp = MAKE_KMASK( 0x202 ) - sub;\
|
||||
io = ((io) | clamp) & (clamp - sub);\
|
||||
}
|
||||
|
||||
enum { composite_size = composite_border + 8 + composite_border };
|
||||
enum { rgb_pad = (center_offset + composite_border + 7) / 8 * 8 - center_offset - composite_border };
|
||||
enum { rgb_size = (rgb_pad + composite_size + 7) / 8 * 8 };
|
||||
enum { rescaled_size = rgb_size / 8 * 7 };
|
||||
enum { ntsc_kernel_size = composite_size * 2 };
|
||||
|
||||
typedef struct ntsc_to_rgb_t
|
||||
{
|
||||
float composite [composite_size];
|
||||
float to_rgb [6];
|
||||
float brightness;
|
||||
float contrast;
|
||||
float sharpness;
|
||||
short rgb [rgb_size] [3];
|
||||
short rescaled [rescaled_size + 1] [3]; /* extra space for sharpen */
|
||||
float kernel [ntsc_kernel_size];
|
||||
} ntsc_to_rgb_t;
|
||||
|
||||
static float const pi = 3.14159265358979323846f;
|
||||
|
||||
static void rotate_matrix( float const* in, float s, float c, float* out )
|
||||
{
|
||||
int n = 3;
|
||||
while ( n-- )
|
||||
{
|
||||
float i = *in++;
|
||||
float q = *in++;
|
||||
*out++ = i * c - q * s;
|
||||
*out++ = i * s + q * c;
|
||||
}
|
||||
}
|
||||
|
||||
static void ntsc_to_rgb_init( ntsc_to_rgb_t* ntsc, atari_ntsc_setup_t const* setup, float hue )
|
||||
{
|
||||
static float const to_rgb [6] = { 0.956, 0.621, -0.272, -0.647, -1.105, 1.702 };
|
||||
float gaussian_factor = 1+setup->gaussian_factor; /* 1 = normal, > 1 reduces echoes of bright objects (was 2.1)*/
|
||||
float const brightness_bias = rgb_unit / 128; /* reduces vert bands on artifact colored areas */
|
||||
int i;
|
||||
/* ranges need to be scaled a bit to avoid pixels overflowing at extremes */
|
||||
ntsc->brightness = (setup->brightness-0.0f) * (0.4f * rgb_unit) + brightness_bias;
|
||||
ntsc->contrast = (setup->contrast-0.0f) * 0.4f + 1;
|
||||
ntsc->sharpness = 1 + (setup->sharpness < 0 ? setup->sharpness * 0.5f : setup->sharpness);
|
||||
|
||||
for ( i = 0; i < composite_size; i++ )
|
||||
ntsc->composite [i] = 0;
|
||||
|
||||
/* Generate gaussian kernel, padded with zero */
|
||||
for ( i = 0; i < ntsc_kernel_size; i++ )
|
||||
ntsc->kernel [i] = 0;
|
||||
for ( i = -composite_border; i <= composite_border; i++ )
|
||||
ntsc->kernel [ntsc_kernel_size / 2 + i] = exp( i * i * (-0.03125f * gaussian_factor) );
|
||||
|
||||
/* normalize kernel totals of every fourth sample (at all four phases) to 0.5, otherwise */
|
||||
/* i/q low-pass will favor one of the four alignments and cause repeating spots */
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
double sum = 0;
|
||||
float scale;
|
||||
int x;
|
||||
for ( x = i; x < ntsc_kernel_size; x += 4 )
|
||||
sum += ntsc->kernel [x];
|
||||
scale = 0.5 / sum;
|
||||
for ( x = i; x < ntsc_kernel_size; x += 4 )
|
||||
ntsc->kernel [x] *= scale;
|
||||
}
|
||||
|
||||
/* adjust decoder matrix */
|
||||
{
|
||||
float sat = setup->saturation + 1;
|
||||
rotate_matrix( to_rgb, sin( hue ) * sat, cos( hue ) * sat, ntsc->to_rgb );
|
||||
}
|
||||
|
||||
memset( ntsc->rgb, 0, sizeof ntsc->rgb );
|
||||
}
|
||||
|
||||
/* Convert NTSC composite signal to RGB, where composite signal contains only four
|
||||
non-zero samples beginning at offset */
|
||||
static void ntsc_to_rgb( ntsc_to_rgb_t const* ntsc, int offset, short* out )
|
||||
{
|
||||
float const* kernel = &ntsc->kernel [ntsc_kernel_size / 2 - offset];
|
||||
float f0 = ntsc->composite [offset];
|
||||
float f1 = ntsc->composite [offset + 1];
|
||||
float f2 = ntsc->composite [offset + 2];
|
||||
float f3 = ntsc->composite [offset + 3];
|
||||
int x = 0;
|
||||
while ( x < composite_size )
|
||||
{
|
||||
#define PIXEL( get_y ) \
|
||||
{\
|
||||
float i = kernel [ 0] * f0 + kernel [-2] * f2;\
|
||||
float q = kernel [-1] * f1 + kernel [-3] * f3;\
|
||||
float y = get_y;\
|
||||
float r = y + i * ntsc->to_rgb [0] + q * ntsc->to_rgb [1];\
|
||||
float g = y + i * ntsc->to_rgb [2] + q * ntsc->to_rgb [3];\
|
||||
float b = y + i * ntsc->to_rgb [4] + q * ntsc->to_rgb [5];\
|
||||
kernel++;\
|
||||
out [0] = (int) r;\
|
||||
out [1] = (int) g;\
|
||||
out [2] = (int) b;\
|
||||
out += 3;\
|
||||
}
|
||||
|
||||
PIXEL( i - ntsc->composite [x + 0] )
|
||||
PIXEL( q - ntsc->composite [x + 1] )
|
||||
PIXEL( ntsc->composite [x + 2] - i )
|
||||
PIXEL( ntsc->composite [x + 3] - q )
|
||||
x += 4;
|
||||
|
||||
#undef PIXEL
|
||||
}
|
||||
}
|
||||
|
||||
/* Rescale pixels to NTSC aspect ratio using linear interpolation,
|
||||
with 7 output pixels for every 8 input pixels, linear interpolation */
|
||||
static void rescale( short const* in, int count, short* out )
|
||||
{
|
||||
do
|
||||
{
|
||||
int const accuracy = 16;
|
||||
int const unit = 1 << accuracy;
|
||||
int const step = unit / 8;
|
||||
int left = unit - step;
|
||||
int right = step;
|
||||
int n = 7;
|
||||
while ( n-- )
|
||||
{
|
||||
int r = (in [0] * left + in [3] * right) >> accuracy;
|
||||
int g = (in [1] * left + in [4] * right) >> accuracy;
|
||||
int b = (in [2] * left + in [5] * right) >> accuracy;
|
||||
*out++ = r;
|
||||
*out++ = g;
|
||||
*out++ = b;
|
||||
left -= step;
|
||||
right += step;
|
||||
in += 3;
|
||||
}
|
||||
in += 3;
|
||||
}
|
||||
while ( (count -= 7) > 0 );
|
||||
}
|
||||
|
||||
/* sharpen image using (level-1)/2, level, (level-1)/2 convolution kernel */
|
||||
static void sharpen( short const* in, float level, int count, short* out )
|
||||
{
|
||||
/* to do: sharpen luma only? */
|
||||
int const accuracy = 16;
|
||||
int const middle = (int) (level * (1 << accuracy));
|
||||
int const side = (middle - (1 << accuracy)) >> 1;
|
||||
|
||||
*out++ = *in++;
|
||||
*out++ = *in++;
|
||||
*out++ = *in++;
|
||||
|
||||
for ( count = (count - 2) * 3; count--; in++ )
|
||||
*out++ = (in [0] * middle - in [-3] * side - in [3] * side) >> accuracy;
|
||||
*out++ = *in++;
|
||||
*out++ = *in++;
|
||||
*out++ = *in++;
|
||||
}
|
||||
|
||||
/* Generate pixel and capture into table */
|
||||
static ntsc_rgb_t* gen_pixel( ntsc_to_rgb_t* ntsc, int ntsc_pos, int rescaled_pos, ntsc_rgb_t* out )
|
||||
{
|
||||
ntsc_to_rgb( ntsc, composite_border + ntsc_pos, ntsc->rgb [rgb_pad] );
|
||||
rescale( ntsc->rgb [0], rescaled_size, ntsc->rescaled [1] );
|
||||
sharpen( ntsc->rescaled [1], ntsc->sharpness, rescaled_size, ntsc->rescaled [0] );
|
||||
|
||||
{
|
||||
short const* in = ntsc->rescaled [rescaled_pos];
|
||||
int n = rgb_kernel_size;
|
||||
while ( n-- )
|
||||
{
|
||||
*out++ = MAKE_KRGB( in [0], in [1], in [2] );
|
||||
in += 3;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
void atari_ntsc_init( atari_ntsc_t* emu, atari_ntsc_setup_t const* setup )
|
||||
{
|
||||
|
||||
/* init pixel renderer */
|
||||
int entry;
|
||||
float burst_phase = (setup->burst_phase) * pi;
|
||||
ntsc_to_rgb_t ntsc;
|
||||
ntsc_to_rgb_init( &ntsc, setup, setup->hue * pi - burst_phase );
|
||||
|
||||
for ( entry = 0; entry < atari_ntsc_color_count; entry++ )
|
||||
{
|
||||
/*NTSC PHASE CONSTANTS.*/
|
||||
float ntsc_phase_constant[16]={0,2.27,1.87,1.62,
|
||||
1.22,0.62,-0.31,-0.855,
|
||||
-1.18,-1.43,-1.63,-1.93,
|
||||
-2.38,-3.43,2.52,2.07};
|
||||
/*NTSC luma multipliers from gtia.pdf*/
|
||||
float luma_mult[16]={
|
||||
0.6941, 0.7091, 0.7241, 0.7401,
|
||||
0.7560, 0.7741, 0.7931, 0.8121,
|
||||
0.8260, 0.8470, 0.8700, 0.8930,
|
||||
0.9160, 0.9420, 0.9690, 1.0000};
|
||||
/* calculate yiq for color entry */
|
||||
int color = entry >> 4;
|
||||
float angle = burst_phase + ntsc_phase_constant[color];
|
||||
float lumafactor = ( luma_mult[ entry & 0x0f] - luma_mult[0] )/( luma_mult[15] - luma_mult[0] );
|
||||
float adj_lumafactor = pow(lumafactor, 1 +setup->gamma_adj);
|
||||
float y = adj_lumafactor * rgb_unit;
|
||||
float base_saturation = (color ? rgb_unit * 0.35f: 0.0f);
|
||||
float saturation_ramp = setup->saturation_ramp;
|
||||
float saturation = base_saturation * ( 1 - saturation_ramp*lumafactor );
|
||||
float i = sin( angle ) * saturation;
|
||||
float q = cos( angle ) * saturation;
|
||||
ntsc_rgb_t* out = emu->table [entry];
|
||||
y = y * ntsc.contrast + ntsc.brightness;
|
||||
|
||||
/* generate at four alignments with respect to output */
|
||||
ntsc.composite [composite_border + 0] = i + y;
|
||||
ntsc.composite [composite_border + 1] = q + y;
|
||||
out = gen_pixel( &ntsc, 0, 0, out );
|
||||
|
||||
ntsc.composite [composite_border + 0] = 0;
|
||||
ntsc.composite [composite_border + 1] = 0;
|
||||
ntsc.composite [composite_border + 2] = i - y;
|
||||
ntsc.composite [composite_border + 3] = q - y;
|
||||
out = gen_pixel( &ntsc, 2, 2, out );
|
||||
|
||||
ntsc.composite [composite_border + 2] = 0;
|
||||
ntsc.composite [composite_border + 3] = 0;
|
||||
ntsc.composite [composite_border + 4] = i + y;
|
||||
ntsc.composite [composite_border + 5] = q + y;
|
||||
out = gen_pixel( &ntsc, 4, 4, out );
|
||||
|
||||
ntsc.composite [composite_border + 4] = 0;
|
||||
ntsc.composite [composite_border + 5] = 0;
|
||||
ntsc.composite [composite_border + 6] = i - y;
|
||||
ntsc.composite [composite_border + 7] = q - y;
|
||||
out = gen_pixel( &ntsc, 6, 6, out );
|
||||
|
||||
ntsc.composite [composite_border + 6] = 0;
|
||||
ntsc.composite [composite_border + 7] = 0;
|
||||
|
||||
/* correct roundoff errors that would cause vertical bands in solid areas */
|
||||
{
|
||||
float r = y + i * ntsc.to_rgb [0] + q * ntsc.to_rgb [1];
|
||||
float g = y + i * ntsc.to_rgb [2] + q * ntsc.to_rgb [3];
|
||||
float b = y + i * ntsc.to_rgb [4] + q * ntsc.to_rgb [5];
|
||||
ntsc_rgb_t correct = MAKE_KRGB( (int) r, (int) g, (int) b ) + MAKE_KMASK( 0x100 );
|
||||
int i;
|
||||
out = emu->table [entry];
|
||||
for ( i = 0; i < rgb_kernel_size / 2; i++ )
|
||||
{
|
||||
/* sum as would occur when outputting run of pixels using same color,
|
||||
but don't sum first kernel; the difference between this and the correct
|
||||
color is what the first kernel's entry should be */
|
||||
ntsc_rgb_t sum = out [(i+12)%14+14]+out[(i+10)%14+28]+out[(i+8)%14+42]+
|
||||
out[i+7]+out [ i+ 5 +14]+out[ i+ 3 +28]+out[ i+1 +42];
|
||||
out [i] = correct - sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
Log_print("atari_ntsc_init(): sharpness:%f saturation:%f brightness:%f contrast:%f gaussian_factor:%f burst_phase:%f, hue:%f gamma_adj:%f saturation_ramp:%f\n",setup->sharpness,setup->saturation,setup->brightness,setup->contrast,setup->gaussian_factor,setup->burst_phase,setup->hue,setup->gamma_adj,setup->saturation_ramp);
|
||||
}
|
||||
|
||||
void atari_ntsc_blit( atari_ntsc_t const* emu, unsigned char const* in, long in_pitch,
|
||||
int width, int height, unsigned short* out, long out_pitch )
|
||||
{
|
||||
int const chunk_count = (width - 10) / 7;
|
||||
long next_in_line = in_pitch - chunk_count * 4;
|
||||
long next_out_line = out_pitch - (chunk_count + 1) * (7 * sizeof *out);
|
||||
while ( height-- )
|
||||
{
|
||||
#define ENTRY( n ) emu->table [n]
|
||||
ntsc_rgb_t const* k1 = ENTRY( 0 );
|
||||
ntsc_rgb_t const* k2 = k1;
|
||||
ntsc_rgb_t const* k3 = k1;
|
||||
ntsc_rgb_t const* k4 = k1;
|
||||
ntsc_rgb_t const* k5 = k4;
|
||||
ntsc_rgb_t const* k6 = k4;
|
||||
ntsc_rgb_t const* k7 = k4;
|
||||
int n;
|
||||
|
||||
#if ATARI_NTSC_RGB_BITS == 16
|
||||
#define TO_RGB( in ) ((in >> 11 & 0xF800) | (in >> 6 & 0x07C0) | (in >> 2 & 0x001F))
|
||||
#elif ATARI_NTSC_RGB_BITS == 15
|
||||
#define TO_RGB( in ) ((in >> 12 & 0x7C00) | (in >> 7 & 0x03E0) | (in >> 2 & 0x001F))
|
||||
#endif
|
||||
|
||||
#define PIXEL( a ) {\
|
||||
ntsc_rgb_t temp =\
|
||||
k0 [a ] + k1 [(a+5)%7+14] + k2 [(a+3)%7+28] + k3 [(a+1)%7+42] +\
|
||||
k4 [a+7] + k5 [(a+5)%7+21] + k6 [(a+3)%7+35] + k7 [(a+1)%7+49];\
|
||||
if ( a ) out [a-1] = rgb;\
|
||||
CLAMP_RGB( temp, 0 );\
|
||||
rgb = TO_RGB( temp );\
|
||||
}
|
||||
|
||||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
ntsc_rgb_t const* k0 = ENTRY( in [0] );
|
||||
int rgb;
|
||||
PIXEL( 0 );
|
||||
PIXEL( 1 );
|
||||
k5 = k1;
|
||||
k1 = ENTRY( in [1] );
|
||||
PIXEL( 2 );
|
||||
PIXEL( 3 );
|
||||
k6 = k2;
|
||||
k2 = ENTRY( in [2] );
|
||||
PIXEL( 4 );
|
||||
PIXEL( 5 );
|
||||
k7 = k3;
|
||||
k3 = ENTRY( in [3] );
|
||||
PIXEL( 6 );
|
||||
out [6] = rgb;
|
||||
k4 = k0;
|
||||
in += 4;
|
||||
out += 7;
|
||||
}
|
||||
{
|
||||
ntsc_rgb_t const* k0 = ENTRY( 0 );
|
||||
int rgb;
|
||||
PIXEL( 0 );
|
||||
PIXEL( 1 );
|
||||
k5 = k1;
|
||||
k1 = k0;
|
||||
PIXEL( 2 );
|
||||
PIXEL( 3 );
|
||||
k6 = k2;
|
||||
k2 = k0;
|
||||
PIXEL( 4 );
|
||||
PIXEL( 5 );
|
||||
k7 = k3;
|
||||
k3 = k0;
|
||||
PIXEL( 6 );
|
||||
k4 = k0;
|
||||
out [6] = rgb;
|
||||
out += 7;
|
||||
PIXEL( 0 );
|
||||
PIXEL( 1 );
|
||||
k5 = k0;
|
||||
PIXEL( 2 );
|
||||
out [2] = rgb;
|
||||
}
|
||||
#undef PIXEL
|
||||
|
||||
in += next_in_line;
|
||||
out = (unsigned short*) ((char*) out + next_out_line);
|
||||
}
|
||||
}
|
||||
|
||||
/* Atari800-specific: */
|
||||
|
||||
/* Adjust default values here */
|
||||
atari_ntsc_setup_t atari_ntsc_setup = {
|
||||
0.f, /* hue */
|
||||
-0.1f, /* saturation */
|
||||
0.f, /* contrast */
|
||||
-0.1f, /* brightness */
|
||||
-0.5f, /* sharpness */
|
||||
-0.6f, /* burst phase */
|
||||
0.f, /* gaussian factor */
|
||||
-0.15, /* gamma adjustment */
|
||||
0.25 /* satutration ramp */
|
||||
};
|
||||
|
||||
int atari_ntsc_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 1; i < *argc; i++) {
|
||||
int i_a = (i + 1 < *argc); /* is argument available? */
|
||||
int a_m = 0; /* error, argument missing! */
|
||||
|
||||
if (strcmp(argv[i], "-ntsc_hue") == 0) {
|
||||
if (i_a)
|
||||
atari_ntsc_setup.hue = atof(argv[++i]);
|
||||
else a_m = 1;
|
||||
} else if (strcmp(argv[i], "-ntsc_sat") == 0) {
|
||||
if (i_a)
|
||||
atari_ntsc_setup.saturation = atof(argv[++i]);
|
||||
else a_m = 1;
|
||||
} else if (strcmp(argv[i], "-ntsc_cont") == 0) {
|
||||
if (i_a)
|
||||
atari_ntsc_setup.contrast = atof(argv[++i]);
|
||||
else a_m = 1;
|
||||
} else if (strcmp(argv[i], "-ntsc_bright") == 0) {
|
||||
if (i_a)
|
||||
atari_ntsc_setup.brightness = atof(argv[++i]);
|
||||
else a_m = 1;
|
||||
} else if (strcmp(argv[i], "-ntsc_sharp") == 0) {
|
||||
if (i_a)
|
||||
atari_ntsc_setup.sharpness = atof(argv[++i]);
|
||||
else a_m = 1;
|
||||
} else if (strcmp(argv[i], "-ntsc_burst") == 0) {
|
||||
if (i_a)
|
||||
atari_ntsc_setup.burst_phase = atof(argv[++i]);
|
||||
else a_m = 1;
|
||||
} else if (strcmp(argv[i], "-ntsc_gauss") == 0) {
|
||||
if (i_a)
|
||||
atari_ntsc_setup.gaussian_factor = atof(argv[++i]);
|
||||
else a_m = 1;
|
||||
} else if (strcmp(argv[i], "-ntsc_gamma") == 0) {
|
||||
if (i_a)
|
||||
atari_ntsc_setup.gamma_adj = atof(argv[++i]);
|
||||
else a_m = 1;
|
||||
} else if (strcmp(argv[i], "-ntsc_ramp") == 0) {
|
||||
if (i_a)
|
||||
atari_ntsc_setup.saturation_ramp = atof(argv[++i]);
|
||||
else a_m = 1;
|
||||
}
|
||||
else {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
Log_print("\t-ntsc_hue <n> Set NTSC hue -1..1 (default %.2g) (-ntsc_emu only)", atari_ntsc_setup.hue);
|
||||
Log_print("\t-ntsc_sat <n> Set NTSC saturation (default %.2g) (-ntsc_emu only)", atari_ntsc_setup.saturation);
|
||||
Log_print("\t-ntsc_cont <n> Set NTSC contrast (default %.2g) (-ntsc_emu only)", atari_ntsc_setup.contrast);
|
||||
Log_print("\t-ntsc_bright <n> Set NTSC brightness (default %.2g) (-ntsc_emu only)", atari_ntsc_setup.brightness);
|
||||
Log_print("\t-ntsc_sharp <n> Set NTSC sharpness (default %.2g) (-ntsc_emu only)", atari_ntsc_setup.sharpness);
|
||||
Log_print("\t-ntsc_burst <n> Set NTSC burst phase -1..1 (artif colours)(def: %.2g)", atari_ntsc_setup.burst_phase);
|
||||
Log_print("\t (-ntsc_emu only)");
|
||||
Log_print("\t-ntsc_gauss <n> Set NTSC Gaussian factor (default %.2g)", atari_ntsc_setup.gaussian_factor);
|
||||
Log_print("\t (-ntsc_emu only)");
|
||||
Log_print("\t-ntsc_gamma <n> Set NTSC gamma adjustment (default %.2g)", atari_ntsc_setup.gamma_adj);
|
||||
Log_print("\t (-ntsc_emu only)");
|
||||
Log_print("\t-ntsc_ramp <n> Set NTSC saturation ramp factor (default %.2g)", atari_ntsc_setup.saturation_ramp);
|
||||
Log_print("\t (-ntsc_emu only)");
|
||||
}
|
||||
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
|
||||
if (a_m) {
|
||||
Log_print("Missing argument for '%s'", argv[i]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*argc = j;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
|
||||
/* Atari GTIA NTSC composite video to RGB emulator/blitter */
|
||||
|
||||
#ifndef ATARI_NTSC_H
|
||||
#define ATARI_NTSC_H
|
||||
|
||||
/* Picture parameters, ranging from -1.0 to 1.0 where 0.0 is normal. To easily
|
||||
clear all fields, make it a static object then set whatever fields you want:
|
||||
static snes_ntsc_setup_t setup;
|
||||
setup.hue = ... */
|
||||
typedef struct atari_ntsc_setup_t
|
||||
{
|
||||
float hue;
|
||||
float saturation;
|
||||
float contrast;
|
||||
float brightness;
|
||||
float sharpness;
|
||||
float burst_phase; /* not in radians; -1.0 = -180 degrees, 1.0 = +180 degrees */
|
||||
float gaussian_factor;
|
||||
/* gamma adjustment */
|
||||
float gamma_adj;
|
||||
/* lower saturation for higher luma values */
|
||||
float saturation_ramp;
|
||||
} atari_ntsc_setup_t;
|
||||
|
||||
/* private */
|
||||
enum { atari_ntsc_entry_size = 56 };
|
||||
enum { atari_ntsc_color_count = 256 };
|
||||
typedef unsigned long ntsc_rgb_t;
|
||||
/*end private*/
|
||||
|
||||
/* Caller must allocate space for blitter data, which uses 56 KB of memory. */
|
||||
typedef struct atari_ntsc_t
|
||||
{
|
||||
ntsc_rgb_t table [atari_ntsc_color_count] [atari_ntsc_entry_size];
|
||||
} atari_ntsc_t;
|
||||
|
||||
/* Initialize and adjust parameters. Can be called multiple times on the same
|
||||
atari_ntsc_t object. */
|
||||
void atari_ntsc_init( struct atari_ntsc_t*, atari_ntsc_setup_t const* setup );
|
||||
|
||||
/* Blit one or more scanlines of Atari 8-bit palette values to 16-bit 5-6-5 RGB output.
|
||||
For every 7 output pixels, reads approximately 4 source pixels. Use constants below for
|
||||
definite input and output pixel counts. */
|
||||
void atari_ntsc_blit( struct atari_ntsc_t const*, unsigned char const* atari_in, long in_pitch,
|
||||
int out_width, int out_height, unsigned short* rgb_out, long out_pitch );
|
||||
|
||||
/* Useful values to use for output width and number of input pixels read */
|
||||
enum {
|
||||
atari_ntsc_min_out_width = 570, /* minimum width that doesn't cut off active area */
|
||||
atari_ntsc_min_in_width = 320,
|
||||
|
||||
atari_ntsc_full_out_width = 598, /* room for 8-pixel left & right overscan borders */
|
||||
atari_ntsc_full_in_width = 336
|
||||
};
|
||||
|
||||
/* supports 16-bit and 15-bit RGB output */
|
||||
#ifndef ATARI_NTSC_RGB_BITS
|
||||
#define ATARI_NTSC_RGB_BITS 16
|
||||
#endif
|
||||
|
||||
|
||||
/* Atari800-specific: */
|
||||
|
||||
extern atari_ntsc_setup_t atari_ntsc_setup;
|
||||
|
||||
int atari_ntsc_Initialise(int *argc, char *argv[]);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
* binload.c - load a binary executable file
|
||||
*
|
||||
* Copyright (C) 1995-1998 David Firth
|
||||
* Copyright (C) 1998-2005 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "atari.h"
|
||||
#include "binload.h"
|
||||
#include "cpu.h"
|
||||
#include "devices.h"
|
||||
#include "esc.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "sio.h"
|
||||
|
||||
int BINLOAD_start_binloading = FALSE;
|
||||
int BINLOAD_loading_basic = 0;
|
||||
FILE *BINLOAD_bin_file = NULL;
|
||||
|
||||
/* Read a word from file */
|
||||
static int read_word(void)
|
||||
{
|
||||
UBYTE buf[2];
|
||||
if (fread(buf, 1, 2, BINLOAD_bin_file) != 2) {
|
||||
fclose(BINLOAD_bin_file);
|
||||
BINLOAD_bin_file = NULL;
|
||||
if (BINLOAD_start_binloading) {
|
||||
BINLOAD_start_binloading = FALSE;
|
||||
Log_print("binload: not valid BIN file");
|
||||
return -1;
|
||||
}
|
||||
CPU_regPC = MEMORY_dGetWordAligned(0x2e0);
|
||||
return -1;
|
||||
}
|
||||
return buf[0] + (buf[1] << 8);
|
||||
}
|
||||
|
||||
/* Start or continue loading */
|
||||
static void loader_cont(void)
|
||||
{
|
||||
if (BINLOAD_bin_file == NULL)
|
||||
return;
|
||||
if (BINLOAD_start_binloading) {
|
||||
MEMORY_dPutByte(0x244, 0);
|
||||
MEMORY_dPutByte(0x09, 1);
|
||||
}
|
||||
else
|
||||
CPU_regS += 2; /* pop ESC code */
|
||||
|
||||
MEMORY_dPutByte(0x2e3, 0xd7);
|
||||
do {
|
||||
int temp;
|
||||
UWORD from;
|
||||
UWORD to;
|
||||
do
|
||||
temp = read_word();
|
||||
while (temp == 0xffff);
|
||||
if (temp < 0)
|
||||
return;
|
||||
from = (UWORD) temp;
|
||||
|
||||
temp = read_word();
|
||||
if (temp < 0)
|
||||
return;
|
||||
to = (UWORD) temp;
|
||||
|
||||
if (BINLOAD_start_binloading) {
|
||||
MEMORY_dPutWordAligned(0x2e0, from);
|
||||
BINLOAD_start_binloading = FALSE;
|
||||
}
|
||||
|
||||
to++;
|
||||
do {
|
||||
int byte = fgetc(BINLOAD_bin_file);
|
||||
if (byte == EOF) {
|
||||
fclose(BINLOAD_bin_file);
|
||||
BINLOAD_bin_file = NULL;
|
||||
CPU_regPC = MEMORY_dGetWordAligned(0x2e0);
|
||||
if (MEMORY_dGetByte(0x2e3) != 0xd7) {
|
||||
/* run INIT routine which RTSes directly to RUN routine */
|
||||
CPU_regPC--;
|
||||
MEMORY_dPutByte(0x0100 + CPU_regS--, CPU_regPC >> 8); /* high */
|
||||
MEMORY_dPutByte(0x0100 + CPU_regS--, CPU_regPC & 0xff); /* low */
|
||||
CPU_regPC = MEMORY_dGetWordAligned(0x2e2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
MEMORY_PutByte(from, (UBYTE) byte);
|
||||
from++;
|
||||
} while (from != to);
|
||||
} while (MEMORY_dGetByte(0x2e3) == 0xd7);
|
||||
|
||||
CPU_regS--;
|
||||
ESC_Add((UWORD) (0x100 + CPU_regS), ESC_BINLOADER_CONT, loader_cont);
|
||||
CPU_regS--;
|
||||
MEMORY_dPutByte(0x0100 + CPU_regS--, 0x01); /* high */
|
||||
MEMORY_dPutByte(0x0100 + CPU_regS, CPU_regS + 1); /* low */
|
||||
CPU_regS--;
|
||||
CPU_regPC = MEMORY_dGetWordAligned(0x2e2);
|
||||
CPU_SetC;
|
||||
|
||||
MEMORY_dPutByte(0x0300, 0x31); /* for "Studio Dream" */
|
||||
}
|
||||
|
||||
/* Fake boot sector to call loader_cont at boot time */
|
||||
int BINLOAD_LoaderStart(UBYTE *buffer)
|
||||
{
|
||||
buffer[0] = 0x00; /* ignored */
|
||||
buffer[1] = 0x01; /* one boot sector */
|
||||
buffer[2] = 0x00; /* start at memory location 0x0700 */
|
||||
buffer[3] = 0x07;
|
||||
buffer[4] = 0x77; /* reset reboots (0xe477 = Atari OS Coldstart) */
|
||||
buffer[5] = 0xe4;
|
||||
buffer[6] = 0xf2; /* ESC */
|
||||
buffer[7] = ESC_BINLOADER_CONT;
|
||||
ESC_Add(0x706, ESC_BINLOADER_CONT, loader_cont);
|
||||
return 'C';
|
||||
}
|
||||
|
||||
/* Load BIN file, returns TRUE if ok */
|
||||
int BINLOAD_Loader(const char *filename)
|
||||
{
|
||||
UBYTE buf[2];
|
||||
if (BINLOAD_bin_file != NULL) { /* close previously open file */
|
||||
fclose(BINLOAD_bin_file);
|
||||
BINLOAD_bin_file = NULL;
|
||||
BINLOAD_loading_basic = 0;
|
||||
}
|
||||
if (Atari800_machine_type == Atari800_MACHINE_5200) {
|
||||
Log_print("binload: can't run Atari programs directly on the 5200");
|
||||
return FALSE;
|
||||
}
|
||||
BINLOAD_bin_file = fopen(filename, "rb");
|
||||
if (BINLOAD_bin_file == NULL) { /* open */
|
||||
Log_print("binload: can't open \"%s\"", filename);
|
||||
return FALSE;
|
||||
}
|
||||
/* Avoid "BOOT ERROR" when loading a BASIC program */
|
||||
if (SIO_drive_status[0] == SIO_NO_DISK)
|
||||
SIO_DisableDrive(1);
|
||||
if (fread(buf, 1, 2, BINLOAD_bin_file) == 2) {
|
||||
if (buf[0] == 0xff && buf[1] == 0xff) {
|
||||
BINLOAD_start_binloading = TRUE; /* force SIO to call BINLOAD_LoaderStart at boot */
|
||||
Atari800_Coldstart(); /* reboot */
|
||||
return TRUE;
|
||||
}
|
||||
else if (buf[0] == 0 && buf[1] == 0) {
|
||||
BINLOAD_loading_basic = BINLOAD_LOADING_BASIC_SAVED;
|
||||
Devices_PatchOS();
|
||||
Atari800_Coldstart();
|
||||
return TRUE;
|
||||
}
|
||||
else if (buf[0] >= '0' && buf[0] <= '9') {
|
||||
BINLOAD_loading_basic = BINLOAD_LOADING_BASIC_LISTED;
|
||||
Devices_PatchOS();
|
||||
Atari800_Coldstart();
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
fclose(BINLOAD_bin_file);
|
||||
BINLOAD_bin_file = NULL;
|
||||
Log_print("binload: \"%s\" not recognized as a DOS or BASIC program", filename);
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef BINLOAD_H_
|
||||
#define BINLOAD_H_
|
||||
|
||||
#include <stdio.h> /* FILE */
|
||||
#include "atari.h" /* UBYTE */
|
||||
|
||||
extern FILE *BINLOAD_bin_file;
|
||||
|
||||
int BINLOAD_Loader(const char *filename);
|
||||
extern int BINLOAD_start_binloading;
|
||||
extern int BINLOAD_loading_basic;
|
||||
#define BINLOAD_LOADING_BASIC_SAVED 1
|
||||
#define BINLOAD_LOADING_BASIC_LISTED 2
|
||||
#define BINLOAD_LOADING_BASIC_LISTED_ATARI 3
|
||||
#define BINLOAD_LOADING_BASIC_LISTED_CR 4
|
||||
#define BINLOAD_LOADING_BASIC_LISTED_LF 5
|
||||
#define BINLOAD_LOADING_BASIC_LISTED_CRLF 6
|
||||
#define BINLOAD_LOADING_BASIC_LISTED_CR_OR_CRLF 7
|
||||
#define BINLOAD_LOADING_BASIC_RUN 8
|
||||
int BINLOAD_LoaderStart(UBYTE *buffer);
|
||||
|
||||
#endif /* BINLOAD_H_ */
|
||||
@@ -1,794 +0,0 @@
|
||||
/*
|
||||
* cartridge.c - cartridge emulation
|
||||
*
|
||||
* Copyright (C) 2001-2006 Piotr Fusik
|
||||
* Copyright (C) 2001-2006 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "atari.h"
|
||||
#include "binload.h" /* BINLOAD_loading_basic */
|
||||
#include "cartridge.h"
|
||||
#include "memory.h"
|
||||
#include "pia.h"
|
||||
#include "rtime.h"
|
||||
#include "util.h"
|
||||
#ifndef BASIC
|
||||
#include "statesav.h"
|
||||
#endif
|
||||
|
||||
int CARTRIDGE_kb[CARTRIDGE_LAST_SUPPORTED + 1] = {
|
||||
0,
|
||||
8, /* CARTRIDGE_STD_8 */
|
||||
16, /* CARTRIDGE_STD_16 */
|
||||
16, /* CARTRIDGE_OSS_16 */
|
||||
32, /* CARTRIDGE_5200_32 */
|
||||
32, /* CARTRIDGE_DB_32 */
|
||||
16, /* CARTRIDGE_5200_EE_16 */
|
||||
40, /* CARTRIDGE_5200_40 */
|
||||
64, /* CARTRIDGE_WILL_64 */
|
||||
64, /* CARTRIDGE_EXP_64 */
|
||||
64, /* CARTRIDGE_DIAMOND_64 */
|
||||
64, /* CARTRIDGE_SDX */
|
||||
32, /* CARTRIDGE_XEGS_32 */
|
||||
64, /* CARTRIDGE_XEGS_64 */
|
||||
128, /* CARTRIDGE_XEGS_128 */
|
||||
16, /* CARTRIDGE_OSS2_16 */
|
||||
16, /* CARTRIDGE_5200_NS_16 */
|
||||
128, /* CARTRIDGE_ATRAX_128 */
|
||||
40, /* CARTRIDGE_BBSB_40 */
|
||||
8, /* CARTRIDGE_5200_8 */
|
||||
4, /* CARTRIDGE_5200_4 */
|
||||
8, /* CARTRIDGE_RIGHT_8 */
|
||||
32, /* CARTRIDGE_WILL_32 */
|
||||
256, /* CARTRIDGE_XEGS_256 */
|
||||
512, /* CARTRIDGE_XEGS_512 */
|
||||
1024, /* CARTRIDGE_XEGS_1024 */
|
||||
16, /* CARTRIDGE_MEGA_16 */
|
||||
32, /* CARTRIDGE_MEGA_32 */
|
||||
64, /* CARTRIDGE_MEGA_64 */
|
||||
128, /* CARTRIDGE_MEGA_128 */
|
||||
256, /* CARTRIDGE_MEGA_256 */
|
||||
512, /* CARTRIDGE_MEGA_512 */
|
||||
1024, /* CARTRIDGE_MEGA_1024 */
|
||||
32, /* CARTRIDGE_SWXEGS_32 */
|
||||
64, /* CARTRIDGE_SWXEGS_64 */
|
||||
128, /* CARTRIDGE_SWXEGS_128 */
|
||||
256, /* CARTRIDGE_SWXEGS_256 */
|
||||
512, /* CARTRIDGE_SWXEGS_512 */
|
||||
1024, /* CARTRIDGE_SWXEGS_1024 */
|
||||
8, /* CARTRIDGE_PHOENIX_8 */
|
||||
16, /* CARTRIDGE_BLIZZARD_16 */
|
||||
128, /* CARTRIDGE_ATMAX_128 */
|
||||
1024, /* CARTRIDGE_ATMAX_1024 */
|
||||
128 /* CARTRIDGE_SDX_128 */
|
||||
};
|
||||
|
||||
int CARTRIDGE_IsFor5200(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case CARTRIDGE_5200_32:
|
||||
case CARTRIDGE_5200_EE_16:
|
||||
case CARTRIDGE_5200_40:
|
||||
case CARTRIDGE_5200_NS_16:
|
||||
case CARTRIDGE_5200_8:
|
||||
case CARTRIDGE_5200_4:
|
||||
return TRUE;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static UBYTE *cart_image = NULL; /* cartridge memory */
|
||||
static char cart_filename[FILENAME_MAX];
|
||||
int CARTRIDGE_type = CARTRIDGE_NONE;
|
||||
|
||||
static int bank;
|
||||
|
||||
/* DB_32, XEGS_32, XEGS_64, XEGS_128, XEGS_256, XEGS_512, XEGS_1024,
|
||||
SWXEGS_32, SWXEGS_64, SWXEGS_128, SWXEGS_256, SWXEGS_512, SWXEGS_1024 */
|
||||
static void set_bank_809F(int b, int main)
|
||||
{
|
||||
if (b != bank) {
|
||||
if (b & 0x80) {
|
||||
MEMORY_Cart809fDisable();
|
||||
MEMORY_CartA0bfDisable();
|
||||
}
|
||||
else {
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0x9fff, cart_image + b * 0x2000);
|
||||
if (bank & 0x80)
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + main);
|
||||
}
|
||||
bank = b;
|
||||
}
|
||||
}
|
||||
|
||||
/* OSS_16, OSS2_16 */
|
||||
static void set_bank_A0AF(int b, int main)
|
||||
{
|
||||
if (b != bank) {
|
||||
if (b < 0)
|
||||
MEMORY_CartA0bfDisable();
|
||||
else {
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xafff, cart_image + b * 0x1000);
|
||||
if (bank < 0)
|
||||
MEMORY_CopyROM(0xb000, 0xbfff, cart_image + main);
|
||||
}
|
||||
bank = b;
|
||||
}
|
||||
}
|
||||
|
||||
/* WILL_64, EXP_64, DIAMOND_64, SDX_64, WILL_32, ATMAX_128, ATMAX_1024,
|
||||
ATRAX_128 */
|
||||
static void set_bank_A0BF(int b, int n)
|
||||
{
|
||||
if (b != bank) {
|
||||
if (b & n)
|
||||
MEMORY_CartA0bfDisable();
|
||||
else {
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + (b & (n - 1)) * 0x2000);
|
||||
}
|
||||
bank = b;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_bank_80BF(int b)
|
||||
{
|
||||
if (b != bank) {
|
||||
if (b & 0x80) {
|
||||
MEMORY_Cart809fDisable();
|
||||
MEMORY_CartA0bfDisable();
|
||||
}
|
||||
else {
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0xbfff, cart_image + b * 0x4000);
|
||||
}
|
||||
bank = b;
|
||||
}
|
||||
}
|
||||
|
||||
/* an access (read or write) to D500-D5FF area */
|
||||
static void access_D5(UWORD addr)
|
||||
{
|
||||
int b = bank;
|
||||
switch (CARTRIDGE_type) {
|
||||
case CARTRIDGE_OSS_16:
|
||||
if (addr & 0x08)
|
||||
b = -1;
|
||||
else
|
||||
switch (addr & 0x07) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
b = 0;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x07:
|
||||
b = 1;
|
||||
break;
|
||||
case 0x04:
|
||||
case 0x05:
|
||||
b = 2;
|
||||
break;
|
||||
/* case 0x02:
|
||||
case 0x06: */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
set_bank_A0AF(b, 0x3000);
|
||||
break;
|
||||
case CARTRIDGE_DB_32:
|
||||
set_bank_809F(addr & 0x03, 0x6000);
|
||||
break;
|
||||
case CARTRIDGE_WILL_64:
|
||||
set_bank_A0BF(addr, 8);
|
||||
break;
|
||||
case CARTRIDGE_WILL_32:
|
||||
set_bank_A0BF(addr & 0xb, 8);
|
||||
break;
|
||||
case CARTRIDGE_EXP_64:
|
||||
if ((addr & 0xf0) == 0x70)
|
||||
set_bank_A0BF(addr ^ 7, 8);
|
||||
break;
|
||||
case CARTRIDGE_DIAMOND_64:
|
||||
if ((addr & 0xf0) == 0xd0)
|
||||
set_bank_A0BF(addr ^ 7, 8);
|
||||
break;
|
||||
case CARTRIDGE_SDX_64:
|
||||
if ((addr & 0xf0) == 0xe0)
|
||||
set_bank_A0BF(addr ^ 7, 8);
|
||||
break;
|
||||
case CARTRIDGE_SDX_128:
|
||||
if ((addr & 0xe0) == 0xe0 && addr != bank) {
|
||||
if (addr & 8)
|
||||
MEMORY_CartA0bfDisable();
|
||||
else {
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xbfff,
|
||||
cart_image + (((addr & 7) + ((addr & 0x10) >> 1)) ^ 0xf) * 0x2000);
|
||||
}
|
||||
bank = addr;
|
||||
}
|
||||
break;
|
||||
case CARTRIDGE_OSS2_16:
|
||||
switch (addr & 0x09) {
|
||||
case 0x00:
|
||||
b = 1;
|
||||
break;
|
||||
case 0x01:
|
||||
b = 3;
|
||||
break;
|
||||
case 0x08:
|
||||
b = -1;
|
||||
break;
|
||||
case 0x09:
|
||||
b = 2;
|
||||
break;
|
||||
}
|
||||
set_bank_A0AF(b, 0x0000);
|
||||
break;
|
||||
case CARTRIDGE_PHOENIX_8:
|
||||
MEMORY_CartA0bfDisable();
|
||||
break;
|
||||
case CARTRIDGE_BLIZZARD_16:
|
||||
MEMORY_Cart809fDisable();
|
||||
MEMORY_CartA0bfDisable();
|
||||
break;
|
||||
case CARTRIDGE_ATMAX_128:
|
||||
if ((addr & 0xe0) == 0)
|
||||
set_bank_A0BF(addr, 16);
|
||||
break;
|
||||
case CARTRIDGE_ATMAX_1024:
|
||||
set_bank_A0BF(addr, 128);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* a read from D500-D5FF area */
|
||||
UBYTE CARTRIDGE_GetByte(UWORD addr)
|
||||
{
|
||||
if (RTIME_enabled && (addr == 0xd5b8 || addr == 0xd5b9))
|
||||
return RTIME_GetByte();
|
||||
access_D5(addr);
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
/* a write to D500-D5FF area */
|
||||
void CARTRIDGE_PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
if (RTIME_enabled && (addr == 0xd5b8 || addr == 0xd5b9)) {
|
||||
RTIME_PutByte(byte);
|
||||
return;
|
||||
}
|
||||
switch (CARTRIDGE_type) {
|
||||
case CARTRIDGE_XEGS_32:
|
||||
set_bank_809F(byte & 0x03, 0x6000);
|
||||
break;
|
||||
case CARTRIDGE_XEGS_64:
|
||||
set_bank_809F(byte & 0x07, 0xe000);
|
||||
break;
|
||||
case CARTRIDGE_XEGS_128:
|
||||
set_bank_809F(byte & 0x0f, 0x1e000);
|
||||
break;
|
||||
case CARTRIDGE_XEGS_256:
|
||||
set_bank_809F(byte & 0x1f, 0x3e000);
|
||||
break;
|
||||
case CARTRIDGE_XEGS_512:
|
||||
set_bank_809F(byte & 0x3f, 0x7e000);
|
||||
break;
|
||||
case CARTRIDGE_XEGS_1024:
|
||||
set_bank_809F(byte & 0x7f, 0xfe000);
|
||||
break;
|
||||
case CARTRIDGE_ATRAX_128:
|
||||
set_bank_A0BF(byte & 0x8f, 128);
|
||||
break;
|
||||
case CARTRIDGE_MEGA_16:
|
||||
set_bank_80BF(byte & 0x80);
|
||||
break;
|
||||
case CARTRIDGE_MEGA_32:
|
||||
set_bank_80BF(byte & 0x81);
|
||||
break;
|
||||
case CARTRIDGE_MEGA_64:
|
||||
set_bank_80BF(byte & 0x83);
|
||||
break;
|
||||
case CARTRIDGE_MEGA_128:
|
||||
set_bank_80BF(byte & 0x87);
|
||||
break;
|
||||
case CARTRIDGE_MEGA_256:
|
||||
set_bank_80BF(byte & 0x8f);
|
||||
break;
|
||||
case CARTRIDGE_MEGA_512:
|
||||
set_bank_80BF(byte & 0x9f);
|
||||
break;
|
||||
case CARTRIDGE_MEGA_1024:
|
||||
set_bank_80BF(byte & 0xbf);
|
||||
break;
|
||||
case CARTRIDGE_SWXEGS_32:
|
||||
set_bank_809F(byte & 0x83, 0x6000);
|
||||
break;
|
||||
case CARTRIDGE_SWXEGS_64:
|
||||
set_bank_809F(byte & 0x87, 0xe000);
|
||||
break;
|
||||
case CARTRIDGE_SWXEGS_128:
|
||||
set_bank_809F(byte & 0x8f, 0x1e000);
|
||||
break;
|
||||
case CARTRIDGE_SWXEGS_256:
|
||||
set_bank_809F(byte & 0x9f, 0x3e000);
|
||||
break;
|
||||
case CARTRIDGE_SWXEGS_512:
|
||||
set_bank_809F(byte & 0xbf, 0x7e000);
|
||||
break;
|
||||
case CARTRIDGE_SWXEGS_1024:
|
||||
set_bank_809F(byte, 0xfe000);
|
||||
break;
|
||||
default:
|
||||
access_D5(addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* special support of Bounty Bob on Atari5200 */
|
||||
void CARTRIDGE_BountyBob1(UWORD addr)
|
||||
{
|
||||
if (Atari800_machine_type == Atari800_MACHINE_5200) {
|
||||
if (addr >= 0x4ff6 && addr <= 0x4ff9) {
|
||||
addr -= 0x4ff6;
|
||||
MEMORY_CopyROM(0x4000, 0x4fff, cart_image + addr * 0x1000);
|
||||
}
|
||||
} else {
|
||||
if (addr >= 0x8ff6 && addr <= 0x8ff9) {
|
||||
addr -= 0x8ff6;
|
||||
MEMORY_CopyROM(0x8000, 0x8fff, cart_image + addr * 0x1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CARTRIDGE_BountyBob2(UWORD addr)
|
||||
{
|
||||
if (Atari800_machine_type == Atari800_MACHINE_5200) {
|
||||
if (addr >= 0x5ff6 && addr <= 0x5ff9) {
|
||||
addr -= 0x5ff6;
|
||||
MEMORY_CopyROM(0x5000, 0x5fff, cart_image + 0x4000 + addr * 0x1000);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (addr >= 0x9ff6 && addr <= 0x9ff9) {
|
||||
addr -= 0x9ff6;
|
||||
MEMORY_CopyROM(0x9000, 0x9fff, cart_image + 0x4000 + addr * 0x1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PAGED_ATTRIB
|
||||
UBYTE CARTRIDGE_BountyBob1GetByte(UWORD addr)
|
||||
{
|
||||
if (Atari800_machine_type == Atari800_MACHINE_5200) {
|
||||
if (addr >= 0x4ff6 && addr <= 0x4ff9) {
|
||||
CARTRIDGE_BountyBob1(addr);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (addr >= 0x8ff6 && addr <= 0x8ff9) {
|
||||
CARTRIDGE_BountyBob1(addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return MEMORY_dGetByte(addr);
|
||||
}
|
||||
|
||||
UBYTE CARTRIDGE_BountyBob2GetByte(UWORD addr)
|
||||
{
|
||||
if (Atari800_machine_type == Atari800_MACHINE_5200) {
|
||||
if (addr >= 0x5ff6 && addr <= 0x5ff9) {
|
||||
CARTRIDGE_BountyBob2(addr);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (addr >= 0x9ff6 && addr <= 0x9ff9) {
|
||||
CARTRIDGE_BountyBob2(addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return MEMORY_dGetByte(addr);
|
||||
}
|
||||
|
||||
void CARTRIDGE_BountyBob1PutByte(UWORD addr, UBYTE value)
|
||||
{
|
||||
if (Atari800_machine_type == Atari800_MACHINE_5200) {
|
||||
if (addr >= 0x4ff6 && addr <= 0x4ff9) {
|
||||
CARTRIDGE_BountyBob1(addr);
|
||||
}
|
||||
} else {
|
||||
if (addr >= 0x8ff6 && addr <= 0x8ff9) {
|
||||
CARTRIDGE_BountyBob1(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CARTRIDGE_BountyBob2PutByte(UWORD addr, UBYTE value)
|
||||
{
|
||||
if (Atari800_machine_type == Atari800_MACHINE_5200) {
|
||||
if (addr >= 0x5ff6 && addr <= 0x5ff9) {
|
||||
CARTRIDGE_BountyBob2(addr);
|
||||
}
|
||||
} else {
|
||||
if (addr >= 0x9ff6 && addr <= 0x9ff9) {
|
||||
CARTRIDGE_BountyBob2(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int CARTRIDGE_Checksum(const UBYTE *image, int nbytes)
|
||||
{
|
||||
int checksum = 0;
|
||||
while (nbytes > 0) {
|
||||
checksum += *image++;
|
||||
nbytes--;
|
||||
}
|
||||
return checksum;
|
||||
}
|
||||
|
||||
int CARTRIDGE_Insert(const char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
int len;
|
||||
int type;
|
||||
UBYTE header[16];
|
||||
|
||||
/* remove currently inserted cart */
|
||||
CARTRIDGE_Remove();
|
||||
|
||||
/* open file */
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == NULL)
|
||||
return CARTRIDGE_CANT_OPEN;
|
||||
/* check file length */
|
||||
len = Util_flen(fp);
|
||||
Util_rewind(fp);
|
||||
|
||||
/* Save Filename for state save */
|
||||
strcpy(cart_filename, filename);
|
||||
|
||||
/* if full kilobytes, assume it is raw image */
|
||||
if ((len & 0x3ff) == 0) {
|
||||
/* alloc memory and read data */
|
||||
cart_image = (UBYTE *) Util_malloc(len);
|
||||
fread(cart_image, 1, len, fp);
|
||||
fclose(fp);
|
||||
/* find cart type */
|
||||
CARTRIDGE_type = CARTRIDGE_NONE;
|
||||
len >>= 10; /* number of kilobytes */
|
||||
for (type = 1; type <= CARTRIDGE_LAST_SUPPORTED; type++)
|
||||
if (CARTRIDGE_kb[type] == len) {
|
||||
if (CARTRIDGE_type == CARTRIDGE_NONE)
|
||||
CARTRIDGE_type = type;
|
||||
else
|
||||
return len; /* more than one cartridge type of such length - user must select */
|
||||
}
|
||||
if (CARTRIDGE_type != CARTRIDGE_NONE) {
|
||||
CARTRIDGE_Start();
|
||||
return 0; /* ok */
|
||||
}
|
||||
free(cart_image);
|
||||
cart_image = NULL;
|
||||
return CARTRIDGE_BAD_FORMAT;
|
||||
}
|
||||
/* if not full kilobytes, assume it is CART file */
|
||||
fread(header, 1, 16, fp);
|
||||
if ((header[0] == 'C') &&
|
||||
(header[1] == 'A') &&
|
||||
(header[2] == 'R') &&
|
||||
(header[3] == 'T')) {
|
||||
type = (header[4] << 24) |
|
||||
(header[5] << 16) |
|
||||
(header[6] << 8) |
|
||||
header[7];
|
||||
if (type >= 1 && type <= CARTRIDGE_LAST_SUPPORTED) {
|
||||
int checksum;
|
||||
len = CARTRIDGE_kb[type] << 10;
|
||||
/* alloc memory and read data */
|
||||
cart_image = (UBYTE *) Util_malloc(len);
|
||||
fread(cart_image, 1, len, fp);
|
||||
fclose(fp);
|
||||
checksum = (header[8] << 24) |
|
||||
(header[9] << 16) |
|
||||
(header[10] << 8) |
|
||||
header[11];
|
||||
CARTRIDGE_type = type;
|
||||
CARTRIDGE_Start();
|
||||
return checksum == CARTRIDGE_Checksum(cart_image, len) ? 0 : CARTRIDGE_BAD_CHECKSUM;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return CARTRIDGE_BAD_FORMAT;
|
||||
}
|
||||
|
||||
void CARTRIDGE_Remove(void)
|
||||
{
|
||||
CARTRIDGE_type = CARTRIDGE_NONE;
|
||||
if (cart_image != NULL) {
|
||||
free(cart_image);
|
||||
cart_image = NULL;
|
||||
}
|
||||
CARTRIDGE_Start();
|
||||
}
|
||||
|
||||
void CARTRIDGE_Start(void) {
|
||||
if (Atari800_machine_type == Atari800_MACHINE_5200) {
|
||||
MEMORY_SetROM(0x4ff6, 0x4ff9); /* disable Bounty Bob bank switching */
|
||||
MEMORY_SetROM(0x5ff6, 0x5ff9);
|
||||
switch (CARTRIDGE_type) {
|
||||
case CARTRIDGE_5200_32:
|
||||
MEMORY_CopyROM(0x4000, 0xbfff, cart_image);
|
||||
break;
|
||||
case CARTRIDGE_5200_EE_16:
|
||||
MEMORY_CopyROM(0x4000, 0x5fff, cart_image);
|
||||
MEMORY_CopyROM(0x6000, 0x9fff, cart_image);
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + 0x2000);
|
||||
break;
|
||||
case CARTRIDGE_5200_40:
|
||||
MEMORY_CopyROM(0x4000, 0x4fff, cart_image);
|
||||
MEMORY_CopyROM(0x5000, 0x5fff, cart_image + 0x4000);
|
||||
MEMORY_CopyROM(0x8000, 0x9fff, cart_image + 0x8000);
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + 0x8000);
|
||||
#ifndef PAGED_ATTRIB
|
||||
MEMORY_SetHARDWARE(0x4ff6, 0x4ff9);
|
||||
MEMORY_SetHARDWARE(0x5ff6, 0x5ff9);
|
||||
#else
|
||||
MEMORY_readmap[0x4f] = CARTRIDGE_BountyBob1GetByte;
|
||||
MEMORY_readmap[0x5f] = CARTRIDGE_BountyBob2GetByte;
|
||||
MEMORY_writemap[0x4f] = CARTRIDGE_BountyBob1PutByte;
|
||||
MEMORY_writemap[0x5f] = CARTRIDGE_BountyBob2PutByte;
|
||||
#endif
|
||||
break;
|
||||
case CARTRIDGE_5200_NS_16:
|
||||
MEMORY_CopyROM(0x8000, 0xbfff, cart_image);
|
||||
break;
|
||||
case CARTRIDGE_5200_8:
|
||||
MEMORY_CopyROM(0x8000, 0x9fff, cart_image);
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image);
|
||||
break;
|
||||
case CARTRIDGE_5200_4:
|
||||
MEMORY_CopyROM(0x8000, 0x8fff, cart_image);
|
||||
MEMORY_CopyROM(0x9000, 0x9fff, cart_image);
|
||||
MEMORY_CopyROM(0xa000, 0xafff, cart_image);
|
||||
MEMORY_CopyROM(0xb000, 0xbfff, cart_image);
|
||||
break;
|
||||
default:
|
||||
/* clear cartridge area so the 5200 will crash */
|
||||
MEMORY_dFillMem(0x4000, 0, 0x8000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (CARTRIDGE_type) {
|
||||
case CARTRIDGE_STD_8:
|
||||
case CARTRIDGE_PHOENIX_8:
|
||||
MEMORY_Cart809fDisable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image);
|
||||
break;
|
||||
case CARTRIDGE_STD_16:
|
||||
case CARTRIDGE_BLIZZARD_16:
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0xbfff, cart_image);
|
||||
break;
|
||||
case CARTRIDGE_OSS_16:
|
||||
MEMORY_Cart809fDisable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xafff, cart_image);
|
||||
MEMORY_CopyROM(0xb000, 0xbfff, cart_image + 0x3000);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_DB_32:
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0x9fff, cart_image);
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + 0x6000);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_WILL_64:
|
||||
case CARTRIDGE_WILL_32:
|
||||
case CARTRIDGE_EXP_64:
|
||||
case CARTRIDGE_DIAMOND_64:
|
||||
case CARTRIDGE_SDX_64:
|
||||
case CARTRIDGE_SDX_128:
|
||||
MEMORY_Cart809fDisable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_XEGS_32:
|
||||
case CARTRIDGE_SWXEGS_32:
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0x9fff, cart_image);
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + 0x6000);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_XEGS_64:
|
||||
case CARTRIDGE_SWXEGS_64:
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0x9fff, cart_image);
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + 0xe000);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_XEGS_128:
|
||||
case CARTRIDGE_SWXEGS_128:
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0x9fff, cart_image);
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + 0x1e000);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_XEGS_256:
|
||||
case CARTRIDGE_SWXEGS_256:
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0x9fff, cart_image);
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + 0x3e000);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_XEGS_512:
|
||||
case CARTRIDGE_SWXEGS_512:
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0x9fff, cart_image);
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + 0x7e000);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_XEGS_1024:
|
||||
case CARTRIDGE_SWXEGS_1024:
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0x9fff, cart_image);
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + 0xfe000);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_OSS2_16:
|
||||
MEMORY_Cart809fDisable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xafff, cart_image + 0x1000);
|
||||
MEMORY_CopyROM(0xb000, 0xbfff, cart_image);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_ATRAX_128:
|
||||
MEMORY_Cart809fDisable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_BBSB_40:
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0x8fff, cart_image);
|
||||
MEMORY_CopyROM(0x9000, 0x9fff, cart_image + 0x4000);
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + 0x8000);
|
||||
#ifndef PAGED_ATTRIB
|
||||
MEMORY_SetHARDWARE(0x8ff6, 0x8ff9);
|
||||
MEMORY_SetHARDWARE(0x9ff6, 0x9ff9);
|
||||
#else
|
||||
MEMORY_readmap[0x8f] = CARTRIDGE_BountyBob1GetByte;
|
||||
MEMORY_readmap[0x9f] = CARTRIDGE_BountyBob2GetByte;
|
||||
MEMORY_writemap[0x8f] = CARTRIDGE_BountyBob1PutByte;
|
||||
MEMORY_writemap[0x9f] = CARTRIDGE_BountyBob2PutByte;
|
||||
#endif
|
||||
break;
|
||||
case CARTRIDGE_RIGHT_8:
|
||||
if (Atari800_machine_type == Atari800_MACHINE_OSA || Atari800_machine_type == Atari800_MACHINE_OSB) {
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CopyROM(0x8000, 0x9fff, cart_image);
|
||||
if ((!Atari800_disable_basic || BINLOAD_loading_basic) && MEMORY_have_basic) {
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, MEMORY_basic);
|
||||
break;
|
||||
}
|
||||
MEMORY_CartA0bfDisable();
|
||||
break;
|
||||
}
|
||||
/* there's no right slot in XL/XE */
|
||||
MEMORY_Cart809fDisable();
|
||||
MEMORY_CartA0bfDisable();
|
||||
break;
|
||||
case CARTRIDGE_MEGA_16:
|
||||
case CARTRIDGE_MEGA_32:
|
||||
case CARTRIDGE_MEGA_64:
|
||||
case CARTRIDGE_MEGA_128:
|
||||
case CARTRIDGE_MEGA_256:
|
||||
case CARTRIDGE_MEGA_512:
|
||||
case CARTRIDGE_MEGA_1024:
|
||||
MEMORY_Cart809fEnable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0x8000, 0xbfff, cart_image);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_ATMAX_128:
|
||||
MEMORY_Cart809fDisable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image);
|
||||
bank = 0;
|
||||
break;
|
||||
case CARTRIDGE_ATMAX_1024:
|
||||
MEMORY_Cart809fDisable();
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, cart_image + 0xfe000);
|
||||
bank = 0x7f;
|
||||
break;
|
||||
default:
|
||||
MEMORY_Cart809fDisable();
|
||||
if ((Atari800_machine_type == Atari800_MACHINE_OSA || Atari800_machine_type == Atari800_MACHINE_OSB)
|
||||
&& (!Atari800_disable_basic || BINLOAD_loading_basic) && MEMORY_have_basic) {
|
||||
MEMORY_CartA0bfEnable();
|
||||
MEMORY_CopyROM(0xa000, 0xbfff, MEMORY_basic);
|
||||
break;
|
||||
}
|
||||
MEMORY_CartA0bfDisable();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BASIC
|
||||
|
||||
void CARTRIDGE_StateRead(void)
|
||||
{
|
||||
int savedCartType = CARTRIDGE_NONE;
|
||||
|
||||
/* Read the cart type from the file. If there is no cart type, becaused we have
|
||||
reached the end of the file, this will just default to CARTRIDGE_NONE */
|
||||
StateSav_ReadINT(&savedCartType, 1);
|
||||
if (savedCartType != CARTRIDGE_NONE) {
|
||||
char filename[FILENAME_MAX];
|
||||
StateSav_ReadFNAME(filename);
|
||||
if (filename[0]) {
|
||||
/* Insert the cartridge... */
|
||||
if (CARTRIDGE_Insert(filename) >= 0) {
|
||||
/* And set the type to the saved type, in case it was a raw cartridge image */
|
||||
CARTRIDGE_type = savedCartType;
|
||||
CARTRIDGE_Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CARTRIDGE_StateSave(void)
|
||||
{
|
||||
/* Save the cartridge type, or CARTRIDGE_NONE if there isn't one...*/
|
||||
StateSav_SaveINT(&CARTRIDGE_type, 1);
|
||||
if (CARTRIDGE_type != CARTRIDGE_NONE) {
|
||||
StateSav_SaveFNAME(cart_filename);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,81 +0,0 @@
|
||||
#ifndef CARTRIDGE_H_
|
||||
#define CARTRIDGE_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "atari.h"
|
||||
|
||||
#define CARTRIDGE_NONE 0
|
||||
#define CARTRIDGE_STD_8 1
|
||||
#define CARTRIDGE_STD_16 2
|
||||
#define CARTRIDGE_OSS_16 3
|
||||
#define CARTRIDGE_5200_32 4
|
||||
#define CARTRIDGE_DB_32 5
|
||||
#define CARTRIDGE_5200_EE_16 6
|
||||
#define CARTRIDGE_5200_40 7
|
||||
#define CARTRIDGE_WILL_64 8
|
||||
#define CARTRIDGE_EXP_64 9
|
||||
#define CARTRIDGE_DIAMOND_64 10
|
||||
#define CARTRIDGE_SDX_64 11
|
||||
#define CARTRIDGE_XEGS_32 12
|
||||
#define CARTRIDGE_XEGS_64 13
|
||||
#define CARTRIDGE_XEGS_128 14
|
||||
#define CARTRIDGE_OSS2_16 15
|
||||
#define CARTRIDGE_5200_NS_16 16
|
||||
#define CARTRIDGE_ATRAX_128 17
|
||||
#define CARTRIDGE_BBSB_40 18
|
||||
#define CARTRIDGE_5200_8 19
|
||||
#define CARTRIDGE_5200_4 20
|
||||
#define CARTRIDGE_RIGHT_8 21
|
||||
#define CARTRIDGE_WILL_32 22
|
||||
#define CARTRIDGE_XEGS_256 23
|
||||
#define CARTRIDGE_XEGS_512 24
|
||||
#define CARTRIDGE_XEGS_1024 25
|
||||
#define CARTRIDGE_MEGA_16 26
|
||||
#define CARTRIDGE_MEGA_32 27
|
||||
#define CARTRIDGE_MEGA_64 28
|
||||
#define CARTRIDGE_MEGA_128 29
|
||||
#define CARTRIDGE_MEGA_256 30
|
||||
#define CARTRIDGE_MEGA_512 31
|
||||
#define CARTRIDGE_MEGA_1024 32
|
||||
#define CARTRIDGE_SWXEGS_32 33
|
||||
#define CARTRIDGE_SWXEGS_64 34
|
||||
#define CARTRIDGE_SWXEGS_128 35
|
||||
#define CARTRIDGE_SWXEGS_256 36
|
||||
#define CARTRIDGE_SWXEGS_512 37
|
||||
#define CARTRIDGE_SWXEGS_1024 38
|
||||
#define CARTRIDGE_PHOENIX_8 39
|
||||
#define CARTRIDGE_BLIZZARD_16 40
|
||||
#define CARTRIDGE_ATMAX_128 41
|
||||
#define CARTRIDGE_ATMAX_1024 42
|
||||
#define CARTRIDGE_SDX_128 43
|
||||
#define CARTRIDGE_LAST_SUPPORTED 43
|
||||
|
||||
#define CARTRIDGE_MAX_SIZE (1024 * 1024)
|
||||
extern int CARTRIDGE_kb[CARTRIDGE_LAST_SUPPORTED + 1];
|
||||
extern int CARTRIDGE_type;
|
||||
|
||||
int CARTRIDGE_IsFor5200(int type);
|
||||
int CARTRIDGE_Checksum(const UBYTE *image, int nbytes);
|
||||
|
||||
#define CARTRIDGE_CANT_OPEN -1 /* Can't open cartridge image file */
|
||||
#define CARTRIDGE_BAD_FORMAT -2 /* Unknown cartridge format */
|
||||
#define CARTRIDGE_BAD_CHECKSUM -3 /* Warning: bad CART checksum */
|
||||
int CARTRIDGE_Insert(const char *filename);
|
||||
|
||||
void CARTRIDGE_Remove(void);
|
||||
|
||||
void CARTRIDGE_Start(void);
|
||||
UBYTE CARTRIDGE_GetByte(UWORD addr);
|
||||
void CARTRIDGE_PutByte(UWORD addr, UBYTE byte);
|
||||
void CARTRIDGE_BountyBob1(UWORD addr);
|
||||
void CARTRIDGE_BountyBob2(UWORD addr);
|
||||
void CARTRIDGE_StateSave(void);
|
||||
void CARTRIDGE_StateRead(void);
|
||||
#ifdef PAGED_ATTRIB
|
||||
UBYTE CARTRIDGE_BountyBob1GetByte(UWORD addr);
|
||||
UBYTE CARTRIDGE_BountyBob2GetByte(UWORD addr);
|
||||
void CARTRIDGE_BountyBob1PutByte(UWORD addr, UBYTE value);
|
||||
void CARTRIDGE_BountyBob2PutByte(UWORD addr, UBYTE value);
|
||||
#endif
|
||||
|
||||
#endif /* CARTRIDGE_H_ */
|
||||
@@ -1,752 +0,0 @@
|
||||
/*
|
||||
* cassette.c - cassette emulation
|
||||
*
|
||||
* Copyright (C) 2001 Piotr Fusik
|
||||
* Copyright (C) 2001-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "atari.h"
|
||||
#include "cpu.h"
|
||||
#include "cassette.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "sio.h"
|
||||
#include "util.h"
|
||||
#include "pokey.h"
|
||||
|
||||
#define MAX_BLOCKS 2048
|
||||
|
||||
static FILE *cassette_file = NULL;
|
||||
static int cassette_isCAS;
|
||||
UBYTE CASSETTE_buffer[4096];
|
||||
static ULONG cassette_block_offset[MAX_BLOCKS];
|
||||
static SLONG cassette_elapsedtime; /* elapsed time since begin of file */
|
||||
/* in scanlines */
|
||||
static SLONG cassette_savetime; /* helper for cas save */
|
||||
static SLONG cassette_nextirqevent; /* timestamp of next irq in scanlines */
|
||||
|
||||
static char cassette_filename[FILENAME_MAX];
|
||||
static char cassette_description[CASSETTE_DESCRIPTION_MAX];
|
||||
static int cassette_current_blockbyte = 0;
|
||||
static int cassette_current_block;
|
||||
static int cassette_max_blockbytes = 0;
|
||||
static int cassette_max_block = 0;
|
||||
static int cassette_savefile = FALSE;
|
||||
static int cassette_gapdelay = 0; /* in ms, includes leader and all gaps */
|
||||
static int cassette_putdelay = 0; /* in ms, delay since last putbyte */
|
||||
static int cassette_motor = 0;
|
||||
static int cassette_baudrate = 600;
|
||||
static int cassette_baudblock[MAX_BLOCKS];
|
||||
|
||||
int CASSETTE_hold_start_on_reboot = 0;
|
||||
int CASSETTE_hold_start = 0;
|
||||
int CASSETTE_press_space = 0;
|
||||
static int eof_of_tape = 0;
|
||||
|
||||
typedef struct {
|
||||
char identifier[4];
|
||||
UBYTE length_lo;
|
||||
UBYTE length_hi;
|
||||
UBYTE aux_lo;
|
||||
UBYTE aux_hi;
|
||||
} CAS_Header;
|
||||
/*
|
||||
Just for remembering - CAS format in short:
|
||||
It consists of chunks. Each chunk has a header, possibly followed by data.
|
||||
If a header is unknown or unexpected it may be skipped by the length of the
|
||||
header (8 bytes), and additionally the length given in the length-field(s).
|
||||
There are (until now) 3 types of chunks:
|
||||
-CAS file marker, has to be at begin of file - identifier "FUJI", length is
|
||||
number of characters of an (optional) ascii-name (without trailing 0), aux
|
||||
is always 0.
|
||||
-baud rate selector - identifier "baud", length always 0, aux is rate in baud
|
||||
(usually 600; one byte is 8 bits + startbit + stopbit, makes 60 bytes per
|
||||
second).
|
||||
-data record - identifier "data", length is length of the data block (usually
|
||||
$84 as used by the OS), aux is length of mark tone (including leader and gaps)
|
||||
just before the record data in milliseconds.
|
||||
*/
|
||||
|
||||
int CASSETTE_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
|
||||
strcpy(cassette_filename, "None");
|
||||
memset(cassette_description, 0, sizeof(cassette_description));
|
||||
|
||||
for (i = j = 1; i < *argc; i++) {
|
||||
int i_a = (i + 1 < *argc); /* is argument available? */
|
||||
int a_m = FALSE; /* error, argument missing! */
|
||||
|
||||
if (strcmp(argv[i], "-tape") == 0) {
|
||||
if (i_a)
|
||||
CASSETTE_Insert(argv[++i]);
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-boottape") == 0) {
|
||||
if (i_a) {
|
||||
CASSETTE_Insert(argv[++i]);
|
||||
CASSETTE_hold_start = 1;
|
||||
}
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
Log_print("\t-tape <file> Insert cassette image");
|
||||
Log_print("\t-boottape <file> Insert cassette image and boot it");
|
||||
}
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
|
||||
if (a_m) {
|
||||
Log_print("Missing argument for '%s'", argv[i]);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
*argc = j;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Gets information about the cassette image. Returns TRUE if ok.
|
||||
To get information without attaching file, use:
|
||||
char description[CASSETTE_DESCRIPTION_MAX];
|
||||
int last_block;
|
||||
int isCAS;
|
||||
CASSETTE_CheckFile(filename, NULL, description, &last_block, &isCAS);
|
||||
*/
|
||||
int CASSETTE_CheckFile(const char *filename, FILE **fp, char *description, int *last_block, int *isCAS)
|
||||
{
|
||||
FILE *f;
|
||||
CAS_Header header;
|
||||
int blocks;
|
||||
|
||||
/* atm, no appending to existing cas files - too dangerous to data!
|
||||
and will not work anyway without patched sio
|
||||
f = fopen(filename, "rb+");
|
||||
if (f == NULL) */
|
||||
f = fopen(filename, "rb");
|
||||
if (f == NULL)
|
||||
return FALSE;
|
||||
if (description)
|
||||
memset(description, 0, CASSETTE_DESCRIPTION_MAX);
|
||||
|
||||
if (fread(&header, 1, 6, f) == 6
|
||||
&& header.identifier[0] == 'F'
|
||||
&& header.identifier[1] == 'U'
|
||||
&& header.identifier[2] == 'J'
|
||||
&& header.identifier[3] == 'I') {
|
||||
/* CAS file */
|
||||
UWORD length;
|
||||
UWORD skip;
|
||||
if (isCAS)
|
||||
*isCAS = TRUE;
|
||||
fseek(f, 2L, SEEK_CUR); /* ignore the aux bytes */
|
||||
|
||||
/* read or skip file description */
|
||||
skip = length = header.length_lo + (header.length_hi << 8);
|
||||
if (description) {
|
||||
if (length < CASSETTE_DESCRIPTION_MAX)
|
||||
skip = 0;
|
||||
else
|
||||
skip -= CASSETTE_DESCRIPTION_MAX - 1;
|
||||
fread(description, 1, length - skip, f);
|
||||
}
|
||||
fseek(f, skip, SEEK_CUR);
|
||||
|
||||
/* count number of blocks */
|
||||
blocks = 0;
|
||||
cassette_baudblock[0]=600;
|
||||
do {
|
||||
/* chunk header is always 8 bytes */
|
||||
if (fread(&header, 1, 8, f) != 8)
|
||||
break;
|
||||
if (header.identifier[0] == 'b'
|
||||
&& header.identifier[1] == 'a'
|
||||
&& header.identifier[2] == 'u'
|
||||
&& header.identifier[3] == 'd') {
|
||||
cassette_baudrate=header.aux_lo + (header.aux_hi << 8);
|
||||
}
|
||||
else if (header.identifier[0] == 'd'
|
||||
&& header.identifier[1] == 'a'
|
||||
&& header.identifier[2] == 't'
|
||||
&& header.identifier[3] == 'a') {
|
||||
blocks++;
|
||||
if (fp) {
|
||||
cassette_block_offset[blocks] = ftell(f) - 4;
|
||||
cassette_baudblock[blocks] = cassette_baudrate;
|
||||
}
|
||||
}
|
||||
length = header.length_lo + (header.length_hi << 8);
|
||||
/* skip possibly present data block */
|
||||
fseek(f, length, SEEK_CUR);
|
||||
} while (blocks < MAX_BLOCKS);
|
||||
}
|
||||
else {
|
||||
/* raw file */
|
||||
int file_length = Util_flen(f);
|
||||
blocks = ((file_length + 127) >> 7) + 1;
|
||||
if (isCAS)
|
||||
*isCAS = FALSE;
|
||||
}
|
||||
if (last_block)
|
||||
*last_block = blocks;
|
||||
/* if filelength is 0, then it is a savefile */
|
||||
fseek(f,0L,SEEK_SET);
|
||||
if (fread(&header, 1, 4, f) == 0) {
|
||||
cassette_savefile = TRUE;
|
||||
}
|
||||
if (fp)
|
||||
*fp = f;
|
||||
else
|
||||
fclose(f);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Create CAS file header for saving data to tape */
|
||||
int CASSETTE_CreateFile(const char *filename, FILE **fp, int *isCAS)
|
||||
{
|
||||
CAS_Header header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
|
||||
/* if no file pointer location was given, this function is senseless */
|
||||
if (fp == NULL)
|
||||
return FALSE;
|
||||
/* close if open */
|
||||
if (*fp != NULL)
|
||||
fclose(*fp);
|
||||
/* create new file */
|
||||
*fp = fopen(filename, "wb");
|
||||
if (*fp == NULL)
|
||||
return FALSE;
|
||||
|
||||
/* write CAS-header */
|
||||
{
|
||||
size_t desc_len = strlen(cassette_description);
|
||||
header.length_lo = (UBYTE) desc_len;
|
||||
header.length_hi = (UBYTE) (desc_len >> 8);
|
||||
if (fwrite("FUJI", 1, 4, *fp) == 4
|
||||
&& fwrite(&header.length_lo, 1, 4, *fp) == 4
|
||||
&& fwrite(cassette_description, 1, desc_len, *fp) == desc_len) {
|
||||
/* ok */
|
||||
}
|
||||
else {
|
||||
fclose(*fp);
|
||||
*fp = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.aux_lo = cassette_baudrate & 0xff; /* provisional: 600 baud */
|
||||
header.aux_hi = cassette_baudrate >> 8;
|
||||
if ((fwrite("baud", 1, 4, *fp) == 4)
|
||||
&& (fwrite(&header.length_lo, 1, 4, *fp) == 4)) {
|
||||
/* ok */
|
||||
}
|
||||
else {
|
||||
fclose(*fp);
|
||||
*fp = NULL;
|
||||
return FALSE;
|
||||
};
|
||||
|
||||
/* file is now a cassette file */
|
||||
*isCAS = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int CASSETTE_Insert(const char *filename)
|
||||
{
|
||||
CASSETTE_Remove();
|
||||
strcpy(cassette_filename, filename);
|
||||
cassette_elapsedtime = 0;
|
||||
cassette_savetime = 0;
|
||||
cassette_nextirqevent = 0;
|
||||
cassette_current_blockbyte = 0;
|
||||
cassette_max_blockbytes = 0;
|
||||
cassette_current_block = 1;
|
||||
cassette_gapdelay = 0;
|
||||
eof_of_tape = 0;
|
||||
cassette_savefile = FALSE;
|
||||
cassette_baudrate = 600;
|
||||
return CASSETTE_CheckFile(filename, &cassette_file, cassette_description,
|
||||
&cassette_max_block, &cassette_isCAS);
|
||||
}
|
||||
|
||||
void CASSETTE_Remove(void)
|
||||
{
|
||||
if (cassette_file != NULL) {
|
||||
/* save last block, ignore trailing space tone */
|
||||
if ((cassette_current_blockbyte > 0) && cassette_savefile)
|
||||
CASSETTE_Write(cassette_current_blockbyte);
|
||||
|
||||
fclose(cassette_file);
|
||||
cassette_file = NULL;
|
||||
}
|
||||
cassette_max_block = 0;
|
||||
strcpy(cassette_filename, "None");
|
||||
memset(cassette_description, 0, sizeof(cassette_description));
|
||||
}
|
||||
|
||||
/* Read a record by SIO-patch
|
||||
returns block length (with checksum) */
|
||||
static int ReadRecord_SIO(void)
|
||||
{
|
||||
int length = 0;
|
||||
if (cassette_isCAS) {
|
||||
CAS_Header header;
|
||||
/* if waiting for gap was longer than gap of record, skip
|
||||
atm there is no check if we start then inmidst a record */
|
||||
int filegaptimes = 0;
|
||||
while (cassette_gapdelay >= filegaptimes) {
|
||||
if (cassette_current_block > cassette_max_block) {
|
||||
length = -1;
|
||||
break;
|
||||
};
|
||||
fseek(cassette_file, cassette_block_offset[cassette_current_block], SEEK_SET);
|
||||
fread(&header.length_lo, 1, 4, cassette_file);
|
||||
length = header.length_lo + (header.length_hi << 8);
|
||||
/* add gaplength */
|
||||
filegaptimes += header.aux_lo + (header.aux_hi << 8);
|
||||
/* add time used by the data themselves
|
||||
a byte is encoded into 10 bits */
|
||||
filegaptimes += length * 10 * 1000 / cassette_baudblock[cassette_current_block];
|
||||
|
||||
fread(&CASSETTE_buffer[0], 1, length, cassette_file);
|
||||
cassette_current_block++;
|
||||
}
|
||||
cassette_gapdelay = 0;
|
||||
}
|
||||
else {
|
||||
length = 132;
|
||||
CASSETTE_buffer[0] = 0x55;
|
||||
CASSETTE_buffer[1] = 0x55;
|
||||
if (cassette_current_block >= cassette_max_block) {
|
||||
/* EOF record */
|
||||
CASSETTE_buffer[2] = 0xfe;
|
||||
memset(CASSETTE_buffer + 3, 0, 128);
|
||||
}
|
||||
else {
|
||||
int bytes;
|
||||
fseek(cassette_file, (cassette_current_block - 1) * 128, SEEK_SET);
|
||||
bytes = fread(CASSETTE_buffer + 3, 1, 128, cassette_file);
|
||||
if (bytes < 128) {
|
||||
CASSETTE_buffer[2] = 0xfa; /* non-full record */
|
||||
memset(CASSETTE_buffer + 3 + bytes, 0, 127 - bytes);
|
||||
CASSETTE_buffer[0x82] = bytes;
|
||||
}
|
||||
else
|
||||
CASSETTE_buffer[2] = 0xfc; /* full record */
|
||||
}
|
||||
CASSETTE_buffer[0x83] = SIO_ChkSum(CASSETTE_buffer, 0x83);
|
||||
cassette_current_block++;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
static UWORD WriteRecord(int len)
|
||||
{
|
||||
CAS_Header header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
|
||||
/* always append */
|
||||
fseek(cassette_file, 0, SEEK_END);
|
||||
/* write recordheader */
|
||||
Util_strncpy(header.identifier, "data", 4);
|
||||
header.length_lo = len & 0xFF;
|
||||
header.length_hi = (len >> 8) & 0xFF;
|
||||
header.aux_lo = cassette_gapdelay & 0xff;
|
||||
header.aux_hi = (cassette_gapdelay >> 8) & 0xff;
|
||||
cassette_gapdelay = 0;
|
||||
fwrite(&header, 1, 8, cassette_file);
|
||||
cassette_max_block++;
|
||||
cassette_current_block++;
|
||||
/* write record */
|
||||
return fwrite(&CASSETTE_buffer, 1, len, cassette_file);
|
||||
}
|
||||
|
||||
int CASSETTE_AddGap(int gaptime)
|
||||
{
|
||||
cassette_gapdelay += gaptime;
|
||||
if (cassette_gapdelay < 0)
|
||||
cassette_gapdelay = 0;
|
||||
return cassette_gapdelay;
|
||||
}
|
||||
|
||||
/* Indicates that a loading leader is expected by the OS */
|
||||
void CASSETTE_LeaderLoad(void)
|
||||
{
|
||||
cassette_gapdelay = 9600;
|
||||
/* registers for SETVBV: third system timer, ~0.1 sec */
|
||||
CPU_regA = 3;
|
||||
CPU_regX = 0;
|
||||
CPU_regY = 5;
|
||||
}
|
||||
|
||||
/* indicates that a save leader is written by the OS */
|
||||
void CASSETTE_LeaderSave(void)
|
||||
{
|
||||
cassette_gapdelay = 19200;
|
||||
/* registers for SETVBV: third system timer, ~0.1 sec */
|
||||
CPU_regA = 3;
|
||||
CPU_regX = 0;
|
||||
CPU_regY = 5;
|
||||
}
|
||||
|
||||
/* Read Cassette Record from Storage medium
|
||||
returns size of data in buffer (atm equal with record size, but there
|
||||
are protections with variable baud rates imaginable where a record
|
||||
must be split and a baud chunk inserted inbetween) or -1 for error */
|
||||
int CASSETTE_Read(void)
|
||||
{
|
||||
/* no file or blockpositions don't match anymore after saving */
|
||||
if ((cassette_file == NULL) || (cassette_savefile == TRUE))
|
||||
return -1;
|
||||
if (cassette_current_block > cassette_max_block)
|
||||
return -1; /* EOF */
|
||||
return ReadRecord_SIO();
|
||||
}
|
||||
|
||||
/* Write Cassette Record to Storage medium
|
||||
length is size of the whole data with checksum(s)
|
||||
returns really written bytes, -1 for error */
|
||||
int CASSETTE_Write(int length)
|
||||
{
|
||||
/* there must be a filename given for saving */
|
||||
if (strcmp(cassette_filename, "None") == 0)
|
||||
return -1;
|
||||
/* if file doesn't exist (or has no records), create the header */
|
||||
if ((cassette_file == NULL || ftell(cassette_file) == 0) &&
|
||||
(CASSETTE_CreateFile(cassette_filename,
|
||||
&cassette_file,&cassette_isCAS) == FALSE))
|
||||
return -1;
|
||||
/* on a raw file, saving is denied because it can hold
|
||||
only 1 file and could cause confusion */
|
||||
if (cassette_isCAS == FALSE)
|
||||
return -1;
|
||||
/* save record (always appends to the end of file) */
|
||||
cassette_savefile = TRUE;
|
||||
return WriteRecord(length);
|
||||
}
|
||||
|
||||
/* convert milliseconds to scanlines */
|
||||
static SLONG MSToScanLines(int ms)
|
||||
{
|
||||
/* for PAL resolution, deviation in NTSC is negligible */
|
||||
return 312*50*ms/1000;
|
||||
}
|
||||
|
||||
/* Support to read a record by POKEY-registers
|
||||
evals gap length
|
||||
returns block length (with checksum) */
|
||||
static int ReadRecord_POKEY(void)
|
||||
{
|
||||
int length = 0;
|
||||
if (cassette_isCAS) {
|
||||
CAS_Header header;
|
||||
/* no file or blockpositions don't match anymore after saving */
|
||||
if ((cassette_file == NULL) || (cassette_savefile == TRUE)) {
|
||||
cassette_nextirqevent = -1;
|
||||
length = -1;
|
||||
return length;
|
||||
}
|
||||
/* if end of CAS file */
|
||||
if (cassette_current_block > cassette_max_block){
|
||||
cassette_nextirqevent = -1;
|
||||
length = -1;
|
||||
eof_of_tape = 1;
|
||||
return length;
|
||||
}
|
||||
else {
|
||||
fseek(cassette_file, cassette_block_offset[
|
||||
cassette_current_block], SEEK_SET);
|
||||
fread(&header.length_lo, 1, 4, cassette_file);
|
||||
length = header.length_lo + (header.length_hi << 8);
|
||||
/* eval total length as pregap + 1 byte */
|
||||
cassette_nextirqevent = cassette_elapsedtime +
|
||||
MSToScanLines(
|
||||
header.aux_lo + (header.aux_hi << 8)
|
||||
+ 10 * 1000 / cassette_baudblock[
|
||||
cassette_current_block]);
|
||||
/* read block into buffer */
|
||||
fread(&CASSETTE_buffer[0], 1, length, cassette_file);
|
||||
cassette_max_blockbytes = length;
|
||||
cassette_current_blockbyte = 0;
|
||||
cassette_current_block++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
length = 132;
|
||||
CASSETTE_buffer[0] = 0x55;
|
||||
CASSETTE_buffer[1] = 0x55;
|
||||
if (cassette_current_block >= cassette_max_block) {
|
||||
/* EOF record */
|
||||
CASSETTE_buffer[2] = 0xfe;
|
||||
memset(CASSETTE_buffer + 3, 0, 128);
|
||||
if (cassette_current_block > cassette_max_block) {
|
||||
eof_of_tape = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int bytes;
|
||||
fseek(cassette_file,
|
||||
(cassette_current_block - 1) * 128, SEEK_SET);
|
||||
bytes = fread(CASSETTE_buffer + 3, 1, 128,
|
||||
cassette_file);
|
||||
if (bytes < 128) {
|
||||
CASSETTE_buffer[2] = 0xfa; /* non-full record */
|
||||
memset(CASSETTE_buffer + 3 + bytes, 0,
|
||||
127 - bytes);
|
||||
CASSETTE_buffer[0x82] = bytes;
|
||||
}
|
||||
else
|
||||
CASSETTE_buffer[2] = 0xfc; /* full record */
|
||||
}
|
||||
CASSETTE_buffer[0x83] = SIO_ChkSum(CASSETTE_buffer, 0x83);
|
||||
/* eval time to first byte coming out of pokey */
|
||||
if (cassette_current_block == 1) {
|
||||
/* on first block, length includes a leader */
|
||||
cassette_nextirqevent = cassette_elapsedtime +
|
||||
MSToScanLines(19200
|
||||
+ 10 * 1000 / 600); /* always 600 baud */
|
||||
}
|
||||
else {
|
||||
cassette_nextirqevent = cassette_elapsedtime +
|
||||
MSToScanLines(260
|
||||
+ 10 * 1000 / 600); /* always 600 baud */
|
||||
}
|
||||
cassette_max_blockbytes = length;
|
||||
cassette_current_blockbyte = 0;
|
||||
cassette_current_block++;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/* sets the stamp of next irq and loads new record if necessary
|
||||
adjust is a value to correction of time of next irq*/
|
||||
static int SetNextByteTime_POKEY(int adjust)
|
||||
{
|
||||
int length = 0;
|
||||
cassette_current_blockbyte += 1;
|
||||
/* if there are still bytes in the buffer, take next byte */
|
||||
if (cassette_current_blockbyte < cassette_max_blockbytes) {
|
||||
cassette_nextirqevent = cassette_elapsedtime + adjust
|
||||
+ MSToScanLines(10 * 1000 / (cassette_isCAS?cassette_baudblock[
|
||||
cassette_current_block-1]:600));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if buffer is exhausted, load next record */
|
||||
length = ReadRecord_POKEY();
|
||||
/* if failed, return -1 */
|
||||
if (length == -1) {
|
||||
cassette_nextirqevent = -1;
|
||||
return -1;
|
||||
}
|
||||
cassette_nextirqevent += adjust;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the byte for which the serial data ready int has been triggered */
|
||||
int CASSETTE_GetByte(void)
|
||||
{
|
||||
/* there are programs which load 2 blocks as one */
|
||||
return CASSETTE_buffer[cassette_current_blockbyte];
|
||||
}
|
||||
|
||||
/* Check status of I/O-line
|
||||
Mark tone and stop bit gives 1, start bit 0
|
||||
$55 as data give 1,0,1,0,1,0,1,0 (sync to evaluate tape speed,
|
||||
least significant bit first)
|
||||
returns state of I/O-line as block.byte.bit */
|
||||
int CASSETTE_IOLineStatus(void)
|
||||
{
|
||||
int bit = 0;
|
||||
|
||||
/* if motor off and EOF return always 1 (equivalent the mark tone) */
|
||||
if ((cassette_motor == 0)
|
||||
|| (eof_of_tape != 0)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* exam rate; if elapsed time > nextirq - duration of one byte */
|
||||
if (cassette_elapsedtime >
|
||||
(cassette_nextirqevent - 10 * 50 * 312 /
|
||||
(cassette_isCAS?cassette_baudblock[cassette_current_block-1]:
|
||||
600) + 1)) {
|
||||
bit = (cassette_nextirqevent - cassette_elapsedtime)
|
||||
/ (50 * 312 / (cassette_isCAS?cassette_baudblock[
|
||||
cassette_current_block-1]:600));
|
||||
}
|
||||
else {
|
||||
bit = 0;
|
||||
}
|
||||
|
||||
/* if stopbit or out of range, return mark tone */
|
||||
if ((bit <= 0) || (bit > 9))
|
||||
return 1;
|
||||
|
||||
/* if start bit, return space tone */
|
||||
if (bit == 9)
|
||||
return 0;
|
||||
|
||||
/* eval tone to return */
|
||||
return (CASSETTE_GetByte() >> (8 - bit)) & 1;
|
||||
}
|
||||
|
||||
/* Get the delay to trigger the next interrupt
|
||||
remark: The I/O-Line-status is also evaluated on this basis */
|
||||
int CASSETTE_GetInputIRQDelay(void)
|
||||
{
|
||||
int timespan;
|
||||
|
||||
/* if no file or eof or motor off, return zero */
|
||||
if ((cassette_file == NULL)
|
||||
|| (eof_of_tape != 0)
|
||||
|| (cassette_motor == 0)
|
||||
|| (cassette_nextirqevent < 0)
|
||||
|| cassette_savefile) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return time span */
|
||||
timespan = cassette_nextirqevent - cassette_elapsedtime;
|
||||
/* if timespan is negative, eval timespan to next byte */
|
||||
if (timespan <= 0) {
|
||||
if (SetNextByteTime_POKEY(0) == -1) {
|
||||
return -1;
|
||||
}
|
||||
/* return time span */
|
||||
timespan = cassette_nextirqevent - cassette_elapsedtime;
|
||||
}
|
||||
if (timespan < 40) {
|
||||
timespan += ((312 * 50 - 1) / (cassette_isCAS?cassette_baudblock[
|
||||
cassette_current_block-1]:600)) * 10;
|
||||
}
|
||||
|
||||
/* if still negative, return "failed" */
|
||||
if (timespan < 0) {
|
||||
timespan = -1;
|
||||
}
|
||||
return timespan;
|
||||
}
|
||||
|
||||
/* return if save file */
|
||||
int CASSETTE_IsSaveFile(void)
|
||||
{
|
||||
return cassette_savefile;
|
||||
}
|
||||
|
||||
/* put a byte into the cas file */
|
||||
/* the block is being written at first putbyte of the subsequent block */
|
||||
void CASSETTE_PutByte(int byte)
|
||||
{
|
||||
/* get time since last byte-put resp. motor on */
|
||||
cassette_putdelay = 1000*(cassette_elapsedtime-cassette_savetime)/312/50;
|
||||
/* subtract one byte-duration from put delay */
|
||||
cassette_putdelay -= 1000 * 10 * (POKEY_AUDF[POKEY_CHAN3] + POKEY_AUDF[POKEY_CHAN4]*0x100)/895000;
|
||||
/* if putdelay > 5 (ms) */
|
||||
if (cassette_putdelay > 05) {
|
||||
|
||||
/* write previous block */
|
||||
if (cassette_current_blockbyte > 0) {
|
||||
CASSETTE_Write(cassette_current_blockbyte);
|
||||
cassette_current_blockbyte = 0;
|
||||
cassette_gapdelay = 0;
|
||||
}
|
||||
/* set new gap-time */
|
||||
cassette_gapdelay += cassette_putdelay;
|
||||
}
|
||||
/* put byte into buffer */
|
||||
CASSETTE_buffer[cassette_current_blockbyte] = byte;
|
||||
cassette_current_blockbyte++;
|
||||
/* set new last byte-put time */
|
||||
cassette_savetime = cassette_elapsedtime;
|
||||
}
|
||||
|
||||
/* set motor status
|
||||
1 - on, 0 - off
|
||||
remark: the real evaluation is done in AddScanLine*/
|
||||
void CASSETTE_TapeMotor(int onoff)
|
||||
{
|
||||
if (cassette_file != NULL) {
|
||||
if (cassette_savefile) { /* cas save */
|
||||
if (onoff != cassette_motor) {
|
||||
if (onoff == 0) {
|
||||
/* get time since last byte-put resp. motor on */
|
||||
cassette_putdelay = 1000*(cassette_elapsedtime-cassette_savetime)/312/50;
|
||||
/* subtract one byte-duration from put delay */
|
||||
cassette_putdelay -= 1000*10 * (POKEY_AUDF[POKEY_CHAN3] + POKEY_AUDF[POKEY_CHAN4]*0x100)/895000;
|
||||
/* set putdelay non-negative */
|
||||
if (cassette_putdelay < 0) {
|
||||
cassette_putdelay = 0;
|
||||
}
|
||||
/* write block from buffer */
|
||||
if (cassette_current_blockbyte > 0) {
|
||||
CASSETTE_Write(cassette_current_blockbyte);
|
||||
cassette_gapdelay = 0;
|
||||
cassette_current_blockbyte = 0;
|
||||
}
|
||||
/* set new gap-time */
|
||||
cassette_gapdelay += cassette_putdelay;
|
||||
|
||||
}
|
||||
else {
|
||||
/* motor on if it was off - restart gap time */
|
||||
cassette_savetime = cassette_elapsedtime;
|
||||
}
|
||||
cassette_motor = onoff;
|
||||
}
|
||||
}
|
||||
else {
|
||||
cassette_motor = onoff;
|
||||
/* restart gap time */
|
||||
if (onoff == 1)
|
||||
cassette_savetime = cassette_elapsedtime;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void CASSETTE_AddScanLine(void)
|
||||
{
|
||||
int tmp;
|
||||
/* if motor on and a cassette file is opened, and not eof */
|
||||
/* increment elapsed cassette time */
|
||||
if (cassette_motor && (cassette_file != NULL)
|
||||
&& ((eof_of_tape == 0) || cassette_savefile)) {
|
||||
cassette_elapsedtime++;
|
||||
|
||||
/* only for loading: set next byte interrupt time */
|
||||
/* valid cassette times are up to 870 baud, giving
|
||||
a time span of 18 scanlines, so comparing with
|
||||
-2 leaves a safe timespan for letting get the bit out
|
||||
of the pokey */
|
||||
if (((cassette_nextirqevent - cassette_elapsedtime) <= -2)
|
||||
&& !cassette_savefile) {
|
||||
tmp = SetNextByteTime_POKEY(-2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#ifndef CASSETTE_H_
|
||||
#define CASSETTE_H_
|
||||
|
||||
#include <stdio.h> /* for FILE and FILENAME_MAX */
|
||||
|
||||
#include "atari.h" /* for UBYTE */
|
||||
|
||||
#define CASSETTE_DESCRIPTION_MAX 256
|
||||
|
||||
int CASSETTE_Initialise(int *argc, char *argv[]);
|
||||
|
||||
int CASSETTE_CheckFile(const char *filename, FILE **fp, char *description, int *last_block, int *isCAS);
|
||||
int CASSETTE_CreateFile(const char *filename, FILE **fp, int *isCAS);
|
||||
int CASSETTE_Insert(const char *filename);
|
||||
void CASSETTE_Remove(void);
|
||||
|
||||
extern int CASSETTE_hold_start;
|
||||
extern int CASSETTE_hold_start_on_reboot; /* preserve hold_start after reboot */
|
||||
extern int CASSETTE_press_space;
|
||||
|
||||
int CASSETTE_AddGap(int gaptime);
|
||||
void CASSETTE_LeaderLoad(void);
|
||||
void CASSETTE_LeaderSave(void);
|
||||
int CASSETTE_Read(void);
|
||||
int CASSETTE_Write(int length);
|
||||
int CASSETTE_IOLineStatus(void);
|
||||
int CASSETTE_GetByte(void);
|
||||
int CASSETTE_GetInputIRQDelay(void);
|
||||
int CASSETTE_IsSaveFile(void);
|
||||
void CASSETTE_PutByte(int byte);
|
||||
void CASSETTE_TapeMotor(int onoff);
|
||||
void CASSETTE_AddScanLine(void);
|
||||
extern UBYTE CASSETTE_buffer[4096];
|
||||
|
||||
#endif /* CASSETTE_H_ */
|
||||
@@ -1,405 +0,0 @@
|
||||
/*
|
||||
* cfg.c - Emulator Configuration
|
||||
*
|
||||
* Copyright (c) 1995-1998 David Firth
|
||||
* Copyright (c) 1998-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "atari.h"
|
||||
#include <stdlib.h>
|
||||
#include "cfg.h"
|
||||
#include "devices.h"
|
||||
#include "esc.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "pbi.h"
|
||||
#include "platform.h"
|
||||
#include "pokeysnd.h"
|
||||
#include "ui.h"
|
||||
#include "util.h"
|
||||
|
||||
char CFG_osa_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
char CFG_osb_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
char CFG_xlxe_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
char CFG_5200_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
char CFG_basic_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
|
||||
|
||||
void CFG_FindROMImages(const char *directory, int only_if_not_set)
|
||||
{
|
||||
static char * const rom_filenames[5] = {
|
||||
CFG_osa_filename,
|
||||
CFG_osb_filename,
|
||||
CFG_xlxe_filename,
|
||||
CFG_5200_filename,
|
||||
CFG_basic_filename
|
||||
};
|
||||
static const char * const common_filenames[] = {
|
||||
"atariosa.rom", "atari_osa.rom", "atari_os_a.rom",
|
||||
"ATARIOSA.ROM", "ATARI_OSA.ROM", "ATARI_OS_A.ROM",
|
||||
NULL,
|
||||
"atariosb.rom", "atari_osb.rom", "atari_os_b.rom",
|
||||
"ATARIOSB.ROM", "ATARI_OSB.ROM", "ATARI_OS_B.ROM",
|
||||
NULL,
|
||||
"atarixlxe.rom", "atarixl.rom", "atari_xlxe.rom", "atari_xl_xe.rom",
|
||||
"ATARIXLXE.ROM", "ATARIXL.ROM", "ATARI_XLXE.ROM", "ATARI_XL_XE.ROM",
|
||||
NULL,
|
||||
"atari5200.rom", "atar5200.rom", "5200.rom", "5200.bin", "atari_5200.rom",
|
||||
"ATARI5200.ROM", "ATAR5200.ROM", "5200.ROM", "5200.BIN", "ATARI_5200.ROM",
|
||||
NULL,
|
||||
"ataribasic.rom", "ataribas.rom", "basic.rom", "atari_basic.rom",
|
||||
"ATARIBASIC.ROM", "ATARIBAS.ROM", "BASIC.ROM", "ATARI_BASIC.ROM",
|
||||
NULL
|
||||
};
|
||||
const char * const *common_filename = common_filenames;
|
||||
int i;
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (!only_if_not_set || Util_filenamenotset(rom_filenames[i])) {
|
||||
do {
|
||||
char full_filename[FILENAME_MAX];
|
||||
Util_catpath(full_filename, directory, *common_filename);
|
||||
if (Util_fileexists(full_filename)) {
|
||||
strcpy(rom_filenames[i], full_filename);
|
||||
break;
|
||||
}
|
||||
} while (*++common_filename != NULL);
|
||||
}
|
||||
while (*common_filename++ != NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* If another default path config path is defined use it
|
||||
otherwise use the default one */
|
||||
#ifndef DEFAULT_CFG_NAME
|
||||
#define DEFAULT_CFG_NAME ".atari800.cfg"
|
||||
#endif
|
||||
|
||||
#ifndef SYSTEM_WIDE_CFG_FILE
|
||||
#define SYSTEM_WIDE_CFG_FILE "/etc/atari800.cfg"
|
||||
#endif
|
||||
|
||||
static char rtconfig_filename[FILENAME_MAX];
|
||||
|
||||
int CFG_LoadConfig(const char *alternate_config_filename)
|
||||
{
|
||||
FILE *fp;
|
||||
const char *fname = rtconfig_filename;
|
||||
char string[256];
|
||||
#ifndef BASIC
|
||||
int was_obsolete_dir = FALSE;
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORTS_PLATFORM_CONFIGINIT
|
||||
PLATFORM_ConfigInit();
|
||||
#endif
|
||||
|
||||
/* if alternate config filename is passed then use it */
|
||||
if (alternate_config_filename != NULL && *alternate_config_filename > 0) {
|
||||
Util_strlcpy(rtconfig_filename, alternate_config_filename, FILENAME_MAX);
|
||||
}
|
||||
/* else use the default config name under the HOME folder */
|
||||
else {
|
||||
char *home = getenv("HOME");
|
||||
if (home != NULL)
|
||||
Util_catpath(rtconfig_filename, home, DEFAULT_CFG_NAME);
|
||||
else
|
||||
strcpy(rtconfig_filename, DEFAULT_CFG_NAME);
|
||||
}
|
||||
|
||||
fp = fopen(fname, "r");
|
||||
if (fp == NULL) {
|
||||
Log_print("User config file '%s' not found.", rtconfig_filename);
|
||||
|
||||
#ifdef SYSTEM_WIDE_CFG_FILE
|
||||
/* try system wide config file */
|
||||
fname = SYSTEM_WIDE_CFG_FILE;
|
||||
Log_print("Trying system wide config file: %s", fname);
|
||||
fp = fopen(fname, "r");
|
||||
#endif
|
||||
if (fp == NULL) {
|
||||
Log_print("No configuration file found, will create fresh one from scratch:");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
fgets(string, sizeof(string), fp);
|
||||
|
||||
Log_print("Using Atari800 config file: %s\nCreated by %s", fname, string);
|
||||
|
||||
while (fgets(string, sizeof(string), fp)) {
|
||||
char *ptr;
|
||||
Util_chomp(string);
|
||||
ptr = strchr(string, '=');
|
||||
if (ptr != NULL) {
|
||||
*ptr++ = '\0';
|
||||
Util_trim(string);
|
||||
Util_trim(ptr);
|
||||
|
||||
if (strcmp(string, "OS/A_ROM") == 0)
|
||||
Util_strlcpy(CFG_osa_filename, ptr, sizeof(CFG_osa_filename));
|
||||
else if (strcmp(string, "OS/B_ROM") == 0)
|
||||
Util_strlcpy(CFG_osb_filename, ptr, sizeof(CFG_osb_filename));
|
||||
else if (strcmp(string, "XL/XE_ROM") == 0)
|
||||
Util_strlcpy(CFG_xlxe_filename, ptr, sizeof(CFG_xlxe_filename));
|
||||
else if (strcmp(string, "BASIC_ROM") == 0)
|
||||
Util_strlcpy(CFG_basic_filename, ptr, sizeof(CFG_basic_filename));
|
||||
else if (strcmp(string, "5200_ROM") == 0)
|
||||
Util_strlcpy(CFG_5200_filename, ptr, sizeof(CFG_5200_filename));
|
||||
#ifdef BASIC
|
||||
else if (strcmp(string, "ATARI_FILES_DIR") == 0
|
||||
|| strcmp(string, "SAVED_FILES_DIR") == 0
|
||||
|| strcmp(string, "DISK_DIR") == 0 || strcmp(string, "ROM_DIR") == 0
|
||||
|| strcmp(string, "EXE_DIR") == 0 || strcmp(string, "STATE_DIR") == 0)
|
||||
/* do nothing */;
|
||||
#else
|
||||
else if (strcmp(string, "ATARI_FILES_DIR") == 0) {
|
||||
if (UI_n_atari_files_dir >= UI_MAX_DIRECTORIES)
|
||||
Log_print("All ATARI_FILES_DIR slots used!");
|
||||
else
|
||||
Util_strlcpy(UI_atari_files_dir[UI_n_atari_files_dir++], ptr, FILENAME_MAX);
|
||||
}
|
||||
else if (strcmp(string, "SAVED_FILES_DIR") == 0) {
|
||||
if (UI_n_saved_files_dir >= UI_MAX_DIRECTORIES)
|
||||
Log_print("All SAVED_FILES_DIR slots used!");
|
||||
else
|
||||
Util_strlcpy(UI_saved_files_dir[UI_n_saved_files_dir++], ptr, FILENAME_MAX);
|
||||
}
|
||||
else if (strcmp(string, "DISK_DIR") == 0 || strcmp(string, "ROM_DIR") == 0
|
||||
|| strcmp(string, "EXE_DIR") == 0 || strcmp(string, "STATE_DIR") == 0) {
|
||||
/* ignore blank and "." values */
|
||||
if (ptr[0] != '\0' && (ptr[0] != '.' || ptr[1] != '\0'))
|
||||
was_obsolete_dir = TRUE;
|
||||
}
|
||||
#endif
|
||||
else if (strcmp(string, "H1_DIR") == 0)
|
||||
Util_strlcpy(Devices_atari_h_dir[0], ptr, FILENAME_MAX);
|
||||
else if (strcmp(string, "H2_DIR") == 0)
|
||||
Util_strlcpy(Devices_atari_h_dir[1], ptr, FILENAME_MAX);
|
||||
else if (strcmp(string, "H3_DIR") == 0)
|
||||
Util_strlcpy(Devices_atari_h_dir[2], ptr, FILENAME_MAX);
|
||||
else if (strcmp(string, "H4_DIR") == 0)
|
||||
Util_strlcpy(Devices_atari_h_dir[3], ptr, FILENAME_MAX);
|
||||
else if (strcmp(string, "HD_READ_ONLY") == 0)
|
||||
Devices_h_read_only = Util_sscandec(ptr);
|
||||
|
||||
else if (strcmp(string, "PRINT_COMMAND") == 0) {
|
||||
if (!Devices_SetPrintCommand(ptr))
|
||||
Log_print("Unsafe PRINT_COMMAND ignored");
|
||||
}
|
||||
|
||||
else if (strcmp(string, "SCREEN_REFRESH_RATIO") == 0)
|
||||
Atari800_refresh_rate = Util_sscandec(ptr);
|
||||
else if (strcmp(string, "DISABLE_BASIC") == 0)
|
||||
Atari800_disable_basic = Util_sscanbool(ptr);
|
||||
|
||||
else if (strcmp(string, "ENABLE_SIO_PATCH") == 0) {
|
||||
ESC_enable_sio_patch = Util_sscanbool(ptr);
|
||||
}
|
||||
else if (strcmp(string, "ENABLE_H_PATCH") == 0) {
|
||||
Devices_enable_h_patch = Util_sscanbool(ptr);
|
||||
}
|
||||
else if (strcmp(string, "ENABLE_P_PATCH") == 0) {
|
||||
Devices_enable_p_patch = Util_sscanbool(ptr);
|
||||
}
|
||||
else if (strcmp(string, "ENABLE_R_PATCH") == 0) {
|
||||
Devices_enable_r_patch = Util_sscanbool(ptr);
|
||||
}
|
||||
|
||||
else if (strcmp(string, "ENABLE_NEW_POKEY") == 0) {
|
||||
#ifdef SOUND
|
||||
POKEYSND_enable_new_pokey = Util_sscanbool(ptr);
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(string, "STEREO_POKEY") == 0) {
|
||||
#ifdef STEREO_SOUND
|
||||
POKEYSND_stereo_enabled = Util_sscanbool(ptr);
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(string, "SPEAKER_SOUND") == 0) {
|
||||
#ifdef CONSOLE_SOUND
|
||||
POKEYSND_console_sound_enabled = Util_sscanbool(ptr);
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(string, "SERIO_SOUND") == 0) {
|
||||
#ifdef SERIO_SOUND
|
||||
POKEYSND_serio_sound_enabled = Util_sscanbool(ptr);
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(string, "MACHINE_TYPE") == 0) {
|
||||
if (strcmp(ptr, "Atari OS/A") == 0)
|
||||
Atari800_machine_type = Atari800_MACHINE_OSA;
|
||||
else if (strcmp(ptr, "Atari OS/B") == 0)
|
||||
Atari800_machine_type = Atari800_MACHINE_OSB;
|
||||
else if (strcmp(ptr, "Atari XL/XE") == 0)
|
||||
Atari800_machine_type = Atari800_MACHINE_XLXE;
|
||||
else if (strcmp(ptr, "Atari 5200") == 0)
|
||||
Atari800_machine_type = Atari800_MACHINE_5200;
|
||||
else
|
||||
Log_print("Invalid machine type: %s", ptr);
|
||||
}
|
||||
else if (strcmp(string, "RAM_SIZE") == 0) {
|
||||
if (strcmp(ptr, "16") == 0)
|
||||
MEMORY_ram_size = 16;
|
||||
else if (strcmp(ptr, "48") == 0)
|
||||
MEMORY_ram_size = 48;
|
||||
else if (strcmp(ptr, "52") == 0)
|
||||
MEMORY_ram_size = 52;
|
||||
else if (strcmp(ptr, "64") == 0)
|
||||
MEMORY_ram_size = 64;
|
||||
else if (strcmp(ptr, "128") == 0)
|
||||
MEMORY_ram_size = 128;
|
||||
else if (strcmp(ptr, "192") == 0)
|
||||
MEMORY_ram_size = 192;
|
||||
else if (strcmp(ptr, "320 (RAMBO)") == 0)
|
||||
MEMORY_ram_size = MEMORY_RAM_320_RAMBO;
|
||||
else if (strcmp(ptr, "320 (COMPY SHOP)") == 0)
|
||||
MEMORY_ram_size = MEMORY_RAM_320_COMPY_SHOP;
|
||||
else if (strcmp(ptr, "576") == 0)
|
||||
MEMORY_ram_size = 576;
|
||||
else if (strcmp(ptr, "1088") == 0)
|
||||
MEMORY_ram_size = 1088;
|
||||
else
|
||||
Log_print("Invalid RAM size: %s", ptr);
|
||||
}
|
||||
else if (strcmp(string, "DEFAULT_TV_MODE") == 0) {
|
||||
if (strcmp(ptr, "PAL") == 0)
|
||||
Atari800_tv_mode = Atari800_TV_PAL;
|
||||
else if (strcmp(ptr, "NTSC") == 0)
|
||||
Atari800_tv_mode = Atari800_TV_NTSC;
|
||||
else
|
||||
Log_print("Invalid TV Mode: %s", ptr);
|
||||
}
|
||||
/* Add module-specific configurations here */
|
||||
else if (PBI_ReadConfig(string,ptr)) {
|
||||
}
|
||||
else {
|
||||
#ifdef SUPPORTS_PLATFORM_CONFIGURE
|
||||
if (!PLATFORM_Configure(string, ptr)) {
|
||||
Log_print("Unrecognized variable or bad parameters: '%s=%s'", string, ptr);
|
||||
}
|
||||
#else
|
||||
Log_print("Unrecognized variable: %s", string);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log_print("Ignored config line: %s", string);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
#ifndef BASIC
|
||||
if (was_obsolete_dir) {
|
||||
Log_print(
|
||||
"DISK_DIR, ROM_DIR, EXE_DIR and STATE_DIR configuration options\n"
|
||||
"are no longer supported. Please use ATARI_FILES_DIR\n"
|
||||
"and SAVED_FILES_DIR in your Atari800 configuration file.");
|
||||
}
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int CFG_WriteConfig(void)
|
||||
{
|
||||
FILE *fp;
|
||||
int i;
|
||||
static const char * const machine_type_string[4] = {
|
||||
"OS/A", "OS/B", "XL/XE", "5200"
|
||||
};
|
||||
|
||||
fp = fopen(rtconfig_filename, "w");
|
||||
if (fp == NULL) {
|
||||
perror(rtconfig_filename);
|
||||
Log_print("Cannot write to config file: %s", rtconfig_filename);
|
||||
return FALSE;
|
||||
}
|
||||
Log_print("Writing config file: %s", rtconfig_filename);
|
||||
|
||||
fprintf(fp, "%s\n", Atari800_TITLE);
|
||||
fprintf(fp, "OS/A_ROM=%s\n", CFG_osa_filename);
|
||||
fprintf(fp, "OS/B_ROM=%s\n", CFG_osb_filename);
|
||||
fprintf(fp, "XL/XE_ROM=%s\n", CFG_xlxe_filename);
|
||||
fprintf(fp, "BASIC_ROM=%s\n", CFG_basic_filename);
|
||||
fprintf(fp, "5200_ROM=%s\n", CFG_5200_filename);
|
||||
#ifndef BASIC
|
||||
for (i = 0; i < UI_n_atari_files_dir; i++)
|
||||
fprintf(fp, "ATARI_FILES_DIR=%s\n", UI_atari_files_dir[i]);
|
||||
for (i = 0; i < UI_n_saved_files_dir; i++)
|
||||
fprintf(fp, "SAVED_FILES_DIR=%s\n", UI_saved_files_dir[i]);
|
||||
#endif
|
||||
for (i = 0; i < 4; i++)
|
||||
fprintf(fp, "H%c_DIR=%s\n", '1' + i, Devices_atari_h_dir[i]);
|
||||
fprintf(fp, "HD_READ_ONLY=%d\n", Devices_h_read_only);
|
||||
|
||||
#ifdef HAVE_SYSTEM
|
||||
fprintf(fp, "PRINT_COMMAND=%s\n", Devices_print_command);
|
||||
#endif
|
||||
|
||||
#ifndef BASIC
|
||||
fprintf(fp, "SCREEN_REFRESH_RATIO=%d\n", Atari800_refresh_rate);
|
||||
#endif
|
||||
|
||||
fprintf(fp, "MACHINE_TYPE=Atari %s\n", machine_type_string[Atari800_machine_type]);
|
||||
|
||||
fprintf(fp, "RAM_SIZE=");
|
||||
switch (MEMORY_ram_size) {
|
||||
case MEMORY_RAM_320_RAMBO:
|
||||
fprintf(fp, "320 (RAMBO)\n");
|
||||
break;
|
||||
case MEMORY_RAM_320_COMPY_SHOP:
|
||||
fprintf(fp, "320 (COMPY SHOP)\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(fp, "%d\n", MEMORY_ram_size);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(fp, (Atari800_tv_mode == Atari800_TV_PAL) ? "DEFAULT_TV_MODE=PAL\n" : "DEFAULT_TV_MODE=NTSC\n");
|
||||
|
||||
fprintf(fp, "DISABLE_BASIC=%d\n", Atari800_disable_basic);
|
||||
fprintf(fp, "ENABLE_SIO_PATCH=%d\n", ESC_enable_sio_patch);
|
||||
fprintf(fp, "ENABLE_H_PATCH=%d\n", Devices_enable_h_patch);
|
||||
fprintf(fp, "ENABLE_P_PATCH=%d\n", Devices_enable_p_patch);
|
||||
#ifdef R_IO_DEVICE
|
||||
fprintf(fp, "ENABLE_R_PATCH=%d\n", Devices_enable_r_patch);
|
||||
#endif
|
||||
|
||||
#ifdef SOUND
|
||||
fprintf(fp, "ENABLE_NEW_POKEY=%d\n", POKEYSND_enable_new_pokey);
|
||||
#ifdef STEREO_SOUND
|
||||
fprintf(fp, "STEREO_POKEY=%d\n", POKEYSND_stereo_enabled);
|
||||
#endif
|
||||
#ifdef CONSOLE_SOUND
|
||||
fprintf(fp, "SPEAKER_SOUND=%d\n", POKEYSND_console_sound_enabled);
|
||||
#endif
|
||||
#ifdef SERIO_SOUND
|
||||
fprintf(fp, "SERIO_SOUND=%d\n", POKEYSND_serio_sound_enabled);
|
||||
#endif
|
||||
#endif /* SOUND */
|
||||
/* Add module-specific configurations here */
|
||||
PBI_WriteConfig(fp);
|
||||
|
||||
#ifdef SUPPORTS_PLATFORM_CONFIGSAVE
|
||||
PLATFORM_ConfigSave(fp);
|
||||
#endif
|
||||
|
||||
fclose(fp);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef CFG_H_
|
||||
#define CFG_H_
|
||||
/* Checks for "popular" filenames of ROM images in the specified directory
|
||||
and sets CFG_*_filename to the ones found.
|
||||
If only_if_not_set is TRUE, then CFG_*_filename is modified only when
|
||||
Util_filenamenotset() is TRUE for it. */
|
||||
void CFG_FindROMImages(const char *directory, int only_if_not_set);
|
||||
|
||||
/* Load Atari800 text configuration file. */
|
||||
int CFG_LoadConfig(const char *alternate_config_filename);
|
||||
|
||||
/* Writes Atari800 text configuration file. */
|
||||
int CFG_WriteConfig(void);
|
||||
|
||||
/* Paths to ROM images. */
|
||||
extern char CFG_osa_filename[FILENAME_MAX];
|
||||
extern char CFG_osb_filename[FILENAME_MAX];
|
||||
extern char CFG_xlxe_filename[FILENAME_MAX];
|
||||
extern char CFG_5200_filename[FILENAME_MAX];
|
||||
extern char CFG_basic_filename[FILENAME_MAX];
|
||||
|
||||
#endif /* CFG_H_ */
|
||||
@@ -1,443 +0,0 @@
|
||||
/*
|
||||
* colours.c - Atari colour palette
|
||||
*
|
||||
* Copyright (C) 1995-1998 David Firth
|
||||
* Copyright (C) 1998-2009 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h> /* for strcmp() */
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include "atari.h"
|
||||
#include "colours.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "platform.h"
|
||||
#ifdef __PLUS
|
||||
#include "display_win.h"
|
||||
#include "misc_win.h"
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
#define PALETTE_R(x,c) ((UBYTE) (c[x] >> 16))
|
||||
#define PALETTE_G(x,c) ((UBYTE) (c[x] >> 8))
|
||||
#define PALETTE_B(x,c) ((UBYTE) c[x])
|
||||
#define PALETTE_Y(x,c) (0.30 * PALETTE_R(x,c) + 0.59 * PALETTE_G(x,c) + 0.11 * PALETTE_B(x,c))
|
||||
|
||||
int *Colours_table;
|
||||
|
||||
static int colortable_ntsc[256] = {
|
||||
0x000000, 0x101010, 0x1f1f1f, 0x2f2f2f,
|
||||
0x3e3e3e, 0x4e4e4e, 0x5e5e5e, 0x6e6e6e,
|
||||
0x797979, 0x8a8a8a, 0x9c9c9c, 0xadadad,
|
||||
0xbfbfbf, 0xd2d2d2, 0xe6e6e6, 0xfcfcfc,
|
||||
0x110900, 0x241d00, 0x342c00, 0x433c00,
|
||||
0x514a00, 0x615a00, 0x716a00, 0x817a00,
|
||||
0x8c850c, 0x9c951f, 0xaea734, 0xbfb847,
|
||||
0xd0c95b, 0xe3dc71, 0xf6f087, 0xffffa1,
|
||||
0x2a0000, 0x3d0b00, 0x4c1b00, 0x5b2b00,
|
||||
0x693a00, 0x794a00, 0x885a04, 0x976a16,
|
||||
0xa27522, 0xb28634, 0xc39848, 0xd4aa5c,
|
||||
0xe4bb6f, 0xf7cf84, 0xffe29a, 0xfff9b3,
|
||||
0x360000, 0x490100, 0x581100, 0x672100,
|
||||
0x752f00, 0x844008, 0x93501a, 0xa2602b,
|
||||
0xad6c37, 0xbd7d49, 0xcd8f5c, 0xdea16f,
|
||||
0xeeb282, 0xffc697, 0xffdaac, 0xfff1c4,
|
||||
0x420000, 0x540000, 0x630204, 0x721214,
|
||||
0x802123, 0x8f3233, 0x9e4244, 0xad5354,
|
||||
0xb75e60, 0xc77071, 0xd88284, 0xe89496,
|
||||
0xf8a6a7, 0xffbabb, 0xffced0, 0xffe5e7,
|
||||
0x3e002a, 0x51003e, 0x60004d, 0x6f065c,
|
||||
0x7d156a, 0x8c2679, 0x9b3789, 0xaa4798,
|
||||
0xb453a3, 0xc464b3, 0xd577c4, 0xe589d4,
|
||||
0xf59ce5, 0xffb0f7, 0xffc4ff, 0xffdcff,
|
||||
0x0f0077, 0x220089, 0x320097, 0x410fa5,
|
||||
0x501eb2, 0x5f2ec1, 0x6f3fcf, 0x7f50dd,
|
||||
0x8a5be7, 0x9a6df5, 0xac7fff, 0xbd91ff,
|
||||
0xcea3ff, 0xe1b7ff, 0xf4ccff, 0xffe3ff,
|
||||
0x000076, 0x000288, 0x0c1297, 0x1c22a5,
|
||||
0x2b31b2, 0x3b41c0, 0x4c51ce, 0x5c61dc,
|
||||
0x686de6, 0x797ef5, 0x8b90ff, 0x9da2ff,
|
||||
0xafb3ff, 0xc2c7ff, 0xd6dbff, 0xedf2ff,
|
||||
0x000065, 0x001077, 0x002086, 0x082f94,
|
||||
0x173ea1, 0x284eb0, 0x395ebe, 0x496ecc,
|
||||
0x5579d7, 0x668ae6, 0x799cf6, 0x8baeff,
|
||||
0x9ebfff, 0xb2d2ff, 0xc6e6ff, 0xddfcff,
|
||||
0x00074f, 0x001b62, 0x002a71, 0x003a7f,
|
||||
0x0b488d, 0x1b589c, 0x2c68ab, 0x3d78b9,
|
||||
0x4983c4, 0x5b94d3, 0x6ea5e3, 0x80b7f3,
|
||||
0x93c8ff, 0xa7dbff, 0xbceeff, 0xd3ffff,
|
||||
0x000f3b, 0x00234e, 0x00325d, 0x00426c,
|
||||
0x035079, 0x146089, 0x257098, 0x367fa7,
|
||||
0x428ab1, 0x539bc1, 0x67acd2, 0x79bee2,
|
||||
0x8ccff2, 0xa0e1ff, 0xb5f5ff, 0xcdffff,
|
||||
0x001a17, 0x002d2b, 0x003d3a, 0x004c49,
|
||||
0x005a58, 0x0c6a67, 0x1e7a77, 0x2f8987,
|
||||
0x3b9492, 0x4da4a2, 0x60b6b3, 0x73c7c4,
|
||||
0x86d7d5, 0x9aeae8, 0xb0fdfb, 0xc8ffff,
|
||||
0x002500, 0x003800, 0x004803, 0x005713,
|
||||
0x006522, 0x0d7432, 0x1e8443, 0x2f9353,
|
||||
0x3b9e5f, 0x4dae70, 0x60bf83, 0x73d095,
|
||||
0x86e0a7, 0x9bf3bb, 0xb0ffcf, 0xc8ffe6,
|
||||
0x001e00, 0x003100, 0x0c4100, 0x1c5000,
|
||||
0x2a5e00, 0x3b6e00, 0x4b7d00, 0x5b8d00,
|
||||
0x67970c, 0x78a81f, 0x8ab933, 0x9cca47,
|
||||
0xaedb5b, 0xc2ed71, 0xd6ff87, 0xedffa0,
|
||||
0x001300, 0x132600, 0x233600, 0x324500,
|
||||
0x415400, 0x516300, 0x617300, 0x718300,
|
||||
0x7c8e08, 0x8d9e1b, 0x9fb02f, 0xb0c143,
|
||||
0xc1d257, 0xd5e46d, 0xe8f883, 0xfeff9d,
|
||||
0x1e0000, 0x311400, 0x412400, 0x503300,
|
||||
0x5e4200, 0x6e5200, 0x7d6200, 0x8d7209,
|
||||
0x977d15, 0xa88e28, 0xb9a03c, 0xcab150,
|
||||
0xdbc263, 0xedd679, 0xffe98f, 0xffffa8
|
||||
};
|
||||
|
||||
static int colortable_pal[256] = {
|
||||
0x2d2d2d, 0x3b3b3b, 0x494949, 0x575757,
|
||||
0x656565, 0x737373, 0x818181, 0x8f8f8f,
|
||||
0x9d9d9d, 0xababab, 0xb9b9b9, 0xc7c7c7,
|
||||
0xd5d5d5, 0xe3e3e3, 0xf1f1f1, 0xffffff,
|
||||
0x5c2300, 0x6a3100, 0x783f00, 0x864d0a,
|
||||
0x945b18, 0xa26926, 0xb07734, 0xbe8542,
|
||||
0xcc9350, 0xdaa15e, 0xe8af6c, 0xf6bd7a,
|
||||
0xffcb88, 0xffd996, 0xffe7a4, 0xfff5b2,
|
||||
0x691409, 0x772217, 0x853025, 0x933e33,
|
||||
0xa14c41, 0xaf5a4f, 0xbd685d, 0xcb766b,
|
||||
0xd98479, 0xe79287, 0xf5a095, 0xffaea3,
|
||||
0xffbcb1, 0xffcabf, 0xffd8cd, 0xffe6db,
|
||||
0x6c0a38, 0x7a1846, 0x882654, 0x963462,
|
||||
0xa44270, 0xb2507e, 0xc05e8c, 0xce6c9a,
|
||||
0xdc7aa8, 0xea88b6, 0xf896c4, 0xffa4d2,
|
||||
0xffb2e0, 0xffc0ee, 0xffcefc, 0xffdcff,
|
||||
0x640565, 0x721373, 0x802181, 0x8e2f8f,
|
||||
0x9c3d9d, 0xaa4bab, 0xb859b9, 0xc667c7,
|
||||
0xd475d5, 0xe283e3, 0xf091f1, 0xfe9fff,
|
||||
0xffadff, 0xffbbff, 0xffc9ff, 0xffd7ff,
|
||||
0x520789, 0x601597, 0x6e23a5, 0x7c31b3,
|
||||
0x8a3fc1, 0x984dcf, 0xa65bdd, 0xb469eb,
|
||||
0xc277f9, 0xd085ff, 0xde93ff, 0xeca1ff,
|
||||
0xfaafff, 0xffbdff, 0xffcbff, 0xffd9ff,
|
||||
0x3a109c, 0x481eaa, 0x562cb8, 0x643ac6,
|
||||
0x7248d4, 0x8056e2, 0x8e64f0, 0x9c72fe,
|
||||
0xaa80ff, 0xb88eff, 0xc69cff, 0xd4aaff,
|
||||
0xe2b8ff, 0xf0c6ff, 0xfed4ff, 0xffe2ff,
|
||||
0x1f1e9c, 0x2d2caa, 0x3b3ab8, 0x4948c6,
|
||||
0x5756d4, 0x6564e2, 0x7372f0, 0x8180fe,
|
||||
0x8f8eff, 0x9d9cff, 0xabaaff, 0xb9b8ff,
|
||||
0xc7c6ff, 0xd5d4ff, 0xe3e2ff, 0xf1f0ff,
|
||||
0x072e89, 0x153c97, 0x234aa5, 0x3158b3,
|
||||
0x3f66c1, 0x4d74cf, 0x5b82dd, 0x6990eb,
|
||||
0x779ef9, 0x85acff, 0x93baff, 0xa1c8ff,
|
||||
0xafd6ff, 0xbde4ff, 0xcbf2ff, 0xd9ffff,
|
||||
0x003e65, 0x034c73, 0x115a81, 0x1f688f,
|
||||
0x2d769d, 0x3b84ab, 0x4992b9, 0x57a0c7,
|
||||
0x65aed5, 0x73bce3, 0x81caf1, 0x8fd8ff,
|
||||
0x9de6ff, 0xabf4ff, 0xb9ffff, 0xc7ffff,
|
||||
0x004b38, 0x005946, 0x096754, 0x177562,
|
||||
0x258370, 0x33917e, 0x419f8c, 0x4fad9a,
|
||||
0x5dbba8, 0x6bc9b6, 0x79d7c4, 0x87e5d2,
|
||||
0x95f3e0, 0xa3ffee, 0xb1fffc, 0xbfffff,
|
||||
0x005209, 0x006017, 0x0c6e25, 0x1a7c33,
|
||||
0x288a41, 0x36984f, 0x44a65d, 0x52b46b,
|
||||
0x60c279, 0x6ed087, 0x7cde95, 0x8aeca3,
|
||||
0x98fab1, 0xa6ffbf, 0xb4ffcd, 0xc2ffdb,
|
||||
0x005300, 0x0b6100, 0x196f00, 0x277d0a,
|
||||
0x358b18, 0x439926, 0x51a734, 0x5fb542,
|
||||
0x6dc350, 0x7bd15e, 0x89df6c, 0x97ed7a,
|
||||
0xa5fb88, 0xb3ff96, 0xc1ffa4, 0xcfffb2,
|
||||
0x134e00, 0x215c00, 0x2f6a00, 0x3d7800,
|
||||
0x4b8600, 0x59940b, 0x67a219, 0x75b027,
|
||||
0x83be35, 0x91cc43, 0x9fda51, 0xade85f,
|
||||
0xbbf66d, 0xc9ff7b, 0xd7ff89, 0xe5ff97,
|
||||
0x2d4300, 0x3b5100, 0x495f00, 0x576d00,
|
||||
0x657b00, 0x738901, 0x81970f, 0x8fa51d,
|
||||
0x9db32b, 0xabc139, 0xb9cf47, 0xc7dd55,
|
||||
0xd5eb63, 0xe3f971, 0xf1ff7f, 0xffff8d,
|
||||
0x463300, 0x544100, 0x624f00, 0x705d00,
|
||||
0x7e6b00, 0x8c790b, 0x9a8719, 0xa89527,
|
||||
0xb6a335, 0xc4b143, 0xd2bf51, 0xe0cd5f,
|
||||
0xeedb6d, 0xfce97b, 0xfff789, 0xffff97
|
||||
};
|
||||
|
||||
void Colours_SetRGB(int i, int r, int g, int b, int *colortable_ptr)
|
||||
{
|
||||
if (r < 0)
|
||||
r = 0;
|
||||
else if (r > 255)
|
||||
r = 255;
|
||||
if (g < 0)
|
||||
g = 0;
|
||||
else if (g > 255)
|
||||
g = 255;
|
||||
if (b < 0)
|
||||
b = 0;
|
||||
else if (b > 255)
|
||||
b = 255;
|
||||
colortable_ptr[i] = (r << 16) + (g << 8) + b;
|
||||
}
|
||||
|
||||
int Colours_Read(const char *filename, int *colortable_ptr)
|
||||
{
|
||||
FILE *fp;
|
||||
int i;
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == NULL)
|
||||
return FALSE;
|
||||
for (i = 0; i < 256; i++) {
|
||||
int j;
|
||||
colortable_ptr[i] = 0;
|
||||
for (j = 16; j >= 0; j -= 8) {
|
||||
int c = fgetc(fp);
|
||||
if (c == EOF) {
|
||||
fclose(fp);
|
||||
return FALSE;
|
||||
}
|
||||
colortable_ptr[i] |= c << j;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void Colours_Generate(int black, int white, int colshift, int *colortable_ptr)
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
for (i = 0; i < 16; i++) {
|
||||
double angle;
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
if (i == 0) {
|
||||
r = g = b = 0;
|
||||
}
|
||||
else {
|
||||
angle = M_PI * (i / 7.0 - colshift * 0.01);
|
||||
r = (int) (0.08 / 0.30 * cos(angle) * (white - black));
|
||||
g = (int) (0.08 / 0.59 * cos(angle + M_PI * 2 / 3) * (white - black));
|
||||
b = (int) (0.08 / 0.11 * cos(angle + M_PI * 4 / 3) * (white - black));
|
||||
}
|
||||
for (j = 0; j < 16; j++) {
|
||||
int y;
|
||||
y = black + white * j / 15;
|
||||
Colours_SetRGB(i * 16 + j, y + r, y + g, y + b, colortable_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Colours_Adjust(int black, int white, int colintens, int *colortable_ptr)
|
||||
{
|
||||
double black_in;
|
||||
double white_in;
|
||||
double brightfix;
|
||||
double colorfix;
|
||||
int i;
|
||||
black_in = PALETTE_Y(0, colortable_ptr);
|
||||
white_in = PALETTE_Y(15, colortable_ptr);
|
||||
brightfix = (white - black) / (white_in - black_in);
|
||||
colorfix = brightfix * colintens / 100;
|
||||
for (i = 0; i < 256; i++) {
|
||||
double y;
|
||||
double r;
|
||||
double g;
|
||||
double b;
|
||||
y = PALETTE_Y(i, colortable_ptr);
|
||||
r = PALETTE_R(i, colortable_ptr) - y;
|
||||
g = PALETTE_G(i, colortable_ptr) - y;
|
||||
b = PALETTE_B(i, colortable_ptr) - y;
|
||||
y = (y - black_in) * brightfix + black;
|
||||
r = y + r * colorfix;
|
||||
g = y + g * colorfix;
|
||||
b = y + b * colorfix;
|
||||
Colours_SetRGB(i, (int) r, (int) g, (int) b, colortable_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Colours_SetVideoSystem(int mode) {
|
||||
if (mode == Atari800_TV_NTSC) {
|
||||
Colours_table = colortable_ntsc;
|
||||
}
|
||||
else if (mode == Atari800_TV_PAL) {
|
||||
Colours_table = colortable_pal;
|
||||
}
|
||||
else {
|
||||
Atari800_Exit(FALSE);
|
||||
Log_print("Interal error: Invalid Atari800_tv_mode\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Colours_InitialiseMachine(void)
|
||||
{
|
||||
static int saved_tv_mode = Atari800_TV_UNSET;
|
||||
if (saved_tv_mode == Atari800_TV_UNSET) {
|
||||
/* Colours_SetVideoSystem was already called in initialisation*/
|
||||
saved_tv_mode = Atari800_tv_mode;
|
||||
}
|
||||
else if (saved_tv_mode != Atari800_tv_mode) {
|
||||
/* Atari800_tv_mode has changed */
|
||||
saved_tv_mode = Atari800_tv_mode;
|
||||
Colours_SetVideoSystem(Atari800_tv_mode);
|
||||
#if SUPPORTS_PLATFORM_PALETTEUPDATE
|
||||
PLATFORM_PaletteUpdate();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int Colours_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
#ifndef __PLUS
|
||||
/* NTSC */
|
||||
int black_ntsc = 0;
|
||||
int white_ntsc = 255;
|
||||
int colintens_ntsc = 100;
|
||||
int colshift_ntsc = 30;
|
||||
/* PAL */
|
||||
int black_pal = 0;
|
||||
int white_pal = 255;
|
||||
int colintens_pal = 100;
|
||||
int colshift_pal = 30;
|
||||
#else /* __PLUS */
|
||||
/*XXX FIXME: add pal/ntsc*/
|
||||
int black = g_Screen.Pal.nBlackLevel;
|
||||
int white = g_Screen.Pal.nWhiteLevel;
|
||||
int colintens = g_Screen.Pal.nSaturation;
|
||||
int colshift = g_Screen.Pal.nColorShift;
|
||||
#endif /* __PLUS */
|
||||
int generate_ntsc = FALSE;
|
||||
int generate_pal = FALSE;
|
||||
int adjust_ntsc = FALSE;
|
||||
int adjust_pal = FALSE;
|
||||
|
||||
for (i = j = 1; i < *argc; i++) {
|
||||
int i_a = (i + 1 < *argc); /* is argument available? */
|
||||
int a_m = FALSE; /* error, argument missing! */
|
||||
|
||||
if (strcmp(argv[i], "-blackn") == 0) {
|
||||
if (i_a) {
|
||||
black_ntsc = Util_sscandec(argv[++i]);
|
||||
adjust_ntsc = TRUE;
|
||||
}
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-blackp") == 0) {
|
||||
if (i_a) {
|
||||
black_pal = Util_sscandec(argv[++i]);
|
||||
adjust_pal = TRUE;
|
||||
}
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-whiten") == 0) {
|
||||
if (i_a) {
|
||||
white_ntsc = Util_sscandec(argv[++i]);
|
||||
adjust_ntsc = TRUE;
|
||||
}
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-whitep") == 0) {
|
||||
if (i_a) {
|
||||
white_pal = Util_sscandec(argv[++i]);
|
||||
adjust_pal = TRUE;
|
||||
}
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-colorsn") == 0) {
|
||||
if (i_a) {
|
||||
colintens_ntsc = Util_sscandec(argv[++i]);
|
||||
adjust_ntsc = TRUE;
|
||||
}
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-colorsp") == 0) {
|
||||
if (i_a) {
|
||||
colintens_pal = Util_sscandec(argv[++i]);
|
||||
adjust_pal = TRUE;
|
||||
}
|
||||
else a_m = TRUE;
|
||||
}
|
||||
else if (strcmp(argv[i], "-colshiftn") == 0)
|
||||
if (i_a)
|
||||
colshift_ntsc = Util_sscandec(argv[++i]);
|
||||
else a_m = TRUE;
|
||||
else if (strcmp(argv[i], "-colshiftp") == 0)
|
||||
if (i_a)
|
||||
colshift_pal = Util_sscandec(argv[++i]);
|
||||
else a_m = TRUE;
|
||||
else if (strcmp(argv[i], "-genpaln") == 0)
|
||||
generate_ntsc = TRUE;
|
||||
else if (strcmp(argv[i], "-genpalp") == 0)
|
||||
generate_pal = TRUE;
|
||||
else if (strcmp(argv[i], "-paletten") == 0)
|
||||
if (i_a)
|
||||
Colours_Read(argv[++i], colortable_ntsc);
|
||||
else a_m = TRUE;
|
||||
else if (strcmp(argv[i], "-palettep") == 0)
|
||||
if (i_a)
|
||||
Colours_Read(argv[++i], colortable_pal);
|
||||
else a_m = TRUE;
|
||||
else {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
Log_print("\t-paletten <file> Use external NTSC palette");
|
||||
Log_print("\t-palettep <file> Use external PAL palette");
|
||||
Log_print("\t-blackn <0-255> Set NTSC palette black level");
|
||||
Log_print("\t-blackp <0-255> Set PAL palette black level");
|
||||
Log_print("\t-whiten <0-255> Set NTSC palette white level");
|
||||
Log_print("\t-whitep <0-255> Set PAL palette white level");
|
||||
Log_print("\t-colorsn <num> Set NTSC palette colors saturation");
|
||||
Log_print("\t-colorsp <num> Set PAL palette colors saturation");
|
||||
Log_print("\t-genpaln Generate artificial NTSC palette");
|
||||
Log_print("\t-genpalp Generate artificial PAL palette");
|
||||
Log_print("\t-colshiftn <num> Set NTSC palette color shift (-genpaln only)");
|
||||
Log_print("\t-colshiftp <num> Set PAL palette color shift (-genpalp only)");
|
||||
}
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
|
||||
if (a_m) {
|
||||
Log_print("Missing argument for '%s'", argv[i]);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
*argc = j;
|
||||
|
||||
if (generate_ntsc) {
|
||||
Colours_Generate(black_ntsc, white_ntsc, colshift_ntsc, colortable_ntsc);
|
||||
}
|
||||
if (generate_pal) {
|
||||
Colours_Generate(black_pal, white_pal, colshift_pal, colortable_pal);
|
||||
}
|
||||
if (adjust_ntsc) {
|
||||
Colours_Adjust(black_ntsc, white_ntsc, colintens_ntsc, colortable_ntsc);
|
||||
}
|
||||
if (adjust_pal) {
|
||||
Colours_Adjust(black_pal, white_pal, colintens_pal, colortable_pal);
|
||||
}
|
||||
Colours_SetVideoSystem(Atari800_tv_mode); /* Atari800_tv_mode is set before calling Colours_Initialise */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef COLOURS_H_
|
||||
#define COLOURS_H_
|
||||
|
||||
extern int *Colours_table;
|
||||
|
||||
#define Colours_GetR(x) ((UBYTE) (Colours_table[x] >> 16))
|
||||
#define Colours_GetG(x) ((UBYTE) (Colours_table[x] >> 8))
|
||||
#define Colours_GetB(x) ((UBYTE) Colours_table[x])
|
||||
#define Colours_GetY(x) (0.30 * Colours_GetR(x) + 0.59 * Colours_GetG(x) + 0.11 * Colours_GetB(x))
|
||||
void Colours_SetRGB(int i, int r, int g, int b, int *colortable_ptr);
|
||||
|
||||
int Colours_Read(const char *filename, int *colortable_ptr);
|
||||
void Colours_Generate(int black, int white, int colshift, int *colortable_ptr);
|
||||
void Colours_Adjust(int black, int white, int colintens, int *colortable_ptr);
|
||||
void Colours_SetVideoSystem(int mode);
|
||||
void Colours_InitialiseMachine(void);
|
||||
int Colours_Initialise(int *argc, char *argv[]);
|
||||
|
||||
#endif /* COLOURS_H_ */
|
||||
@@ -1,311 +0,0 @@
|
||||
/*
|
||||
* compfile.c - File I/O and ZLIB compression
|
||||
*
|
||||
* Copyright (C) 1995-1998 David Firth
|
||||
* Copyright (C) 1998-2006 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_LIBZ
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#include "afile.h"
|
||||
#include "atari.h"
|
||||
#include "compfile.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
/* GZ decompression ------------------------------------------------------ */
|
||||
|
||||
/* Opens a GZIP compressed file and decompresses its contents to outfp.
|
||||
Returns TRUE on success. */
|
||||
int CompFile_ExtractGZ(const char *infilename, FILE *outfp)
|
||||
{
|
||||
#ifndef HAVE_LIBZ
|
||||
Log_print("This executable cannot decompress ZLIB files");
|
||||
return FALSE;
|
||||
#else
|
||||
/* TODO: replace gz* with low-level light-weight ZLIB functions. */
|
||||
gzFile gzf = gzopen(infilename, "rb");
|
||||
void *buf;
|
||||
int result;
|
||||
if (gzf == NULL) {
|
||||
Log_print("ZLIB could not open file %s", infilename);
|
||||
return FALSE;
|
||||
}
|
||||
#define UNCOMPRESS_BUFFER_SIZE 32768
|
||||
buf = Util_malloc(UNCOMPRESS_BUFFER_SIZE);
|
||||
do {
|
||||
result = gzread(gzf, buf, UNCOMPRESS_BUFFER_SIZE);
|
||||
if (result > 0) {
|
||||
if ((int) fwrite(buf, 1, result, outfp) != result)
|
||||
result = -1;
|
||||
}
|
||||
} while (result == UNCOMPRESS_BUFFER_SIZE);
|
||||
free(buf);
|
||||
gzclose(gzf);
|
||||
return result >= 0;
|
||||
#endif /* HAVE_LIBZ */
|
||||
}
|
||||
|
||||
|
||||
/* DCM decompression ----------------------------------------------------- */
|
||||
|
||||
static int fgetw(FILE *fp)
|
||||
{
|
||||
int low;
|
||||
int high;
|
||||
low = fgetc(fp);
|
||||
if (low == EOF)
|
||||
return -1;
|
||||
high = fgetc(fp);
|
||||
if (high == EOF)
|
||||
return -1;
|
||||
return low + (high << 8);
|
||||
}
|
||||
|
||||
static int fload(void *buf, int size, FILE *fp)
|
||||
{
|
||||
return (int) fread(buf, 1, size, fp) == size;
|
||||
}
|
||||
|
||||
static int fsave(void *buf, int size, FILE *fp)
|
||||
{
|
||||
return (int) fwrite(buf, 1, size, fp) == size;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
FILE *fp;
|
||||
int sectorcount;
|
||||
int sectorsize;
|
||||
int current_sector;
|
||||
} ATR_Info;
|
||||
|
||||
static int write_atr_header(const ATR_Info *pai)
|
||||
{
|
||||
int sectorcount;
|
||||
int sectorsize;
|
||||
ULONG paras;
|
||||
struct AFILE_ATR_Header header;
|
||||
sectorcount = pai->sectorcount;
|
||||
sectorsize = pai->sectorsize;
|
||||
paras = (sectorsize != 256 || sectorcount <= 3)
|
||||
? (sectorcount << 3) /* single density or only boot sectors: sectorcount * 128 / 16 */
|
||||
: (sectorcount << 4) - 0x18; /* double density with 128-byte boot sectors: (sectorcount * 256 - 3 * 128) / 16 */
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.magic1 = AFILE_ATR_MAGIC1;
|
||||
header.magic2 = AFILE_ATR_MAGIC2;
|
||||
header.secsizelo = (UBYTE) sectorsize;
|
||||
header.secsizehi = (UBYTE) (sectorsize >> 8);
|
||||
header.seccountlo = (UBYTE) paras;
|
||||
header.seccounthi = (UBYTE) (paras >> 8);
|
||||
header.hiseccountlo = (UBYTE) (paras >> 16);
|
||||
header.hiseccounthi = (UBYTE) (paras >> 24);
|
||||
return fsave(&header, sizeof(header), pai->fp);
|
||||
}
|
||||
|
||||
static int write_atr_sector(ATR_Info *pai, UBYTE *buf)
|
||||
{
|
||||
return fsave(buf, pai->current_sector++ <= 3 ? 128 : pai->sectorsize, pai->fp);
|
||||
}
|
||||
|
||||
static int pad_till_sector(ATR_Info *pai, int till_sector)
|
||||
{
|
||||
UBYTE zero_buf[256];
|
||||
memset(zero_buf, 0, sizeof(zero_buf));
|
||||
while (pai->current_sector < till_sector)
|
||||
if (!write_atr_sector(pai, zero_buf))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int dcm_pass(FILE *infp, ATR_Info *pai)
|
||||
{
|
||||
UBYTE sector_buf[256];
|
||||
memset(sector_buf, 0, sizeof(sector_buf));
|
||||
for (;;) {
|
||||
/* sector group */
|
||||
int sector_no;
|
||||
int sector_type;
|
||||
sector_no = fgetw(infp);
|
||||
sector_type = fgetc(infp);
|
||||
if (sector_type == 0x45)
|
||||
return TRUE;
|
||||
if (sector_no < pai->current_sector) {
|
||||
Log_print("Error: current sector is %d, next sector group at %d", pai->current_sector, sector_no);
|
||||
return FALSE;
|
||||
}
|
||||
if (!pad_till_sector(pai, sector_no))
|
||||
return FALSE;
|
||||
for (;;) {
|
||||
/* sector */
|
||||
int i;
|
||||
switch (sector_type & 0x7f) {
|
||||
case 0x41:
|
||||
i = fgetc(infp);
|
||||
if (i == EOF)
|
||||
return FALSE;
|
||||
do {
|
||||
int b = fgetc(infp);
|
||||
if (b == EOF)
|
||||
return FALSE;
|
||||
sector_buf[i] = (UBYTE) b;
|
||||
} while (i-- != 0);
|
||||
break;
|
||||
case 0x42:
|
||||
if (!fload(sector_buf + 123, 5, infp))
|
||||
return FALSE;
|
||||
memset(sector_buf, sector_buf[123], 123);
|
||||
break;
|
||||
case 0x43:
|
||||
i = 0;
|
||||
do {
|
||||
int j;
|
||||
int c;
|
||||
j = fgetc(infp);
|
||||
if (j < i) {
|
||||
if (j != 0)
|
||||
return FALSE;
|
||||
j = 256;
|
||||
}
|
||||
if (i < j && !fload(sector_buf + i, j - i, infp))
|
||||
return FALSE;
|
||||
if (j >= pai->sectorsize)
|
||||
break;
|
||||
i = fgetc(infp);
|
||||
if (i < j) {
|
||||
if (i != 0)
|
||||
return FALSE;
|
||||
i = 256;
|
||||
}
|
||||
c = fgetc(infp);
|
||||
if (c == EOF)
|
||||
return FALSE;
|
||||
memset(sector_buf + j, c, i - j);
|
||||
} while (i < pai->sectorsize);
|
||||
break;
|
||||
case 0x44:
|
||||
i = fgetc(infp);
|
||||
if (i == EOF || i >= pai->sectorsize)
|
||||
return FALSE;
|
||||
if (!fload(sector_buf + i, pai->sectorsize - i, infp))
|
||||
return FALSE;
|
||||
break;
|
||||
case 0x46:
|
||||
break;
|
||||
case 0x47:
|
||||
if (!fload(sector_buf, pai->sectorsize, infp))
|
||||
return FALSE;
|
||||
break;
|
||||
default:
|
||||
Log_print("Unrecognized sector coding type 0x%02X", sector_type);
|
||||
return FALSE;
|
||||
}
|
||||
if (!write_atr_sector(pai, sector_buf))
|
||||
return FALSE;
|
||||
if (!(sector_type & 0x80))
|
||||
break; /* goto sector group */
|
||||
sector_type = fgetc(infp);
|
||||
if (sector_type == 0x45)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CompFile_DCMtoATR(FILE *infp, FILE *outfp)
|
||||
{
|
||||
int archive_type;
|
||||
int archive_flags;
|
||||
ATR_Info ai;
|
||||
int pass_flags;
|
||||
int last_sector;
|
||||
archive_type = fgetc(infp);
|
||||
if (archive_type != 0xf9 && archive_type != 0xfa) {
|
||||
Log_print("This is not a DCM image");
|
||||
return FALSE;
|
||||
}
|
||||
archive_flags = fgetc(infp);
|
||||
if ((archive_flags & 0x1f) != 1) {
|
||||
Log_print("Expected pass one first");
|
||||
if (archive_type == 0xf9)
|
||||
Log_print("It seems that DCMs of a multi-file archive have been combined in wrong order");
|
||||
return FALSE;
|
||||
}
|
||||
ai.fp = outfp;
|
||||
ai.current_sector = 1;
|
||||
switch ((archive_flags >> 5) & 3) {
|
||||
case 0:
|
||||
ai.sectorcount = 720;
|
||||
ai.sectorsize = 128;
|
||||
break;
|
||||
case 1:
|
||||
ai.sectorcount = 720;
|
||||
ai.sectorsize = 256;
|
||||
break;
|
||||
case 2:
|
||||
ai.sectorcount = 1040;
|
||||
ai.sectorsize = 128;
|
||||
break;
|
||||
default:
|
||||
Log_print("Unrecognized density");
|
||||
return FALSE;
|
||||
}
|
||||
if (!write_atr_header(&ai))
|
||||
return FALSE;
|
||||
pass_flags = archive_flags;
|
||||
for (;;) {
|
||||
/* pass */
|
||||
int block_type;
|
||||
if (!dcm_pass(infp, &ai))
|
||||
return FALSE;
|
||||
if (pass_flags & 0x80)
|
||||
break;
|
||||
block_type = fgetc(infp);
|
||||
if (block_type != archive_type) {
|
||||
if (block_type == EOF && archive_type == 0xf9) {
|
||||
Log_print("Multi-part archive error.");
|
||||
Log_print("To process these files, you must first combine the files into a single file.");
|
||||
#if defined(WIN32) || defined(DJGPP)
|
||||
Log_print("COPY /B file1.dcm+file2.dcm+file3.dcm newfile.dcm from the DOS prompt");
|
||||
#elif defined(linux) || defined(unix)
|
||||
Log_print("cat file1.dcm file2.dcm file3.dcm >newfile.dcm from the shell");
|
||||
#endif
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
pass_flags = fgetc(infp);
|
||||
if ((pass_flags ^ archive_flags) & 0x60) {
|
||||
Log_print("Density changed inside DCM archive?");
|
||||
return FALSE;
|
||||
}
|
||||
/* TODO: check pass number, this is tricky for >31 */
|
||||
}
|
||||
last_sector = ai.current_sector - 1;
|
||||
if (last_sector <= ai.sectorcount)
|
||||
return pad_till_sector(&ai, ai.sectorcount + 1);
|
||||
/* more sectors written: update ATR header */
|
||||
ai.sectorcount = last_sector;
|
||||
Util_rewind(outfp);
|
||||
return write_atr_header(&ai);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#ifndef COMPFILE_H_
|
||||
#define COMPFILE_H_
|
||||
|
||||
#include <stdio.h> /* FILE */
|
||||
|
||||
int CompFile_ExtractGZ(const char *infilename, FILE *outfp);
|
||||
int CompFile_DCMtoATR(FILE *infp, FILE *outfp);
|
||||
|
||||
#endif /* COMPFILE_H_ */
|
||||
@@ -1,481 +0,0 @@
|
||||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Target: standard I/O. */
|
||||
/* #undef BASIC */
|
||||
|
||||
/* Define to use buffered debug output. */
|
||||
/* #undef BUFFERED_LOG */
|
||||
|
||||
/* Define to allow sound clipping. */
|
||||
/* #undef CLIP_SOUND */
|
||||
|
||||
/* Define to 1 if the `closedir' function returns void instead of `int'. */
|
||||
/* #undef CLOSEDIR_VOID */
|
||||
|
||||
/* Define to allow console sound (keyboard clicks). */
|
||||
#define CONSOLE_SOUND 1
|
||||
|
||||
/* Define to activate crash menu after CIM instruction. */
|
||||
#define CRASH_MENU 1
|
||||
|
||||
/* Define to disable bitmap graphics emulation in CURSES target. */
|
||||
/* #undef CURSES_BASIC */
|
||||
|
||||
/* Alternate config filename due to 8+3 fs limit. */
|
||||
/* #undef DEFAULT_CFG_NAME */
|
||||
|
||||
/* Target: Windows with DirectX. */
|
||||
/* #undef DIRECTX */
|
||||
|
||||
/* Define to use back slash as directory separator. */
|
||||
/* #undef DIR_SEP_BACKSLASH */
|
||||
|
||||
/* Target: DOS VGA. */
|
||||
/* #undef DOSVGA */
|
||||
|
||||
/* Define to enable DOS style drives support. */
|
||||
/* #undef DOS_DRIVES */
|
||||
|
||||
/* Define to enable event recording. */
|
||||
#define EVENT_RECORDING 1
|
||||
|
||||
/* Target: Atari Falcon system. */
|
||||
/* #undef FALCON */
|
||||
|
||||
/* Define to use m68k assembler CPU core for Falcon target. */
|
||||
/* #undef FALCON_CPUASM */
|
||||
|
||||
/* Define to 1 if you have the <arpa/inet.h> header file. */
|
||||
#define HAVE_ARPA_INET_H 1
|
||||
|
||||
/* Define to 1 if you have the `atexit' function. */
|
||||
#define HAVE_ATEXIT 1
|
||||
|
||||
/* Define to 1 if you have the `chmod' function. */
|
||||
#define HAVE_CHMOD 1
|
||||
|
||||
/* Define to 1 if you have the `clock' function. */
|
||||
#define HAVE_CLOCK 1
|
||||
|
||||
/* Define to 1 if you have the <direct.h> header file. */
|
||||
/* #undef HAVE_DIRECT_H */
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
#define HAVE_DIRENT_H 1
|
||||
|
||||
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
|
||||
/* #undef HAVE_DOPRNT */
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#define HAVE_ERRNO_H 1
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `fdopen' function. */
|
||||
#define HAVE_FDOPEN 1
|
||||
|
||||
/* Define to 1 if you have the `fflush' function. */
|
||||
#define HAVE_FFLUSH 1
|
||||
|
||||
/* Define to 1 if you have the <file.h> header file. */
|
||||
/* #undef HAVE_FILE_H */
|
||||
|
||||
/* Define to 1 if you have the `floor' function. */
|
||||
#define HAVE_FLOOR 1
|
||||
|
||||
/* Define to 1 if you have the `fstat' function. */
|
||||
#define HAVE_FSTAT 1
|
||||
|
||||
/* Define to 1 if you have the `getcwd' function. */
|
||||
#define HAVE_GETCWD 1
|
||||
|
||||
/* Define to 1 if you have the `gethostbyaddr' function. */
|
||||
#define HAVE_GETHOSTBYADDR 1
|
||||
|
||||
/* Define to 1 if you have the `gethostbyname' function. */
|
||||
#define HAVE_GETHOSTBYNAME 1
|
||||
|
||||
/* Define to 1 if you have the `gettimeofday' function. */
|
||||
#define HAVE_GETTIMEOFDAY 1
|
||||
|
||||
/* Define to 1 if you have the `inet_ntoa' function. */
|
||||
#define HAVE_INET_NTOA 1
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `png' library (-lpng). */
|
||||
#define HAVE_LIBPNG 1
|
||||
|
||||
/* Define to 1 if you have the `z' library (-lz). */
|
||||
#define HAVE_LIBZ 1
|
||||
|
||||
/* Define to 1 if you have the `localtime' function. */
|
||||
#define HAVE_LOCALTIME 1
|
||||
|
||||
/* Define to 1 if you have the `memmove' function. */
|
||||
#define HAVE_MEMMOVE 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#define HAVE_MEMSET 1
|
||||
|
||||
/* Define to 1 if you have the `mkdir' function. */
|
||||
#define HAVE_MKDIR 1
|
||||
|
||||
/* Define to 1 if you have the `mkstemp' function. */
|
||||
#define HAVE_MKSTEMP 1
|
||||
|
||||
/* Define to 1 if you have the `mktemp' function. */
|
||||
#define HAVE_MKTEMP 1
|
||||
|
||||
/* Define to 1 if you have the `modf' function. */
|
||||
#define HAVE_MODF 1
|
||||
|
||||
/* Define to 1 if you have the `nanosleep' function. */
|
||||
#define HAVE_NANOSLEEP 1
|
||||
|
||||
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||
/* #undef HAVE_NDIR_H */
|
||||
|
||||
/* Define to 1 if you have the <netdb.h> header file. */
|
||||
#define HAVE_NETDB_H 1
|
||||
|
||||
/* Define to 1 if you have the <netinet/in.h> header file. */
|
||||
#define HAVE_NETINET_IN_H 1
|
||||
|
||||
/* Define to 1 if you have the `opendir' function. */
|
||||
#define HAVE_OPENDIR 1
|
||||
|
||||
/* Define to 1 if you have the `rename' function. */
|
||||
#define HAVE_RENAME 1
|
||||
|
||||
/* Define to 1 if you have the `rewind' function. */
|
||||
#define HAVE_REWIND 1
|
||||
|
||||
/* Define to 1 if you have the `rmdir' function. */
|
||||
#define HAVE_RMDIR 1
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#define HAVE_SELECT 1
|
||||
|
||||
/* Define to 1 if you have the `signal' function. */
|
||||
#define HAVE_SIGNAL 1
|
||||
|
||||
/* Define to 1 if you have the <signal.h> header file. */
|
||||
#define HAVE_SIGNAL_H 1
|
||||
|
||||
/* Define to 1 if you have the `snprintf' function. */
|
||||
#define HAVE_SNPRINTF 1
|
||||
|
||||
/* Define to 1 if you have the `socket' function. */
|
||||
#define HAVE_SOCKET 1
|
||||
|
||||
/* Define to 1 if you have the `stat' function. */
|
||||
#define HAVE_STAT 1
|
||||
|
||||
/* Define to 1 if `stat' has the bug that it succeeds when given the
|
||||
zero-length file name argument. */
|
||||
/* #undef HAVE_STAT_EMPTY_STRING_BUG */
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */
|
||||
#define HAVE_STRCASECMP 1
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#define HAVE_STRCHR 1
|
||||
|
||||
/* Define to 1 if you have the `strdup' function. */
|
||||
#define HAVE_STRDUP 1
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#define HAVE_STRERROR 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the `strncpy' function. */
|
||||
#define HAVE_STRNCPY 1
|
||||
|
||||
/* Define to 1 if you have the `strrchr' function. */
|
||||
#define HAVE_STRRCHR 1
|
||||
|
||||
/* Define to 1 if you have the `strstr' function. */
|
||||
#define HAVE_STRSTR 1
|
||||
|
||||
/* Define to 1 if you have the `strtol' function. */
|
||||
#define HAVE_STRTOL 1
|
||||
|
||||
/* Define to 1 if you have the `system' function. */
|
||||
#define HAVE_SYSTEM 1
|
||||
|
||||
/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
/* #undef HAVE_SYS_DIR_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||
#define HAVE_SYS_IOCTL_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
|
||||
*/
|
||||
/* #undef HAVE_SYS_NDIR_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/select.h> header file. */
|
||||
#define HAVE_SYS_SELECT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
#define HAVE_SYS_SOCKET_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/soundcard.h> header file. */
|
||||
#define HAVE_SYS_SOUNDCARD_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/time.h> header file. */
|
||||
#define HAVE_SYS_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#define HAVE_TERMIOS_H 1
|
||||
|
||||
/* Define to 1 if you have the `time' function. */
|
||||
#define HAVE_TIME 1
|
||||
|
||||
/* Define to 1 if you have the <time.h> header file. */
|
||||
#define HAVE_TIME_H 1
|
||||
|
||||
/* Define to 1 if you have the `tmpfile' function. */
|
||||
#define HAVE_TMPFILE 1
|
||||
|
||||
/* Define to 1 if you have the `tmpnam' function. */
|
||||
#define HAVE_TMPNAM 1
|
||||
|
||||
/* Define to 1 if you have the `uclock' function. */
|
||||
/* #undef HAVE_UCLOCK */
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the <unixio.h> header file. */
|
||||
/* #undef HAVE_UNIXIO_H */
|
||||
|
||||
/* Define to 1 if you have the `unlink' function. */
|
||||
#define HAVE_UNLINK 1
|
||||
|
||||
/* Define to 1 if you have the `usleep' function. */
|
||||
#define HAVE_USLEEP 1
|
||||
|
||||
/* Define to 1 if you have the `vprintf' function. */
|
||||
#define HAVE_VPRINTF 1
|
||||
|
||||
/* Define to 1 if you have the `vsnprintf' function. */
|
||||
#define HAVE_VSNPRINTF 1
|
||||
|
||||
/* Define to 1 if you have the <winsock2.h> header file. */
|
||||
/* #undef HAVE_WINSOCK2_H */
|
||||
|
||||
/* Define to allow sound interpolation. */
|
||||
#define INTERPOLATE_SOUND 1
|
||||
|
||||
/* Target: Java NestedVM. */
|
||||
/* #undef JAVANVM */
|
||||
|
||||
/* Define to use LINUX joystick. */
|
||||
/* #undef LINUX_JOYSTICK */
|
||||
|
||||
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
|
||||
slash. */
|
||||
#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
|
||||
|
||||
/* Define to activate assembler in monitor. */
|
||||
#define MONITOR_ASSEMBLER 1
|
||||
|
||||
/* Define to activate code breakpoints and execution history. */
|
||||
#define MONITOR_BREAK 1
|
||||
|
||||
/* Define to activate user-defined breakpoints. */
|
||||
/* #undef MONITOR_BREAKPOINTS */
|
||||
|
||||
/* Define to activate hints in disassembler. */
|
||||
#define MONITOR_HINTS 1
|
||||
|
||||
/* Define to activate 6502 opcode profiling. */
|
||||
/* #undef MONITOR_PROFILE */
|
||||
|
||||
/* Define to activate readline support in monitor. */
|
||||
/* #define MONITOR_READLINE 1 */
|
||||
|
||||
/* Define to activate TRACE command in monitor. */
|
||||
/* #undef MONITOR_TRACE */
|
||||
|
||||
/* Target: X11 with Motif. */
|
||||
/* #undef MOTIF */
|
||||
|
||||
/* Define to allow color changes inside a scanline. */
|
||||
#define NEW_CYCLE_EXACT 1
|
||||
|
||||
/* Define to use nonlinear POKEY mixing. */
|
||||
/* #undef NONLINEAR_MIXING */
|
||||
|
||||
/* Use NTSC video filter. */
|
||||
#define NTSC_FILTER 1
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "pstehlik@sophics.cz"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "Atari800"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "Atari800 2.1.0"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "atari800"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "2.1.0"
|
||||
|
||||
/* Define to use page-based attribute array. */
|
||||
/* #undef PAGED_ATTRIB */
|
||||
|
||||
/* Define to emulate the Black Box. */
|
||||
#define PBI_BB 1
|
||||
|
||||
/* Define to emulate the MIO board. */
|
||||
#define PBI_MIO 1
|
||||
|
||||
/* A prototype 80 column card for the 1090 expansion box. */
|
||||
#define PBI_PROTO80 1
|
||||
|
||||
/* Define to emulate the 1400XL/1450XLD. */
|
||||
#define PBI_XLD 1
|
||||
|
||||
/* Target: Sony PlayStation 2. */
|
||||
/* #undef PS2 */
|
||||
|
||||
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||
#define RETSIGTYPE void
|
||||
|
||||
/* Define to use R: device. */
|
||||
/* #undef R_IO_DEVICE */
|
||||
|
||||
/* Define to use IP network connection with the R: device. */
|
||||
#define R_NETWORK 1
|
||||
|
||||
/* Define to use the host serial port with the R: device. */
|
||||
/* #undef R_SERIAL */
|
||||
|
||||
/* Target: SDL library. */
|
||||
#define SDL 1
|
||||
|
||||
/* Define to the type of arg 1 for `select'. */
|
||||
#define SELECT_TYPE_ARG1 int
|
||||
|
||||
/* Define to the type of args 2, 3 and 4 for `select'. */
|
||||
#define SELECT_TYPE_ARG234 (fd_set *)
|
||||
|
||||
/* Define to the type of arg 5 for `select'. */
|
||||
#define SELECT_TYPE_ARG5 (struct timeval *)
|
||||
|
||||
/* Define to allow serial in/out sound. */
|
||||
/* #undef SERIO_SOUND */
|
||||
|
||||
/* Target: X11 with shared memory extensions. */
|
||||
/* #undef SHM */
|
||||
|
||||
/* Define to activate sound support. */
|
||||
#define SOUND 1
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define to allow stereo sound. */
|
||||
#define STEREO_SOUND 1
|
||||
|
||||
/* Save additional config file options. */
|
||||
#define SUPPORTS_PLATFORM_CONFIGSAVE 1
|
||||
|
||||
/* Additional config file options. */
|
||||
#define SUPPORTS_PLATFORM_CONFIGURE 1
|
||||
|
||||
/* Update the Palette if it changed. */
|
||||
#define SUPPORTS_PLATFORM_PALETTEUPDATE 1
|
||||
|
||||
/* Platform-specific sleep function. */
|
||||
/* #undef SUPPORTS_PLATFORM_SLEEP */
|
||||
|
||||
/* Reinitialise the sound system. */
|
||||
#define SUPPORTS_SOUND_REINIT 1
|
||||
|
||||
/* Alternate system-wide config file for non-Unix OS. */
|
||||
/* #undef SYSTEM_WIDE_CFG_FILE */
|
||||
|
||||
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
|
||||
#define TIME_WITH_SYS_TIME 1
|
||||
|
||||
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
|
||||
/* #undef TM_IN_SYS_TIME */
|
||||
|
||||
/* Target: Curses-compatible library. */
|
||||
/* #undef USE_CURSES */
|
||||
|
||||
/* Define for using cursor/ctrl keys for keyboard joystick. */
|
||||
/* #undef USE_CURSORBLOCK */
|
||||
|
||||
/* Target: Ncurses library. */
|
||||
/* #undef USE_NCURSES */
|
||||
|
||||
/* Define to use very slow computer support (faster -refresh). */
|
||||
/* #undef VERY_SLOW */
|
||||
|
||||
/* Define to allow volume only sound. */
|
||||
#define VOL_ONLY_SOUND 1
|
||||
|
||||
/* Define to 1 if your processor stores words with the most significant byte
|
||||
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||
/* #undef WORDS_BIGENDIAN */
|
||||
|
||||
/* Define if unaligned word access is ok. */
|
||||
#define WORDS_UNALIGNED_OK 1
|
||||
|
||||
/* Target: Standard X11. */
|
||||
/* #undef X11 */
|
||||
|
||||
/* Emulate the XEP80. */
|
||||
#define XEP80_EMULATION 1
|
||||
|
||||
/* Target: X11 with XView. */
|
||||
/* #undef XVIEW */
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
#define inline __inline__
|
||||
#endif
|
||||
|
||||
/* Define to `unsigned int' if <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
||||
|
||||
/* Define to empty if the keyword `volatile' does not work. Warning: valid
|
||||
code using `volatile' can become incorrect without. Disable with care. */
|
||||
/* #undef volatile */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,76 +0,0 @@
|
||||
#ifndef CPU_H_
|
||||
#define CPU_H_
|
||||
|
||||
#include "config.h"
|
||||
#ifdef ASAP /* external project, see http://asap.sf.net */
|
||||
#include "asap_internal.h"
|
||||
#else
|
||||
#include "atari.h"
|
||||
#endif
|
||||
|
||||
#define CPU_N_FLAG 0x80
|
||||
#define CPU_V_FLAG 0x40
|
||||
#define CPU_B_FLAG 0x10
|
||||
#define CPU_D_FLAG 0x08
|
||||
#define CPU_I_FLAG 0x04
|
||||
#define CPU_Z_FLAG 0x02
|
||||
#define CPU_C_FLAG 0x01
|
||||
|
||||
void CPU_Initialise(void); /* used in the assembler version of cpu.c only */
|
||||
void CPU_GetStatus(void);
|
||||
void CPU_PutStatus(void);
|
||||
void CPU_Reset(void);
|
||||
void CPU_StateSave(UBYTE SaveVerbose);
|
||||
void CPU_StateRead(UBYTE SaveVerbose, UBYTE StateVersion);
|
||||
void CPU_NMI(void);
|
||||
void CPU_GO(int limit);
|
||||
#define CPU_GenerateIRQ() (CPU_IRQ = 1)
|
||||
|
||||
#ifdef FALCON_CPUASM
|
||||
extern void CPU_INIT(void);
|
||||
extern void CPU_GET(void); /* put from CCR, N & Z FLAG into regP */
|
||||
extern void CPU_PUT(void); /* put from regP into CCR, N & Z FLAG */
|
||||
#endif
|
||||
|
||||
extern UWORD CPU_regPC;
|
||||
extern UBYTE CPU_regA;
|
||||
extern UBYTE CPU_regP;
|
||||
extern UBYTE CPU_regS;
|
||||
extern UBYTE CPU_regY;
|
||||
extern UBYTE CPU_regX;
|
||||
|
||||
#define CPU_SetN CPU_regP |= CPU_N_FLAG
|
||||
#define CPU_ClrN CPU_regP &= (~CPU_N_FLAG)
|
||||
#define CPU_SetV CPU_regP |= CPU_V_FLAG
|
||||
#define CPU_ClrV CPU_regP &= (~CPU_V_FLAG)
|
||||
#define CPU_SetB CPU_regP |= CPU_B_FLAG
|
||||
#define CPU_ClrB CPU_regP &= (~CPU_B_FLAG)
|
||||
#define CPU_SetD CPU_regP |= CPU_D_FLAG
|
||||
#define CPU_ClrD CPU_regP &= (~CPU_D_FLAG)
|
||||
#define CPU_SetI CPU_regP |= CPU_I_FLAG
|
||||
#define CPU_ClrI CPU_regP &= (~CPU_I_FLAG)
|
||||
#define CPU_SetZ CPU_regP |= CPU_Z_FLAG
|
||||
#define CPU_ClrZ CPU_regP &= (~CPU_Z_FLAG)
|
||||
#define CPU_SetC CPU_regP |= CPU_C_FLAG
|
||||
#define CPU_ClrC CPU_regP &= (~CPU_C_FLAG)
|
||||
|
||||
extern UBYTE CPU_IRQ;
|
||||
|
||||
extern void (*CPU_rts_handler)(void);
|
||||
|
||||
extern UBYTE CPU_cim_encountered;
|
||||
|
||||
#define CPU_REMEMBER_PC_STEPS 64
|
||||
extern UWORD CPU_remember_PC[CPU_REMEMBER_PC_STEPS];
|
||||
extern unsigned int CPU_remember_PC_curpos;
|
||||
extern int CPU_remember_xpos[CPU_REMEMBER_PC_STEPS];
|
||||
|
||||
#define CPU_REMEMBER_JMP_STEPS 16
|
||||
extern UWORD CPU_remember_JMP[CPU_REMEMBER_JMP_STEPS];
|
||||
extern unsigned int CPU_remember_jmp_curpos;
|
||||
|
||||
#ifdef MONITOR_PROFILE
|
||||
extern int CPU_instruction_count[256];
|
||||
#endif
|
||||
|
||||
#endif /* CPU_H_ */
|
||||
@@ -1,201 +0,0 @@
|
||||
/*
|
||||
* cycle_map.c - part of the ANTIC emulation
|
||||
*
|
||||
* Copyright (C) 1995-1998 Perry McFarlane
|
||||
* Copyright (C) 1998-2005 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "cycle_map.h"
|
||||
|
||||
int CYCLE_MAP_cpu2antic[CYCLE_MAP_SIZE * (17 * 7 + 1)];
|
||||
int CYCLE_MAP_antic2cpu[CYCLE_MAP_SIZE * (17 * 7 + 1)];
|
||||
static void try_all_scroll(int md, int use_char_index,
|
||||
int use_font, int use_bitmap, int *cpu2antic, int *antic2cpu);
|
||||
static void antic_steal_map(int width, int md, int scroll_offset, int use_char_index,
|
||||
int use_font, int use_bitmap, char *antic_cycles, int *cpucycles,
|
||||
int *actualcycles);
|
||||
static void cpu_cycle_map(char *antic_cycles_orig, int *cpu_cycles, int *actual_cycles);
|
||||
|
||||
#undef TEST_CYCLE_MAP
|
||||
#ifdef TEST_CYCLE_MAP
|
||||
int main()
|
||||
{
|
||||
CYCLE_MAP_Create();
|
||||
return 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
static void cpu_cycle_map(char *antic_cycles_orig, int *cpu_cycles, int *actual_cycles)
|
||||
{
|
||||
int i;
|
||||
char antic_cycles[CYCLE_MAP_SIZE];
|
||||
int antic_xpos;
|
||||
int cpu_xpos = 0;
|
||||
for (i = 0; i <= 113; i++)
|
||||
antic_cycles[i] = antic_cycles_orig[i];
|
||||
for (i = 114; i < CYCLE_MAP_SIZE; i++)
|
||||
antic_cycles[i] = '.';
|
||||
for (i = 0; i < CYCLE_MAP_SIZE; i++)
|
||||
cpu_cycles[i]=-1;
|
||||
for (antic_xpos = 0; antic_xpos < CYCLE_MAP_SIZE; antic_xpos++) {
|
||||
char c = antic_cycles[antic_xpos];
|
||||
actual_cycles[antic_xpos] = cpu_xpos;
|
||||
if (c != 'R' && c != 'S' && c != 'F' && c != 'I') {
|
||||
/*Not a stolen cycle*/
|
||||
cpu_cycles[cpu_xpos] = antic_xpos;
|
||||
cpu_xpos++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CYCLE_MAP_Create(void)
|
||||
{
|
||||
#ifdef TEST_CYCLE_MAP
|
||||
int i, j;
|
||||
int *cpu_cycles;
|
||||
int *actual_cycles;
|
||||
#endif
|
||||
char antic_cycles[115];
|
||||
int k = 0;
|
||||
antic_steal_map(1, 0, 0, 0, 0, 0, antic_cycles, &CYCLE_MAP_cpu2antic[k], &CYCLE_MAP_antic2cpu[k]); /* blank line, or mode 8-F following line*/
|
||||
k = CYCLE_MAP_SIZE * (17 * 0 + 1);
|
||||
try_all_scroll(0, 1, 1, 0, &CYCLE_MAP_cpu2antic[k], &CYCLE_MAP_antic2cpu[k]); /* mode 2,3,4,5 first line */
|
||||
k = CYCLE_MAP_SIZE * (17 * 1 + 1);
|
||||
try_all_scroll(0, 0, 1, 0, &CYCLE_MAP_cpu2antic[k], &CYCLE_MAP_antic2cpu[k]); /* mode 2,3,4,5 following lines */
|
||||
k = CYCLE_MAP_SIZE * (17 * 2 + 1);
|
||||
try_all_scroll(1, 1, 1, 0, &CYCLE_MAP_cpu2antic[k], &CYCLE_MAP_antic2cpu[k]); /* mode 6,7 first line */
|
||||
k = CYCLE_MAP_SIZE * (17 * 3 + 1);
|
||||
try_all_scroll(1, 0, 1, 0, &CYCLE_MAP_cpu2antic[k], &CYCLE_MAP_antic2cpu[k]); /* mode 6,7 following lines */
|
||||
k = CYCLE_MAP_SIZE * (17 * 4 + 1);
|
||||
try_all_scroll(0, 0, 0, 1, &CYCLE_MAP_cpu2antic[k], &CYCLE_MAP_antic2cpu[k]); /* mode 8,9 first line */
|
||||
k = CYCLE_MAP_SIZE * (17 * 5 + 1);
|
||||
try_all_scroll(1, 0, 0, 1, &CYCLE_MAP_cpu2antic[k], &CYCLE_MAP_antic2cpu[k]); /* mode A,B,C first line */
|
||||
k = CYCLE_MAP_SIZE * (17 * 6 + 1);
|
||||
try_all_scroll(2, 0, 0, 1, &CYCLE_MAP_cpu2antic[k], &CYCLE_MAP_antic2cpu[k]); /* mode D,E,F first line */
|
||||
#ifdef TEST_CYCLE_MAP
|
||||
for(j = 0; j < 17 * 7 + 1; j++) {
|
||||
cpu_cycles = &CYCLE_MAP_cpu2antic[CYCLE_MAP_SIZE * j];
|
||||
actual_cycles = &CYCLE_MAP_antic2cpu[CYCLE_MAP_SIZE * j];
|
||||
printf("%3d ", actual_cycles[114]);
|
||||
for(i = 0; i <= actual_cycles[114] + 6; i++)
|
||||
printf("%3d, ", cpu_cycles[i]);
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void try_all_scroll(int md, int use_char_index,
|
||||
int use_font, int use_bitmap, int *cpu2antic, int *antic2cpu)
|
||||
{
|
||||
char antic_cycles[115];
|
||||
int width;
|
||||
int scroll_offset = 0;
|
||||
width = 1; /* narrow width without scroll*/
|
||||
antic_steal_map(width, md, scroll_offset, use_char_index, use_font,
|
||||
use_bitmap, antic_cycles, &cpu2antic[CYCLE_MAP_SIZE * 0], &antic2cpu[CYCLE_MAP_SIZE * 0]);
|
||||
width = 2; /* standard without scroll or narrow with scroll */
|
||||
for (scroll_offset = 0; scroll_offset <= 7; scroll_offset++) {
|
||||
antic_steal_map(width, md, scroll_offset, use_char_index, use_font,
|
||||
use_bitmap, antic_cycles, &cpu2antic[CYCLE_MAP_SIZE * (1 + scroll_offset)],
|
||||
&antic2cpu[CYCLE_MAP_SIZE * (1 + scroll_offset)]);
|
||||
}
|
||||
width = 3; /* standard with scroll or wide */
|
||||
for (scroll_offset = 0; scroll_offset <= 7; scroll_offset++) {
|
||||
antic_steal_map(width, md, scroll_offset, use_char_index, use_font,
|
||||
use_bitmap, antic_cycles, &cpu2antic[CYCLE_MAP_SIZE * (9 + scroll_offset)],
|
||||
&antic2cpu[CYCLE_MAP_SIZE * (9 + scroll_offset)]);
|
||||
}
|
||||
}
|
||||
|
||||
static void antic_steal_map(int width, int md, int scroll_offset, int use_char_index,
|
||||
int use_font, int use_bitmap, char *antic_cycles, int *cpu_cycles,
|
||||
int *actual_cycles)
|
||||
{
|
||||
int char_start;
|
||||
int bitmap_start;
|
||||
int font_start;
|
||||
int i;
|
||||
int dram_pending;
|
||||
int interval;
|
||||
int steal;
|
||||
int max_chars;
|
||||
/* defaults for wide playfield */
|
||||
#define CHAR_C 13
|
||||
#define BITMAP_C (CHAR_C + 2)
|
||||
#define FONT_C (CHAR_C + 3)
|
||||
#define END_C (CHAR_C + 95)
|
||||
#define DMARS_C (CHAR_C + 15)
|
||||
#define DMARE_C (DMARS_C + 32)
|
||||
char_start = CHAR_C + scroll_offset;
|
||||
bitmap_start = BITMAP_C + scroll_offset;
|
||||
font_start = FONT_C + scroll_offset;
|
||||
max_chars = 48;
|
||||
if (width == 2) { /* standard width */
|
||||
char_start += 8;
|
||||
bitmap_start += 8;
|
||||
font_start += 8;
|
||||
max_chars = 40;
|
||||
}
|
||||
else if (width == 1) { /* narrow */
|
||||
char_start += 16;
|
||||
bitmap_start += 16;
|
||||
font_start += 16;
|
||||
max_chars = 32;
|
||||
}
|
||||
|
||||
interval = (2 << md);
|
||||
max_chars = (max_chars >> md);
|
||||
for (i = 0; i <= 113; i++)
|
||||
antic_cycles[i] = '.';
|
||||
antic_cycles[114] = '\0';
|
||||
antic_cycles[0] = 'M';
|
||||
antic_cycles[1] = antic_cycles[6] = antic_cycles[7] = 'D';
|
||||
antic_cycles[2] = antic_cycles[3] = antic_cycles[4] = antic_cycles[5] = 'P';
|
||||
dram_pending = 0;
|
||||
for (i = 0; i <= 114; i++) {
|
||||
steal = 0;
|
||||
if (i <= END_C) {
|
||||
if (use_char_index && i >= char_start && ((i - char_start) % interval == 0)
|
||||
&& ((i - char_start) < max_chars * interval)) {
|
||||
steal = 'I';
|
||||
}
|
||||
if (use_font && i >= font_start && ((i - font_start) % interval == 0)
|
||||
&& ((i - font_start) < max_chars * interval)) {
|
||||
steal = 'F';
|
||||
}
|
||||
if (use_bitmap && i >= bitmap_start && ((i - bitmap_start) % interval == 0)
|
||||
&& ((i - bitmap_start) < max_chars * interval)) {
|
||||
steal = 'S';
|
||||
}
|
||||
if (i >= DMARS_C && i <= DMARE_C && ((i - DMARS_C) % 4 == 0)) {
|
||||
dram_pending = 1;
|
||||
}
|
||||
}
|
||||
if (steal !=0 ) {
|
||||
antic_cycles[i] = steal;
|
||||
}
|
||||
else if (dram_pending != 0){
|
||||
antic_cycles[i] = 'R';
|
||||
dram_pending = 0;
|
||||
}
|
||||
}
|
||||
cpu_cycle_map(antic_cycles, cpu_cycles, actual_cycles);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#ifndef CYCLE_MAP_H_
|
||||
#define CYCLE_MAP_H_
|
||||
|
||||
#define CYCLE_MAP_SIZE (114 + 9)
|
||||
extern int CYCLE_MAP_cpu2antic[CYCLE_MAP_SIZE * (17 * 7 + 1)];
|
||||
extern int CYCLE_MAP_antic2cpu[CYCLE_MAP_SIZE * (17 * 7 + 1)];
|
||||
void CYCLE_MAP_Create(void);
|
||||
|
||||
#endif /* CYCLE_MAP_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,74 +0,0 @@
|
||||
#ifndef DEVICES_H_
|
||||
#define DEVICES_H_
|
||||
|
||||
#include <stdio.h> /* FILENAME_MAX */
|
||||
#include "atari.h" /* UWORD */
|
||||
|
||||
int Devices_Initialise(int *argc, char *argv[]);
|
||||
int Devices_PatchOS(void);
|
||||
void Devices_Frame(void);
|
||||
void Devices_UpdatePatches(void);
|
||||
|
||||
UWORD Devices_SkipDeviceName(void);
|
||||
|
||||
extern int Devices_enable_h_patch;
|
||||
extern int Devices_enable_p_patch;
|
||||
extern int Devices_enable_r_patch;
|
||||
|
||||
extern char Devices_atari_h_dir[4][FILENAME_MAX];
|
||||
extern int Devices_h_read_only;
|
||||
|
||||
extern char Devices_h_exe_path[FILENAME_MAX];
|
||||
|
||||
extern char Devices_h_current_dir[4][FILENAME_MAX];
|
||||
|
||||
int Devices_H_CountOpen(void);
|
||||
void Devices_H_CloseAll(void);
|
||||
|
||||
extern char Devices_print_command[256];
|
||||
|
||||
int Devices_SetPrintCommand(const char *command);
|
||||
|
||||
#define Devices_ICHIDZ 0x0020
|
||||
#define Devices_ICDNOZ 0x0021
|
||||
#define Devices_ICCOMZ 0x0022
|
||||
#define Devices_ICSTAZ 0x0023
|
||||
#define Devices_ICBALZ 0x0024
|
||||
#define Devices_ICBAHZ 0x0025
|
||||
#define Devices_ICPTLZ 0x0026
|
||||
#define Devices_ICPTHZ 0x0027
|
||||
#define Devices_ICBLLZ 0x0028
|
||||
#define Devices_ICBLHZ 0x0029
|
||||
#define Devices_ICAX1Z 0x002a
|
||||
#define Devices_ICAX2Z 0x002b
|
||||
|
||||
#define Devices_IOCB0 0x0340
|
||||
#define Devices_ICHID 0x0000
|
||||
#define Devices_ICDNO 0x0001
|
||||
#define Devices_ICCOM 0x0002
|
||||
#define Devices_ICSTA 0x0003
|
||||
#define Devices_ICBAL 0x0004
|
||||
#define Devices_ICBAH 0x0005
|
||||
#define Devices_ICPTL 0x0006
|
||||
#define Devices_ICPTH 0x0007
|
||||
#define Devices_ICBLL 0x0008
|
||||
#define Devices_ICBLH 0x0009
|
||||
#define Devices_ICAX1 0x000a
|
||||
#define Devices_ICAX2 0x000b
|
||||
#define Devices_ICAX3 0x000c
|
||||
#define Devices_ICAX4 0x000d
|
||||
#define Devices_ICAX5 0x000e
|
||||
#define Devices_ICAX6 0x000f
|
||||
|
||||
#define Devices_TABLE_OPEN 0
|
||||
#define Devices_TABLE_CLOS 2
|
||||
#define Devices_TABLE_READ 4
|
||||
#define Devices_TABLE_WRIT 6
|
||||
#define Devices_TABLE_STAT 8
|
||||
#define Devices_TABLE_SPEC 10
|
||||
#define Devices_TABLE_INIT 12
|
||||
|
||||
UWORD Devices_UpdateHATABSEntry(char device, UWORD entry_address, UWORD table_address);
|
||||
void Devices_RemoveHATABSEntry(char device, UWORD entry_address, UWORD table_address);
|
||||
|
||||
#endif /* DEVICES_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,569 +0,0 @@
|
||||
.OPT NO LIST
|
||||
; emuos.lis - OS bootstrapping code
|
||||
;
|
||||
; Copyright (C) 1995-1998 David Firth
|
||||
; Copyright (C) 2001-2009 Atari800 development team (see DOC/CREDITS)
|
||||
;
|
||||
; This file is part of the Atari800 emulator project which emulates
|
||||
; the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
;
|
||||
; Atari800 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.
|
||||
;
|
||||
; Atari800 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 Atari800; if not, write to the Free Software
|
||||
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
;
|
||||
;
|
||||
; UPDATE EMUOS.LIS
|
||||
; Start Emulator
|
||||
; Insert MAC/65 Cartridge
|
||||
; ENTER #H5:EMUOS.LIS,A
|
||||
; ASM,,#H0:EMUOS.OBJ
|
||||
; Exit Emulator
|
||||
; mkimg -input emuos.obj -image emuos.img -header emuos.h e000 ffff
|
||||
;
|
||||
BOOT = $09
|
||||
RTCLOK = $12
|
||||
VVBLKI = $0222
|
||||
VVBLKD = $0224
|
||||
;
|
||||
; ============================
|
||||
; OS Hardware Shadow Registers
|
||||
; ============================
|
||||
;
|
||||
CHART = $02F3
|
||||
CHBAS = $02F4
|
||||
CH = $02FC
|
||||
COLOR4 = $02C8
|
||||
COLOR0 = $02C4
|
||||
COLOR1 = $02C5
|
||||
COLOR2 = $02C6
|
||||
COLOR3 = $02C7
|
||||
PCOLR0 = $02C0
|
||||
PCOLR1 = $02C1
|
||||
PCOLR2 = $02C2
|
||||
PCOLR3 = $02C3
|
||||
SDLSTH = $0231
|
||||
SDLSTL = $0230
|
||||
SDMCTL = $022F
|
||||
STICK0 = $0278
|
||||
STICK1 = $0279
|
||||
STICK2 = $027A
|
||||
STICK3 = $027B
|
||||
GPRIOR = $026F
|
||||
SSKCTL = $0232
|
||||
STRIG0 = $0284
|
||||
STRIG1 = $0285
|
||||
STRIG2 = $0286
|
||||
STRIG3 = $0287
|
||||
;
|
||||
DDEVIC = $0300
|
||||
DUNIT = $0301
|
||||
DCOMND = $0302
|
||||
DSTATS = $0303
|
||||
DBUFLO = $0304
|
||||
DBUFHI = $0305
|
||||
DTIMLO = $0306
|
||||
DTIMHI = $0307
|
||||
DBYTLO = $0308
|
||||
DBYTHI = $0309
|
||||
DAUX1 = $030A
|
||||
DAUX2 = $030B
|
||||
;
|
||||
; ==================
|
||||
; Hardware Registers
|
||||
; ==================
|
||||
;
|
||||
CHACTL = $D401
|
||||
CHBASE = $D409
|
||||
COLBK = $D01A
|
||||
COLPF0 = $D016
|
||||
COLPF1 = $D017
|
||||
COLPF2 = $D018
|
||||
COLPF3 = $D019
|
||||
COLPM0 = $D012
|
||||
COLPM1 = $D013
|
||||
COLPM2 = $D014
|
||||
COLPM3 = $D015
|
||||
CONSOL = $D01F
|
||||
DLISTH = $D403
|
||||
DLISTL = $D402
|
||||
DMACTL = $D400
|
||||
KBCODE = $D209
|
||||
IRQEN = $D20E
|
||||
IRQST = $D20E
|
||||
NMIRES = $D40F
|
||||
NMIST = $D40F
|
||||
PACTL = $D302
|
||||
PORTA = $D300
|
||||
PORTB = $D301
|
||||
PRIOR = $D01B
|
||||
SKCTL = $D20F
|
||||
TRIG0 = $D010
|
||||
TRIG1 = $D011
|
||||
TRIG2 = $D012
|
||||
TRIG3 = $D013
|
||||
VCOUNT = $D40B
|
||||
;
|
||||
*= $E000
|
||||
.BYTE $00,$00,$00,$00,$00,$00,$00,$00
|
||||
.BYTE $00,$18,$18,$18,$18,$00,$18,$00
|
||||
.BYTE $00,$66,$66,$66,$00,$00,$00,$00
|
||||
.BYTE $00,$66,$FF,$66,$66,$FF,$66,$00
|
||||
.BYTE $18,$3E,$60,$3C,$06,$7C,$18,$00
|
||||
.BYTE $00,$66,$6C,$18,$30,$66,$46,$00
|
||||
.BYTE $1C,$36,$1C,$38,$6F,$66,$3B,$00
|
||||
.BYTE $00,$18,$18,$18,$00,$00,$00,$00
|
||||
.BYTE $00,$0E,$1C,$18,$18,$1C,$0E,$00
|
||||
.BYTE $00,$70,$38,$18,$18,$38,$70,$00
|
||||
.BYTE $00,$66,$3C,$FF,$3C,$66,$00,$00
|
||||
.BYTE $00,$18,$18,$7E,$18,$18,$00,$00
|
||||
.BYTE $00,$00,$00,$00,$00,$18,$18,$30
|
||||
.BYTE $00,$00,$00,$7E,$00,$00,$00,$00
|
||||
.BYTE $00,$00,$00,$00,$00,$18,$18,$00
|
||||
.BYTE $00,$06,$0C,$18,$30,$60,$40,$00
|
||||
.BYTE $00,$3C,$66,$6E,$76,$66,$3C,$00
|
||||
.BYTE $00,$18,$38,$18,$18,$18,$7E,$00
|
||||
.BYTE $00,$3C,$66,$0C,$18,$30,$7E,$00
|
||||
.BYTE $00,$7E,$0C,$18,$0C,$66,$3C,$00
|
||||
.BYTE $00,$0C,$1C,$3C,$6C,$7E,$0C,$00
|
||||
.BYTE $00,$7E,$60,$7C,$06,$66,$3C,$00
|
||||
.BYTE $00,$3C,$60,$7C,$66,$66,$3C,$00
|
||||
.BYTE $00,$7E,$06,$0C,$18,$30,$30,$00
|
||||
.BYTE $00,$3C,$66,$3C,$66,$66,$3C,$00
|
||||
.BYTE $00,$3C,$66,$3E,$06,$0C,$38,$00
|
||||
.BYTE $00,$00,$18,$18,$00,$18,$18,$00
|
||||
.BYTE $00,$00,$18,$18,$00,$18,$18,$30
|
||||
.BYTE $06,$0C,$18,$30,$18,$0C,$06,$00
|
||||
.BYTE $00,$00,$7E,$00,$00,$7E,$00,$00
|
||||
.BYTE $60,$30,$18,$0C,$18,$30,$60,$00
|
||||
.BYTE $00,$3C,$66,$0C,$18,$00,$18,$00
|
||||
.BYTE $00,$3C,$66,$6E,$6E,$60,$3E,$00
|
||||
.BYTE $00,$18,$3C,$66,$66,$7E,$66,$00
|
||||
.BYTE $00,$7C,$66,$7C,$66,$66,$7C,$00
|
||||
.BYTE $00,$3C,$66,$60,$60,$66,$3C,$00
|
||||
.BYTE $00,$78,$6C,$66,$66,$6C,$78,$00
|
||||
.BYTE $00,$7E,$60,$7C,$60,$60,$7E,$00
|
||||
.BYTE $00,$7E,$60,$7C,$60,$60,$60,$00
|
||||
.BYTE $00,$3E,$60,$60,$6E,$66,$3E,$00
|
||||
.BYTE $00,$66,$66,$7E,$66,$66,$66,$00
|
||||
.BYTE $00,$7E,$18,$18,$18,$18,$7E,$00
|
||||
.BYTE $00,$06,$06,$06,$06,$66,$3C,$00
|
||||
.BYTE $00,$66,$6C,$78,$78,$6C,$66,$00
|
||||
.BYTE $00,$60,$60,$60,$60,$60,$7E,$00
|
||||
.BYTE $00,$63,$77,$7F,$6B,$63,$63,$00
|
||||
.BYTE $00,$66,$76,$7E,$7E,$6E,$66,$00
|
||||
.BYTE $00,$3C,$66,$66,$66,$66,$3C,$00
|
||||
.BYTE $00,$7C,$66,$66,$7C,$60,$60,$00
|
||||
.BYTE $00,$3C,$66,$66,$66,$6C,$36,$00
|
||||
.BYTE $00,$7C,$66,$66,$7C,$6C,$66,$00
|
||||
.BYTE $00,$3C,$60,$3C,$06,$06,$3C,$00
|
||||
.BYTE $00,$7E,$18,$18,$18,$18,$18,$00
|
||||
.BYTE $00,$66,$66,$66,$66,$66,$7E,$00
|
||||
.BYTE $00,$66,$66,$66,$66,$3C,$18,$00
|
||||
.BYTE $00,$63,$63,$6B,$7F,$77,$63,$00
|
||||
.BYTE $00,$66,$66,$3C,$3C,$66,$66,$00
|
||||
.BYTE $00,$66,$66,$3C,$18,$18,$18,$00
|
||||
.BYTE $00,$7E,$0C,$18,$30,$60,$7E,$00
|
||||
.BYTE $00,$1E,$18,$18,$18,$18,$1E,$00
|
||||
.BYTE $00,$40,$60,$30,$18,$0C,$06,$00
|
||||
.BYTE $00,$78,$18,$18,$18,$18,$78,$00
|
||||
.BYTE $00,$08,$1C,$36,$63,$00,$00,$00
|
||||
.BYTE $00,$00,$00,$00,$00,$00,$FF,$00
|
||||
.BYTE $00,$36,$7F,$7F,$3E,$1C,$08,$00
|
||||
.BYTE $18,$18,$18,$1F,$1F,$18,$18,$18
|
||||
.BYTE $03,$03,$03,$03,$03,$03,$03,$03
|
||||
.BYTE $18,$18,$18,$F8,$F8,$00,$00,$00
|
||||
.BYTE $18,$18,$18,$F8,$F8,$18,$18,$18
|
||||
.BYTE $00,$00,$00,$F8,$F8,$18,$18,$18
|
||||
.BYTE $03,$07,$0E,$1C,$38,$70,$E0,$C0
|
||||
.BYTE $C0,$E0,$70,$38,$1C,$0E,$07,$03
|
||||
.BYTE $01,$03,$07,$0F,$1F,$3F,$7F,$FF
|
||||
.BYTE $00,$00,$00,$00,$0F,$0F,$0F,$0F
|
||||
.BYTE $80,$C0,$E0,$F0,$F8,$FC,$FE,$FF
|
||||
.BYTE $0F,$0F,$0F,$0F,$00,$00,$00,$00
|
||||
.BYTE $F0,$F0,$F0,$F0,$00,$00,$00,$00
|
||||
.BYTE $FF,$FF,$00,$00,$00,$00,$00,$00
|
||||
.BYTE $00,$00,$00,$00,$00,$00,$FF,$FF
|
||||
.BYTE $00,$00,$00,$00,$F0,$F0,$F0,$F0
|
||||
.BYTE $00,$1C,$1C,$77,$77,$08,$1C,$00
|
||||
.BYTE $00,$00,$00,$1F,$1F,$18,$18,$18
|
||||
.BYTE $00,$00,$00,$FF,$FF,$00,$00,$00
|
||||
.BYTE $18,$18,$18,$FF,$FF,$18,$18,$18
|
||||
.BYTE $00,$00,$3C,$7E,$7E,$7E,$3C,$00
|
||||
.BYTE $00,$00,$00,$00,$FF,$FF,$FF,$FF
|
||||
.BYTE $C0,$C0,$C0,$C0,$C0,$C0,$C0,$C0
|
||||
.BYTE $00,$00,$00,$FF,$FF,$18,$18,$18
|
||||
.BYTE $18,$18,$18,$FF,$FF,$00,$00,$00
|
||||
.BYTE $F0,$F0,$F0,$F0,$F0,$F0,$F0,$F0
|
||||
.BYTE $18,$18,$18,$1F,$1F,$00,$00,$00
|
||||
.BYTE $78,$60,$78,$60,$7E,$18,$1E,$00
|
||||
.BYTE $00,$18,$3C,$7E,$18,$18,$18,$00
|
||||
.BYTE $00,$18,$18,$18,$7E,$3C,$18,$00
|
||||
.BYTE $00,$18,$30,$7E,$30,$18,$00,$00
|
||||
.BYTE $00,$18,$0C,$7E,$0C,$18,$00,$00
|
||||
.BYTE $00,$18,$3C,$7E,$7E,$3C,$18,$00
|
||||
.BYTE $00,$00,$3C,$06,$3E,$66,$3E,$00
|
||||
.BYTE $00,$60,$60,$7C,$66,$66,$7C,$00
|
||||
.BYTE $00,$00,$3C,$60,$60,$60,$3C,$00
|
||||
.BYTE $00,$06,$06,$3E,$66,$66,$3E,$00
|
||||
.BYTE $00,$00,$3C,$66,$7E,$60,$3C,$00
|
||||
.BYTE $00,$0E,$18,$3E,$18,$18,$18,$00
|
||||
.BYTE $00,$00,$3E,$66,$66,$3E,$06,$7C
|
||||
.BYTE $00,$60,$60,$7C,$66,$66,$66,$00
|
||||
.BYTE $00,$18,$00,$38,$18,$18,$3C,$00
|
||||
.BYTE $00,$06,$00,$06,$06,$06,$06,$3C
|
||||
.BYTE $00,$60,$60,$6C,$78,$6C,$66,$00
|
||||
.BYTE $00,$38,$18,$18,$18,$18,$3C,$00
|
||||
.BYTE $00,$00,$66,$7F,$7F,$6B,$63,$00
|
||||
.BYTE $00,$00,$7C,$66,$66,$66,$66,$00
|
||||
.BYTE $00,$00,$3C,$66,$66,$66,$3C,$00
|
||||
.BYTE $00,$00,$7C,$66,$66,$7C,$60,$60
|
||||
.BYTE $00,$00,$3E,$66,$66,$3E,$06,$06
|
||||
.BYTE $00,$00,$7C,$66,$60,$60,$60,$00
|
||||
.BYTE $00,$00,$3E,$60,$3C,$06,$7C,$00
|
||||
.BYTE $00,$18,$7E,$18,$18,$18,$0E,$00
|
||||
.BYTE $00,$00,$66,$66,$66,$66,$3E,$00
|
||||
.BYTE $00,$00,$66,$66,$66,$3C,$18,$00
|
||||
.BYTE $00,$00,$63,$6B,$7F,$3E,$36,$00
|
||||
.BYTE $00,$00,$66,$3C,$18,$3C,$66,$00
|
||||
.BYTE $00,$00,$66,$66,$66,$3E,$0C,$78
|
||||
.BYTE $00,$00,$7E,$0C,$18,$30,$7E,$00
|
||||
.BYTE $00,$18,$3C,$7E,$7E,$18,$3C,$00
|
||||
.BYTE $18,$18,$18,$18,$18,$18,$18,$18
|
||||
.BYTE $00,$7E,$78,$7C,$6E,$66,$06,$00
|
||||
.BYTE $08,$18,$38,$78,$38,$18,$08,$00
|
||||
.BYTE $10,$18,$1C,$1E,$1C,$18,$10,$00
|
||||
;
|
||||
DISKIV = $E450
|
||||
DSKINV = $E453
|
||||
CIOV = $E456
|
||||
SIOV = $E459
|
||||
SETVBV = $E45C
|
||||
SYSVBV = $E45F
|
||||
XITVBV = $E462
|
||||
SIOINV = $E465
|
||||
SENDEV = $E468
|
||||
INTINV = $E46B
|
||||
CIOINV = $E46E
|
||||
BLKBDV = $E471
|
||||
WARMSV = $E474
|
||||
COLDSV = $E477
|
||||
RBLOKV = $E47A
|
||||
CSOPIV = $E47D
|
||||
;
|
||||
*= DISKIV
|
||||
JMP HALT
|
||||
*= DSKINV
|
||||
JMP HALT
|
||||
*= CIOV
|
||||
JMP HALT
|
||||
*= SIOV
|
||||
JMP HALT
|
||||
*= SETVBV
|
||||
JMP HALT
|
||||
*= SYSVBV
|
||||
JMP HALT
|
||||
*= XITVBV
|
||||
JMP XITVBL
|
||||
*= SIOINV
|
||||
JMP HALT
|
||||
*= SENDEV
|
||||
JMP HALT
|
||||
*= INTINV
|
||||
JMP HALT
|
||||
*= CIOINV
|
||||
JMP HALT
|
||||
*= BLKBDV
|
||||
JMP HALT
|
||||
*= WARMSV
|
||||
JMP COLDSTART
|
||||
*= COLDSV
|
||||
JMP COLDSTART
|
||||
*= RBLOKV
|
||||
JMP HALT
|
||||
*= CSOPIV
|
||||
JMP HALT
|
||||
;
|
||||
*= $F800
|
||||
COLDSTART
|
||||
LDX #$FF
|
||||
TXS
|
||||
LDA # <SYSVBL
|
||||
STA VVBLKI
|
||||
LDA # >SYSVBL
|
||||
STA VVBLKI+1
|
||||
LDA # <XITVBL
|
||||
STA VVBLKD
|
||||
LDA # >XITVBL
|
||||
STA VVBLKD+1
|
||||
LDA # <IRQ
|
||||
STA $0216
|
||||
LDA # >IRQ
|
||||
STA $0217
|
||||
LDA $0000
|
||||
BNE RPIIMG ; Run pre-installed image
|
||||
LDA $0001
|
||||
BNE RPIIMG ; Run pre-installed image
|
||||
LDA $BFFC
|
||||
INC $BFFC
|
||||
CMP $BFFC
|
||||
BNE BOOTDISK
|
||||
; BNE MONTY
|
||||
JSR CART.INIT
|
||||
JMP ($BFFA)
|
||||
CART.INIT
|
||||
JMP ($BFFE)
|
||||
;MONTY
|
||||
; STA $BFFC ; Restore original value to $BFFC
|
||||
; JMP $0115 ; Run Montezummas Revenge
|
||||
RPIIMG
|
||||
JMP ($0000) ; Run pre-installed image
|
||||
;
|
||||
BOOTDISK
|
||||
LDA #$31
|
||||
STA DDEVIC
|
||||
LDA #$01
|
||||
STA DUNIT
|
||||
LDA #$52
|
||||
STA DCOMND
|
||||
LDA #0
|
||||
STA DBUFLO
|
||||
LDA #4
|
||||
STA DBUFHI
|
||||
LDA #$80
|
||||
STA DBYTLO
|
||||
LDA #$00
|
||||
STA DBYTHI
|
||||
LDA #1
|
||||
STA DAUX1
|
||||
LDA #0
|
||||
STA DAUX2
|
||||
JSR SIOV
|
||||
BMI HALT
|
||||
LDA $0400
|
||||
CMP #$FF
|
||||
BNE BOOTDISK.1
|
||||
LDA $0401
|
||||
CMP #$FF
|
||||
BEQ BINARY.FILE
|
||||
BOOTDISK.1
|
||||
STA 0
|
||||
CLC
|
||||
LDA $0402
|
||||
STA DBUFLO
|
||||
ADC #6
|
||||
STA 1
|
||||
LDA $0403
|
||||
STA DBUFHI
|
||||
ADC #0
|
||||
STA 2
|
||||
LDA $0404
|
||||
STA 3
|
||||
LDA $0405
|
||||
STA 4
|
||||
?L1
|
||||
JSR SIOV
|
||||
BMI HALT
|
||||
CLC
|
||||
LDA DBUFLO
|
||||
ADC #$80
|
||||
STA DBUFLO
|
||||
LDA DBUFHI
|
||||
ADC #0
|
||||
STA DBUFHI
|
||||
INC DAUX1
|
||||
BNE ?L2
|
||||
INC DAUX2
|
||||
?L2
|
||||
DEC 0
|
||||
BNE ?L1
|
||||
DEC 5
|
||||
BPL ?L1
|
||||
JSR ?L3 ; Run initialisation code
|
||||
LDA #1
|
||||
STA BOOT
|
||||
JSR ?L4 ; Run main program
|
||||
RTS
|
||||
?L3
|
||||
JMP ($01)
|
||||
?L4
|
||||
JMP ($03)
|
||||
;
|
||||
BINARY.FILE
|
||||
;
|
||||
HALT
|
||||
LDA # <DLIST
|
||||
STA SDLSTL
|
||||
STA DLISTL
|
||||
LDA # >DLIST
|
||||
STA SDLSTH
|
||||
STA DLISTH
|
||||
LDA #$E0
|
||||
STA CHBASE
|
||||
STA CHBAS
|
||||
LDA #$22
|
||||
STA DMACTL
|
||||
STA SDMCTL
|
||||
LDA #$02
|
||||
STA CHACTL
|
||||
STA CHART
|
||||
LDA #$CA
|
||||
STA COLBK
|
||||
STA COLOR4
|
||||
LDA #$94
|
||||
STA COLPF2
|
||||
STA COLOR2
|
||||
LDA #$0A
|
||||
STA COLPF1
|
||||
STA COLOR1
|
||||
;
|
||||
HALT2
|
||||
JMP HALT2
|
||||
DLIST
|
||||
.BYTE $70,$70,$70
|
||||
.BYTE $42, <HALTMSG, >HALTMSG
|
||||
.BYTE $02,$02,$02,$02,$02
|
||||
.BYTE $02,$02,$02,$02,$02
|
||||
.BYTE $02,$02,$02,$02,$02
|
||||
.BYTE $02,$02,$02,$02,$02
|
||||
.BYTE $02,$02,$02
|
||||
.BYTE $41, <DLIST, >DLIST
|
||||
;
|
||||
HALTMSG
|
||||
.SBYTE " Atari800/OS Emulation Halted "
|
||||
.SBYTE " Copyright (c) 1997 David J. Firth "
|
||||
.SBYTE "(c) 1998-2009 Atari800 Development Team "
|
||||
.SBYTE " "
|
||||
.SBYTE " http://atari800.atari.org/ "
|
||||
.SBYTE " "
|
||||
.SBYTE "Sorry this program needs a real Atari/OS"
|
||||
.SBYTE " Visit the Web pages to find out more "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
.SBYTE " "
|
||||
;
|
||||
NMI
|
||||
BIT NMIST
|
||||
BPL VBI
|
||||
JMP ($0200)
|
||||
VBI
|
||||
PHA
|
||||
TXA
|
||||
PHA
|
||||
TYA
|
||||
PHA
|
||||
STA NMIRES
|
||||
JMP (VVBLKI)
|
||||
SYSVBL
|
||||
INC RTCLOK+2
|
||||
BNE SYSVBL.1
|
||||
INC RTCLOK+1
|
||||
BNE SYSVBL.1
|
||||
INC RTCLOK
|
||||
SYSVBL.1
|
||||
LDA SDMCTL
|
||||
STA DMACTL
|
||||
LDA SDLSTL
|
||||
STA DLISTL
|
||||
LDA SDLSTH
|
||||
STA DLISTH
|
||||
LDA COLOR4
|
||||
STA COLBK
|
||||
LDA COLOR0
|
||||
STA COLPF0
|
||||
LDA COLOR1
|
||||
STA COLPF1
|
||||
LDA COLOR2
|
||||
STA COLPF2
|
||||
LDA COLOR3
|
||||
STA COLPF3
|
||||
LDA PCOLR0
|
||||
STA COLPM0
|
||||
LDA PCOLR1
|
||||
STA COLPM1
|
||||
LDA PCOLR2
|
||||
STA COLPM2
|
||||
LDA PCOLR3
|
||||
STA COLPM3
|
||||
LDA CHART
|
||||
STA CHACTL
|
||||
LDA CHBAS
|
||||
STA CHBASE
|
||||
LDA PORTA
|
||||
AND #$0F
|
||||
STA STICK0
|
||||
LDA PORTA
|
||||
ASL A
|
||||
ASL A
|
||||
ASL A
|
||||
ASL A
|
||||
STA STICK1
|
||||
LDA PORTB
|
||||
AND #$0F
|
||||
STA STICK2
|
||||
LDA PORTB
|
||||
ASL A
|
||||
ASL A
|
||||
ASL A
|
||||
ASL A
|
||||
STA STICK3
|
||||
LDA GPRIOR
|
||||
STA PRIOR
|
||||
LDA SSKCTL
|
||||
STA SKCTL
|
||||
LDA TRIG0
|
||||
STA STRIG0
|
||||
LDA TRIG1
|
||||
STA STRIG1
|
||||
LDA TRIG2
|
||||
STA STRIG2
|
||||
LDA TRIG3
|
||||
STA STRIG3
|
||||
JMP (VVBLKD)
|
||||
XITVBL
|
||||
PLA
|
||||
TAY
|
||||
PLA
|
||||
TAX
|
||||
PLA
|
||||
IRQ.VECTOR
|
||||
JMP ($0216)
|
||||
IRQ
|
||||
PHA
|
||||
LDA IRQST ; Get Interrupt Status
|
||||
AND #$40
|
||||
BNE IRQ.EXIT
|
||||
LDA KBCODE
|
||||
STA CH
|
||||
IRQ.EXIT
|
||||
PLA
|
||||
RTI
|
||||
;
|
||||
*= $FFFA
|
||||
.WORD NMI
|
||||
*= $FFFC
|
||||
.WORD COLDSTART
|
||||
*= $FFFE
|
||||
.WORD IRQ.VECTOR
|
||||
@@ -1,197 +0,0 @@
|
||||
/*
|
||||
* esc.c - Patch the OS with escape sequences
|
||||
*
|
||||
* Copyright (c) 1995-1998 David Firth
|
||||
* Copyright (c) 1998-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "atari.h"
|
||||
#include "cassette.h"
|
||||
#include "cpu.h"
|
||||
#include "devices.h"
|
||||
#include "esc.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "pia.h"
|
||||
#include "sio.h"
|
||||
#include "ui.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
int ESC_enable_sio_patch = TRUE;
|
||||
|
||||
/* Now we check address of every escape code, to make sure that the patch
|
||||
has been set by the emulator and is not a CIM in Atari program.
|
||||
Also switch() for escape codes has been changed to array of pointers
|
||||
to functions. This allows adding port-specific patches (e.g. modem device)
|
||||
using ESC_Add, Devices_UpdateHATABSEntry etc. without modifying
|
||||
atari.c/devices.c. Unfortunately it can't be done for patches in Atari OS,
|
||||
because the OS in XL/XE can be disabled.
|
||||
*/
|
||||
static UWORD esc_address[256];
|
||||
static ESC_FunctionType esc_function[256];
|
||||
|
||||
void ESC_ClearAll(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 256; i++)
|
||||
esc_function[i] = NULL;
|
||||
}
|
||||
|
||||
void ESC_Add(UWORD address, UBYTE esc_code, ESC_FunctionType function)
|
||||
{
|
||||
esc_address[esc_code] = address;
|
||||
esc_function[esc_code] = function;
|
||||
MEMORY_dPutByte(address, 0xf2); /* ESC */
|
||||
MEMORY_dPutByte(address + 1, esc_code); /* ESC CODE */
|
||||
}
|
||||
|
||||
void ESC_AddEscRts(UWORD address, UBYTE esc_code, ESC_FunctionType function)
|
||||
{
|
||||
esc_address[esc_code] = address;
|
||||
esc_function[esc_code] = function;
|
||||
MEMORY_dPutByte(address, 0xf2); /* ESC */
|
||||
MEMORY_dPutByte(address + 1, esc_code); /* ESC CODE */
|
||||
MEMORY_dPutByte(address + 2, 0x60); /* RTS */
|
||||
}
|
||||
|
||||
/* 0xd2 is ESCRTS, which works same as pair of ESC and RTS (I think so...).
|
||||
So this function does effectively the same as ESC_AddEscRts,
|
||||
except that it modifies 2, not 3 bytes in Atari memory.
|
||||
I don't know why it is done that way, so I simply leave it
|
||||
unchanged (0xf2/0xd2 are used as in previous versions).
|
||||
*/
|
||||
void ESC_AddEscRts2(UWORD address, UBYTE esc_code, ESC_FunctionType function)
|
||||
{
|
||||
esc_address[esc_code] = address;
|
||||
esc_function[esc_code] = function;
|
||||
MEMORY_dPutByte(address, 0xd2); /* ESCRTS */
|
||||
MEMORY_dPutByte(address + 1, esc_code); /* ESC CODE */
|
||||
}
|
||||
|
||||
void ESC_Remove(UBYTE esc_code)
|
||||
{
|
||||
esc_function[esc_code] = NULL;
|
||||
}
|
||||
|
||||
void ESC_Run(UBYTE esc_code)
|
||||
{
|
||||
if (esc_address[esc_code] == CPU_regPC - 2 && esc_function[esc_code] != NULL) {
|
||||
esc_function[esc_code]();
|
||||
return;
|
||||
}
|
||||
#ifdef CRASH_MENU
|
||||
CPU_regPC -= 2;
|
||||
UI_crash_address = CPU_regPC;
|
||||
UI_crash_afterCIM = CPU_regPC + 2;
|
||||
UI_crash_code = MEMORY_dGetByte(UI_crash_address);
|
||||
UI_Run();
|
||||
#else /* CRASH_MENU */
|
||||
CPU_cim_encountered = 1;
|
||||
Log_print("Invalid ESC code %02x at address %04x", esc_code, CPU_regPC - 2);
|
||||
#ifndef __PLUS
|
||||
if (!Atari800_Exit(TRUE))
|
||||
exit(0);
|
||||
#else /* __PLUS */
|
||||
Atari800_Exit(TRUE);
|
||||
#endif /* __PLUS */
|
||||
#endif /* CRASH_MENU */
|
||||
}
|
||||
|
||||
void ESC_PatchOS(void)
|
||||
{
|
||||
int patched = Devices_PatchOS();
|
||||
if (ESC_enable_sio_patch) {
|
||||
UWORD addr_l;
|
||||
UWORD addr_s;
|
||||
UBYTE check_s_0;
|
||||
UBYTE check_s_1;
|
||||
/* patch Open() of C: so we know when a leader is processed */
|
||||
switch (Atari800_machine_type) {
|
||||
case Atari800_MACHINE_OSA:
|
||||
case Atari800_MACHINE_OSB:
|
||||
addr_l = 0xef74;
|
||||
addr_s = 0xefbc;
|
||||
check_s_0 = 0xa0;
|
||||
check_s_1 = 0x80;
|
||||
break;
|
||||
case Atari800_MACHINE_XLXE:
|
||||
addr_l = 0xfd13;
|
||||
addr_s = 0xfd60;
|
||||
check_s_0 = 0xa9;
|
||||
check_s_1 = 0x03;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
/* don't hurt non-standard OSes that may not support cassette at all */
|
||||
if (MEMORY_dGetByte(addr_l) == 0xa9 && MEMORY_dGetByte(addr_l + 1) == 0x03
|
||||
&& MEMORY_dGetByte(addr_l + 2) == 0x8d && MEMORY_dGetByte(addr_l + 3) == 0x2a
|
||||
&& MEMORY_dGetByte(addr_l + 4) == 0x02
|
||||
&& MEMORY_dGetByte(addr_s) == check_s_0
|
||||
&& MEMORY_dGetByte(addr_s + 1) == check_s_1
|
||||
&& MEMORY_dGetByte(addr_s + 2) == 0x20 && MEMORY_dGetByte(addr_s + 3) == 0x5c
|
||||
&& MEMORY_dGetByte(addr_s + 4) == 0xe4) {
|
||||
ESC_Add(addr_l, ESC_COPENLOAD, CASSETTE_LeaderLoad);
|
||||
ESC_Add(addr_s, ESC_COPENSAVE, CASSETTE_LeaderSave);
|
||||
}
|
||||
ESC_AddEscRts(0xe459, ESC_SIOV, SIO_Handler);
|
||||
patched = TRUE;
|
||||
}
|
||||
else {
|
||||
ESC_Remove(ESC_COPENLOAD);
|
||||
ESC_Remove(ESC_COPENSAVE);
|
||||
ESC_Remove(ESC_SIOV);
|
||||
};
|
||||
if (patched && Atari800_machine_type == Atari800_MACHINE_XLXE) {
|
||||
/* Disable Checksum Test */
|
||||
MEMORY_dPutByte(0xc314, 0x8e);
|
||||
MEMORY_dPutByte(0xc315, 0xff);
|
||||
MEMORY_dPutByte(0xc319, 0x8e);
|
||||
MEMORY_dPutByte(0xc31a, 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
void ESC_UpdatePatches(void)
|
||||
{
|
||||
switch (Atari800_machine_type) {
|
||||
case Atari800_MACHINE_OSA:
|
||||
case Atari800_MACHINE_OSB:
|
||||
/* Restore unpatched OS */
|
||||
MEMORY_dCopyToMem(MEMORY_os, 0xd800, 0x2800);
|
||||
/* Set patches */
|
||||
ESC_PatchOS();
|
||||
Devices_UpdatePatches();
|
||||
break;
|
||||
case Atari800_MACHINE_XLXE:
|
||||
/* Don't patch if OS disabled */
|
||||
if ((PIA_PORTB & 1) == 0)
|
||||
break;
|
||||
/* Restore unpatched OS */
|
||||
MEMORY_dCopyToMem(MEMORY_os, 0xc000, 0x1000);
|
||||
MEMORY_dCopyToMem(MEMORY_os + 0x1800, 0xd800, 0x2800);
|
||||
/* Set patches */
|
||||
ESC_PatchOS();
|
||||
Devices_UpdatePatches();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
#ifndef ESC_H_
|
||||
#define ESC_H_
|
||||
|
||||
/* TRUE to enable patched (fast) Serial I/O. */
|
||||
extern int ESC_enable_sio_patch;
|
||||
|
||||
/* Escape codes used to mark places in 6502 code that must
|
||||
be handled specially by the emulator. An escape sequence
|
||||
is an illegal 6502 opcode 0xF2 or 0xD2 followed
|
||||
by one of these escape codes: */
|
||||
enum ESC_t {
|
||||
|
||||
/* SIO patch. */
|
||||
ESC_SIOV,
|
||||
|
||||
/* stdio-based handlers for the BASIC version
|
||||
and handlers for Atari Basic loader. */
|
||||
ESC_EHOPEN,
|
||||
ESC_EHCLOS,
|
||||
ESC_EHREAD,
|
||||
ESC_EHWRIT,
|
||||
ESC_EHSTAT,
|
||||
ESC_EHSPEC,
|
||||
|
||||
ESC_KHOPEN,
|
||||
ESC_KHCLOS,
|
||||
ESC_KHREAD,
|
||||
ESC_KHWRIT,
|
||||
ESC_KHSTAT,
|
||||
ESC_KHSPEC,
|
||||
|
||||
/* Atari executable loader. */
|
||||
ESC_BINLOADER_CONT,
|
||||
|
||||
/* Cassette emulation. */
|
||||
ESC_COPENLOAD = 0xa8,
|
||||
ESC_COPENSAVE = 0xa9,
|
||||
|
||||
/* Printer. */
|
||||
ESC_PHOPEN = 0xb0,
|
||||
ESC_PHCLOS = 0xb1,
|
||||
ESC_PHREAD = 0xb2,
|
||||
ESC_PHWRIT = 0xb3,
|
||||
ESC_PHSTAT = 0xb4,
|
||||
ESC_PHSPEC = 0xb5,
|
||||
ESC_PHINIT = 0xb6,
|
||||
|
||||
#ifdef R_IO_DEVICE
|
||||
/* R: device. */
|
||||
ESC_ROPEN = 0xd0,
|
||||
ESC_RCLOS = 0xd1,
|
||||
ESC_RREAD = 0xd2,
|
||||
ESC_RWRIT = 0xd3,
|
||||
ESC_RSTAT = 0xd4,
|
||||
ESC_RSPEC = 0xd5,
|
||||
ESC_RINIT = 0xd6,
|
||||
#endif
|
||||
|
||||
/* H: device. */
|
||||
ESC_HHOPEN = 0xc0,
|
||||
ESC_HHCLOS = 0xc1,
|
||||
ESC_HHREAD = 0xc2,
|
||||
ESC_HHWRIT = 0xc3,
|
||||
ESC_HHSTAT = 0xc4,
|
||||
ESC_HHSPEC = 0xc5,
|
||||
ESC_HHINIT = 0xc6
|
||||
};
|
||||
|
||||
/* A function called to handle an escape sequence. */
|
||||
typedef void (*ESC_FunctionType)(void);
|
||||
|
||||
/* Puts an escape sequence at the specified address. */
|
||||
void ESC_Add(UWORD address, UBYTE esc_code, ESC_FunctionType function);
|
||||
|
||||
/* Puts an escape sequence followed by the RTS instruction. */
|
||||
void ESC_AddEscRts(UWORD address, UBYTE esc_code, ESC_FunctionType function);
|
||||
|
||||
/* Puts an escape sequence with an integrated RTS. */
|
||||
void ESC_AddEscRts2(UWORD address, UBYTE esc_code, ESC_FunctionType function);
|
||||
|
||||
/* Unregisters an escape sequence. You must cleanup the Atari memory yourself. */
|
||||
void ESC_Remove(UBYTE esc_code);
|
||||
|
||||
/* Handles an escape sequence. */
|
||||
void ESC_Run(UBYTE esc_code);
|
||||
|
||||
/* Installs SIO patch and disables ROM checksum test. */
|
||||
void ESC_PatchOS(void);
|
||||
|
||||
/* Unregisters all escape sequences */
|
||||
void ESC_ClearAll(void);
|
||||
|
||||
/* Reinitializes patches after enable_*_patch change. */
|
||||
void ESC_UpdatePatches(void);
|
||||
|
||||
#endif /* ESC_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,139 +0,0 @@
|
||||
#ifndef GTIA_H_
|
||||
#define GTIA_H_
|
||||
|
||||
#include "atari.h"
|
||||
#include "screen.h"
|
||||
|
||||
#define GTIA_OFFSET_HPOSP0 0x00
|
||||
#define GTIA_OFFSET_M0PF 0x00
|
||||
#define GTIA_OFFSET_HPOSP1 0x01
|
||||
#define GTIA_OFFSET_M1PF 0x01
|
||||
#define GTIA_OFFSET_HPOSP2 0x02
|
||||
#define GTIA_OFFSET_M2PF 0x02
|
||||
#define GTIA_OFFSET_HPOSP3 0x03
|
||||
#define GTIA_OFFSET_M3PF 0x03
|
||||
#define GTIA_OFFSET_HPOSM0 0x04
|
||||
#define GTIA_OFFSET_P0PF 0x04
|
||||
#define GTIA_OFFSET_HPOSM1 0x05
|
||||
#define GTIA_OFFSET_P1PF 0x05
|
||||
#define GTIA_OFFSET_HPOSM2 0x06
|
||||
#define GTIA_OFFSET_P2PF 0x06
|
||||
#define GTIA_OFFSET_HPOSM3 0x07
|
||||
#define GTIA_OFFSET_P3PF 0x07
|
||||
#define GTIA_OFFSET_SIZEP0 0x08
|
||||
#define GTIA_OFFSET_M0PL 0x08
|
||||
#define GTIA_OFFSET_SIZEP1 0x09
|
||||
#define GTIA_OFFSET_M1PL 0x09
|
||||
#define GTIA_OFFSET_SIZEP2 0x0a
|
||||
#define GTIA_OFFSET_M2PL 0x0a
|
||||
#define GTIA_OFFSET_SIZEP3 0x0b
|
||||
#define GTIA_OFFSET_M3PL 0x0b
|
||||
#define GTIA_OFFSET_SIZEM 0x0c
|
||||
#define GTIA_OFFSET_P0PL 0x0c
|
||||
#define GTIA_OFFSET_GRAFP0 0x0d
|
||||
#define GTIA_OFFSET_P1PL 0x0d
|
||||
#define GTIA_OFFSET_GRAFP1 0x0e
|
||||
#define GTIA_OFFSET_P2PL 0x0e
|
||||
#define GTIA_OFFSET_GRAFP2 0x0f
|
||||
#define GTIA_OFFSET_P3PL 0x0f
|
||||
#define GTIA_OFFSET_GRAFP3 0x10
|
||||
#define GTIA_OFFSET_TRIG0 0x10
|
||||
#define GTIA_OFFSET_GRAFM 0x11
|
||||
#define GTIA_OFFSET_TRIG1 0x11
|
||||
#define GTIA_OFFSET_COLPM0 0x12
|
||||
#define GTIA_OFFSET_TRIG2 0x12
|
||||
#define GTIA_OFFSET_COLPM1 0x13
|
||||
#define GTIA_OFFSET_TRIG3 0x13
|
||||
#define GTIA_OFFSET_COLPM2 0x14
|
||||
#define GTIA_OFFSET_PAL 0x14
|
||||
#define GTIA_OFFSET_COLPM3 0x15
|
||||
#define GTIA_OFFSET_COLPF0 0x16
|
||||
#define GTIA_OFFSET_COLPF1 0x17
|
||||
#define GTIA_OFFSET_COLPF2 0x18
|
||||
#define GTIA_OFFSET_COLPF3 0x19
|
||||
#define GTIA_OFFSET_COLBK 0x1a
|
||||
#define GTIA_OFFSET_PRIOR 0x1b
|
||||
#define GTIA_OFFSET_VDELAY 0x1c
|
||||
#define GTIA_OFFSET_GRACTL 0x1d
|
||||
#define GTIA_OFFSET_HITCLR 0x1e
|
||||
#define GTIA_OFFSET_CONSOL 0x1f
|
||||
|
||||
extern UBYTE GTIA_GRAFM;
|
||||
extern UBYTE GTIA_GRAFP0;
|
||||
extern UBYTE GTIA_GRAFP1;
|
||||
extern UBYTE GTIA_GRAFP2;
|
||||
extern UBYTE GTIA_GRAFP3;
|
||||
extern UBYTE GTIA_HPOSP0;
|
||||
extern UBYTE GTIA_HPOSP1;
|
||||
extern UBYTE GTIA_HPOSP2;
|
||||
extern UBYTE GTIA_HPOSP3;
|
||||
extern UBYTE GTIA_HPOSM0;
|
||||
extern UBYTE GTIA_HPOSM1;
|
||||
extern UBYTE GTIA_HPOSM2;
|
||||
extern UBYTE GTIA_HPOSM3;
|
||||
extern UBYTE GTIA_SIZEP0;
|
||||
extern UBYTE GTIA_SIZEP1;
|
||||
extern UBYTE GTIA_SIZEP2;
|
||||
extern UBYTE GTIA_SIZEP3;
|
||||
extern UBYTE GTIA_SIZEM;
|
||||
extern UBYTE GTIA_COLPM0;
|
||||
extern UBYTE GTIA_COLPM1;
|
||||
extern UBYTE GTIA_COLPM2;
|
||||
extern UBYTE GTIA_COLPM3;
|
||||
extern UBYTE GTIA_COLPF0;
|
||||
extern UBYTE GTIA_COLPF1;
|
||||
extern UBYTE GTIA_COLPF2;
|
||||
extern UBYTE GTIA_COLPF3;
|
||||
extern UBYTE GTIA_COLBK;
|
||||
extern UBYTE GTIA_GRACTL;
|
||||
extern UBYTE GTIA_M0PL;
|
||||
extern UBYTE GTIA_M1PL;
|
||||
extern UBYTE GTIA_M2PL;
|
||||
extern UBYTE GTIA_M3PL;
|
||||
extern UBYTE GTIA_P0PL;
|
||||
extern UBYTE GTIA_P1PL;
|
||||
extern UBYTE GTIA_P2PL;
|
||||
extern UBYTE GTIA_P3PL;
|
||||
extern UBYTE GTIA_PRIOR;
|
||||
extern UBYTE GTIA_VDELAY;
|
||||
|
||||
#ifdef USE_COLOUR_TRANSLATION_TABLE
|
||||
|
||||
extern UWORD GTIA_colour_translation_table[256];
|
||||
#define GTIA_COLOUR_BLACK GTIA_colour_translation_table[0]
|
||||
#define GTIA_COLOUR_TO_WORD(dest,src) dest = GTIA_colour_translation_table[src];
|
||||
|
||||
#else
|
||||
|
||||
#define GTIA_COLOUR_BLACK 0
|
||||
#define GTIA_COLOUR_TO_WORD(dest,src) dest = (((UWORD) (src)) << 8) | (src);
|
||||
|
||||
#endif /* USE_COLOUR_TRANSLATION_TABLE */
|
||||
|
||||
extern UBYTE GTIA_pm_scanline[Screen_WIDTH / 2 + 8]; /* there's a byte for every *pair* of pixels */
|
||||
extern int GTIA_pm_dirty;
|
||||
|
||||
extern UBYTE GTIA_collisions_mask_missile_playfield;
|
||||
extern UBYTE GTIA_collisions_mask_player_playfield;
|
||||
extern UBYTE GTIA_collisions_mask_missile_player;
|
||||
extern UBYTE GTIA_collisions_mask_player_player;
|
||||
|
||||
extern UBYTE GTIA_TRIG[4];
|
||||
extern UBYTE GTIA_TRIG_latch[4];
|
||||
|
||||
extern int GTIA_consol_index;
|
||||
extern UBYTE GTIA_consol_table[3];
|
||||
extern int GTIA_speaker;
|
||||
|
||||
int GTIA_Initialise(int *argc, char *argv[]);
|
||||
void GTIA_Frame(void);
|
||||
void GTIA_NewPmScanline(void);
|
||||
UBYTE GTIA_GetByte(UWORD addr);
|
||||
void GTIA_PutByte(UWORD addr, UBYTE byte);
|
||||
void GTIA_StateSave(void);
|
||||
void GTIA_StateRead(void);
|
||||
|
||||
#ifdef NEW_CYCLE_EXACT
|
||||
void GTIA_UpdatePmplColls(void);
|
||||
#endif
|
||||
#endif /* GTIA_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,93 +0,0 @@
|
||||
#ifndef INPUT_H_
|
||||
#define INPUT_H_
|
||||
|
||||
/* Keyboard AKEY_* are in akey.h */
|
||||
|
||||
/* INPUT_key_consol masks */
|
||||
/* Note: INPUT_key_consol should be INPUT_CONSOL_NONE if no consol key is pressed.
|
||||
When a consol key is pressed, corresponding bit should be cleared.
|
||||
*/
|
||||
#define INPUT_CONSOL_NONE 0x07
|
||||
#define INPUT_CONSOL_START 0x01
|
||||
#define INPUT_CONSOL_SELECT 0x02
|
||||
#define INPUT_CONSOL_OPTION 0x04
|
||||
|
||||
extern int INPUT_key_code; /* regular Atari key code */
|
||||
extern int INPUT_key_shift; /* Shift key pressed */
|
||||
extern int INPUT_key_consol; /* Start, Select and Option keys */
|
||||
|
||||
/* Joysticks ----------------------------------------------------------- */
|
||||
|
||||
/* joystick position */
|
||||
#define INPUT_STICK_LL 0x09
|
||||
#define INPUT_STICK_BACK 0x0d
|
||||
#define INPUT_STICK_LR 0x05
|
||||
#define INPUT_STICK_LEFT 0x0b
|
||||
#define INPUT_STICK_CENTRE 0x0f
|
||||
#define INPUT_STICK_RIGHT 0x07
|
||||
#define INPUT_STICK_UL 0x0a
|
||||
#define INPUT_STICK_FORWARD 0x0e
|
||||
#define INPUT_STICK_UR 0x06
|
||||
|
||||
/* joy_autofire values */
|
||||
#define INPUT_AUTOFIRE_OFF 0
|
||||
#define INPUT_AUTOFIRE_FIRE 1 /* Fire dependent */
|
||||
#define INPUT_AUTOFIRE_CONT 2 /* Continuous */
|
||||
|
||||
extern int INPUT_joy_autofire[4]; /* autofire mode for each Atari port */
|
||||
|
||||
extern int INPUT_joy_block_opposite_directions; /* can't move joystick left
|
||||
and right simultaneously */
|
||||
|
||||
extern int INPUT_joy_multijoy; /* emulate MultiJoy4 interface */
|
||||
|
||||
/* 5200 joysticks values */
|
||||
extern int INPUT_joy_5200_min;
|
||||
extern int INPUT_joy_5200_center;
|
||||
extern int INPUT_joy_5200_max;
|
||||
|
||||
/* Mouse --------------------------------------------------------------- */
|
||||
|
||||
/* INPUT_mouse_mode values */
|
||||
#define INPUT_MOUSE_OFF 0
|
||||
#define INPUT_MOUSE_PAD 1 /* Paddles */
|
||||
#define INPUT_MOUSE_TOUCH 2 /* Atari touch tablet */
|
||||
#define INPUT_MOUSE_KOALA 3 /* Koala pad */
|
||||
#define INPUT_MOUSE_PEN 4 /* Light pen */
|
||||
#define INPUT_MOUSE_GUN 5 /* Light gun */
|
||||
#define INPUT_MOUSE_AMIGA 6 /* Amiga mouse */
|
||||
#define INPUT_MOUSE_ST 7 /* Atari ST mouse */
|
||||
#define INPUT_MOUSE_TRAK 8 /* Atari CX22 Trak-Ball */
|
||||
#define INPUT_MOUSE_JOY 9 /* Joystick */
|
||||
|
||||
extern int INPUT_mouse_mode; /* device emulated with mouse */
|
||||
extern int INPUT_mouse_port; /* Atari port, to which the emulated device is attached */
|
||||
extern int INPUT_mouse_delta_x; /* x motion since last frame */
|
||||
extern int INPUT_mouse_delta_y; /* y motion since last frame */
|
||||
extern int INPUT_mouse_buttons; /* buttons pressed (b0: left, b1: right, b2: middle */
|
||||
extern int INPUT_mouse_speed; /* how fast the mouse pointer moves */
|
||||
extern int INPUT_mouse_pot_min; /* min. value of POKEY's POT register */
|
||||
extern int INPUT_mouse_pot_max; /* max. value of POKEY's POT register */
|
||||
extern int INPUT_mouse_pen_ofs_h; /* light pen/gun horizontal offset (for calibration) */
|
||||
extern int INPUT_mouse_pen_ofs_v; /* light pen/gun vertical offset (for calibration) */
|
||||
extern int INPUT_mouse_joy_inertia; /* how long the mouse pointer can move (time in Atari frames)
|
||||
after a fast motion of mouse */
|
||||
extern int INPUT_direct_mouse; /* When true, convert the mouse pointer
|
||||
position directly into POKEY POT values */
|
||||
|
||||
extern int INPUT_cx85; /* emulate CX85 numeric keypad */
|
||||
/* Functions ----------------------------------------------------------- */
|
||||
|
||||
int INPUT_Initialise(int *argc, char *argv[]);
|
||||
void INPUT_Exit(void);
|
||||
void INPUT_Frame(void);
|
||||
void INPUT_Scanline(void);
|
||||
void INPUT_SelectMultiJoy(int no);
|
||||
void INPUT_CenterMousePointer(void);
|
||||
void INPUT_DrawMousePointer(void);
|
||||
int INPUT_Recording(void);
|
||||
int INPUT_Playingback(void);
|
||||
void INPUT_RecordInt(int i);
|
||||
int INPUT_PlaybackInt(void);
|
||||
|
||||
#endif /* INPUT_H_ */
|
||||
@@ -1,238 +0,0 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# install - install a program, script, or datafile
|
||||
# This comes from X11R5.
|
||||
#
|
||||
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||
# `make' implicit rules from creating a file called install from it
|
||||
# when there is no Makefile.
|
||||
#
|
||||
# This script is compatible with the BSD install script, but was written
|
||||
# from scratch.
|
||||
#
|
||||
|
||||
|
||||
# set DOITPROG to echo to test this script
|
||||
|
||||
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||
doit="${DOITPROG-}"
|
||||
|
||||
|
||||
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||
|
||||
mvprog="${MVPROG-mv}"
|
||||
cpprog="${CPPROG-cp}"
|
||||
chmodprog="${CHMODPROG-chmod}"
|
||||
chownprog="${CHOWNPROG-chown}"
|
||||
chgrpprog="${CHGRPPROG-chgrp}"
|
||||
stripprog="${STRIPPROG-strip}"
|
||||
rmprog="${RMPROG-rm}"
|
||||
mkdirprog="${MKDIRPROG-mkdir}"
|
||||
|
||||
tranformbasename=""
|
||||
transform_arg=""
|
||||
instcmd="$mvprog"
|
||||
chmodcmd="$chmodprog 0755"
|
||||
chowncmd=""
|
||||
chgrpcmd=""
|
||||
stripcmd=""
|
||||
rmcmd="$rmprog -f"
|
||||
mvcmd="$mvprog"
|
||||
src=""
|
||||
dst=""
|
||||
dir_arg=""
|
||||
|
||||
while [ x"$1" != x ]; do
|
||||
case $1 in
|
||||
-c) instcmd="$cpprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-d) dir_arg=true
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-m) chmodcmd="$chmodprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-o) chowncmd="$chownprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-g) chgrpcmd="$chgrpprog $2"
|
||||
shift
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-s) stripcmd="$stripprog"
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||
shift
|
||||
continue;;
|
||||
|
||||
*) if [ x"$src" = x ]
|
||||
then
|
||||
src=$1
|
||||
else
|
||||
# this colon is to work around a 386BSD /bin/sh bug
|
||||
:
|
||||
dst=$1
|
||||
fi
|
||||
shift
|
||||
continue;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ x"$src" = x ]
|
||||
then
|
||||
echo "install: no input file specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]; then
|
||||
dst=$src
|
||||
src=""
|
||||
|
||||
if [ -d $dst ]; then
|
||||
instcmd=:
|
||||
else
|
||||
instcmd=mkdir
|
||||
fi
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
then
|
||||
true
|
||||
else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
exit 1
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# If destination is a directory, append the input filename; if your system
|
||||
# does not like double slashes in filenames, you may need to add some logic
|
||||
|
||||
if [ -d $dst ]
|
||||
then
|
||||
dst="$dst"/`basename $src`
|
||||
else
|
||||
true
|
||||
fi
|
||||
fi
|
||||
|
||||
## this sed command emulates the dirname command
|
||||
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Make sure that the destination directory exists.
|
||||
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
oIFS="${IFS}"
|
||||
# Some sh's can't handle IFS=/ for some reason.
|
||||
IFS='%'
|
||||
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||
IFS="${oIFS}"
|
||||
|
||||
pathcomp=''
|
||||
|
||||
while [ $# -ne 0 ] ; do
|
||||
pathcomp="${pathcomp}${1}"
|
||||
shift
|
||||
|
||||
if [ ! -d "${pathcomp}" ] ;
|
||||
then
|
||||
$mkdirprog "${pathcomp}"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
pathcomp="${pathcomp}/"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ x"$dir_arg" != x ]
|
||||
then
|
||||
$doit $instcmd $dst &&
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||
else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
# Make a temp file name in the proper directory.
|
||||
|
||||
dsttmp=$dstdir/#inst.$$#
|
||||
|
||||
# Move or copy the file name to the temp name
|
||||
|
||||
$doit $instcmd $src $dsttmp &&
|
||||
|
||||
trap "rm -f ${dsttmp}" 0 &&
|
||||
|
||||
# and set any options; do chmod last to preserve setuid bits
|
||||
|
||||
# If any of these fail, we abort the whole thing. If we want to
|
||||
# ignore errors from any of these, just make sure not to ignore
|
||||
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||
|
||||
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
exit 0
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* log.c - A logging facility for debugging
|
||||
*
|
||||
* Copyright (C) 1995-1998 David Firth
|
||||
* Copyright (C) 1998-2005 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#ifdef MACOSX
|
||||
# define PRINT(a) ControlManagerMessagePrint(a)
|
||||
#elif defined(ANDROID)
|
||||
# define PRINT(a) __android_log_print(ANDROID_LOG_INFO, "atari800", a);
|
||||
#else
|
||||
# define PRINT(a) printf("%s", a)
|
||||
#endif
|
||||
|
||||
#ifdef BUFFERED_LOG
|
||||
char Log_buffer[Log_BUFFER_SIZE] = "";
|
||||
#endif
|
||||
|
||||
void Log_print(char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buffer[8192];
|
||||
#ifdef BUFFERED_LOG
|
||||
int buflen;
|
||||
#endif
|
||||
|
||||
va_start(args, format);
|
||||
#ifdef HAVE_VSNPRINTF
|
||||
vsnprintf(buffer, sizeof(buffer) - 2 /* -2 for the strcat() */, format, args);
|
||||
#else
|
||||
vsprintf(buffer, format, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
|
||||
#ifdef __PLUS
|
||||
strcat(buffer, "\r\n");
|
||||
#else
|
||||
strcat(buffer, "\n");
|
||||
#endif
|
||||
|
||||
#ifdef BUFFERED_LOG
|
||||
buflen = strlen(buffer);
|
||||
|
||||
if ((strlen(Log_buffer) + strlen(buffer) + 1) > Log_BUFFER_SIZE)
|
||||
*Log_buffer = 0;
|
||||
|
||||
strcat(Log_buffer, buffer);
|
||||
#else
|
||||
PRINT(buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Log_flushlog(void)
|
||||
{
|
||||
#ifdef BUFFERED_LOG
|
||||
if (*Log_buffer) {
|
||||
PRINT(Log_buffer);
|
||||
*Log_buffer = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef LOG_H_
|
||||
#define LOG_H_
|
||||
|
||||
#define Log_BUFFER_SIZE 8192
|
||||
extern char Log_buffer[Log_BUFFER_SIZE];
|
||||
|
||||
void Log_print(char *format, ...);
|
||||
void Log_flushlog(void);
|
||||
|
||||
#endif /* LOG_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,125 +0,0 @@
|
||||
#ifndef MEMORY_H_
|
||||
#define MEMORY_H_
|
||||
|
||||
#include "config.h"
|
||||
#include <string.h> /* memcpy, memset */
|
||||
|
||||
#include "atari.h"
|
||||
|
||||
#define MEMORY_dGetByte(x) (MEMORY_mem[x])
|
||||
#define MEMORY_dPutByte(x, y) (MEMORY_mem[x] = y)
|
||||
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
#ifdef WORDS_UNALIGNED_OK
|
||||
#define MEMORY_dGetWord(x) UNALIGNED_GET_WORD(&MEMORY_mem[x], memory_read_word_stat)
|
||||
#define MEMORY_dPutWord(x, y) UNALIGNED_PUT_WORD(&MEMORY_mem[x], (y), memory_write_word_stat)
|
||||
#define MEMORY_dGetWordAligned(x) UNALIGNED_GET_WORD(&MEMORY_mem[x], memory_read_aligned_word_stat)
|
||||
#define MEMORY_dPutWordAligned(x, y) UNALIGNED_PUT_WORD(&MEMORY_mem[x], (y), memory_write_aligned_word_stat)
|
||||
#else /* WORDS_UNALIGNED_OK */
|
||||
#define MEMORY_dGetWord(x) (MEMORY_mem[x] + (MEMORY_mem[(x) + 1] << 8))
|
||||
#define MEMORY_dPutWord(x, y) (MEMORY_mem[x] = (UBYTE) (y), MEMORY_mem[(x) + 1] = (UBYTE) ((y) >> 8))
|
||||
/* faster versions of MEMORY_jdGetWord and MEMORY_dPutWord for even addresses */
|
||||
/* TODO: guarantee that memory is UWORD-aligned and use UWORD access */
|
||||
#define MEMORY_dGetWordAligned(x) MEMORY_dGetWord(x)
|
||||
#define MEMORY_dPutWordAligned(x, y) MEMORY_dPutWord(x, y)
|
||||
#endif /* WORDS_UNALIGNED_OK */
|
||||
#else /* WORDS_BIGENDIAN */
|
||||
/* can't do any word optimizations for big endian machines */
|
||||
#define MEMORY_dGetWord(x) (MEMORY_mem[x] + (MEMORY_mem[(x) + 1] << 8))
|
||||
#define MEMORY_dPutWord(x, y) (MEMORY_mem[x] = (UBYTE) (y), MEMORY_mem[(x) + 1] = (UBYTE) ((y) >> 8))
|
||||
#define MEMORY_dGetWordAligned(x) MEMORY_dGetWord(x)
|
||||
#define MEMORY_dPutWordAligned(x, y) MEMORY_dPutWord(x, y)
|
||||
#endif /* WORDS_BIGENDIAN */
|
||||
|
||||
#define MEMORY_dCopyFromMem(from, to, size) memcpy(to, MEMORY_mem + (from), size)
|
||||
#define MEMORY_dCopyToMem(from, to, size) memcpy(MEMORY_mem + (to), from, size)
|
||||
#define MEMORY_dFillMem(addr1, value, length) memset(MEMORY_mem + (addr1), value, length)
|
||||
|
||||
extern UBYTE MEMORY_mem[65536 + 2];
|
||||
|
||||
/* RAM size in kilobytes.
|
||||
Valid values for Atari800_MACHINE_OSA and Atari800_MACHINE_OSB are: 16, 48, 52.
|
||||
Valid values for Atari800_MACHINE_XLXE are: 16, 64, 128, 192, RAM_320_RAMBO,
|
||||
RAM_320_COMPY_SHOP, 576, 1088.
|
||||
The only valid value for Atari800_MACHINE_5200 is 16. */
|
||||
#define MEMORY_RAM_320_RAMBO 320
|
||||
#define MEMORY_RAM_320_COMPY_SHOP 321
|
||||
extern int MEMORY_ram_size;
|
||||
|
||||
#define MEMORY_RAM 0
|
||||
#define MEMORY_ROM 1
|
||||
#define MEMORY_HARDWARE 2
|
||||
|
||||
#ifndef PAGED_ATTRIB
|
||||
|
||||
extern UBYTE MEMORY_attrib[65536];
|
||||
#define MEMORY_GetByte(addr) (MEMORY_attrib[addr] == MEMORY_HARDWARE ? MEMORY_HwGetByte(addr) : MEMORY_mem[addr])
|
||||
#define MEMORY_PutByte(addr, byte) do { if (MEMORY_attrib[addr] == MEMORY_RAM) MEMORY_mem[addr] = byte; else if (MEMORY_attrib[addr] == MEMORY_HARDWARE) MEMORY_HwPutByte(addr, byte); } while (0)
|
||||
#define MEMORY_SetRAM(addr1, addr2) memset(MEMORY_attrib + (addr1), MEMORY_RAM, (addr2) - (addr1) + 1)
|
||||
#define MEMORY_SetROM(addr1, addr2) memset(MEMORY_attrib + (addr1), MEMORY_ROM, (addr2) - (addr1) + 1)
|
||||
#define MEMORY_SetHARDWARE(addr1, addr2) memset(MEMORY_attrib + (addr1), MEMORY_HARDWARE, (addr2) - (addr1) + 1)
|
||||
|
||||
#else /* PAGED_ATTRIB */
|
||||
|
||||
typedef UBYTE (*MEMORY_rdfunc)(UWORD addr);
|
||||
typedef void (*MEMORY_wrfunc)(UWORD addr, UBYTE value);
|
||||
extern MEMORY_rdfunc MEMORY_readmap[256];
|
||||
extern MEMORY_wrfunc MEMORY_writemap[256];
|
||||
void MEMORY_ROM_PutByte(UWORD addr, UBYTE byte);
|
||||
#define MEMORY_GetByte(addr) (MEMORY_readmap[(addr) >> 8] ? (*MEMORY_readmap[(addr) >> 8])(addr) : MEMORY_mem[addr])
|
||||
#define MEMORY_PutByte(addr,byte) (MEMORY_writemap[(addr) >> 8] ? ((*MEMORY_writemap[(addr) >> 8])(addr, byte), 0) : (MEMORY_mem[addr] = byte))
|
||||
#define MEMORY_SetRAM(addr1, addr2) do { \
|
||||
int i; \
|
||||
for (i = (addr1) >> 8; i <= (addr2) >> 8; i++) { \
|
||||
MEMORY_readmap[i] = NULL; \
|
||||
MEMORY_writemap[i] = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
#define MEMORY_SetROM(addr1, addr2) do { \
|
||||
int i; \
|
||||
for (i = (addr1) >> 8; i <= (addr2) >> 8; i++) { \
|
||||
MEMORY_readmap[i] = NULL; \
|
||||
MEMORY_writemap[i] = MEMORY_ROM_PutByte; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* PAGED_ATTRIB */
|
||||
|
||||
extern UBYTE MEMORY_basic[8192];
|
||||
extern UBYTE MEMORY_os[16384];
|
||||
|
||||
extern int MEMORY_xe_bank;
|
||||
extern int MEMORY_selftest_enabled;
|
||||
|
||||
extern int MEMORY_have_basic;
|
||||
extern int MEMORY_cartA0BF_enabled;
|
||||
|
||||
void MEMORY_InitialiseMachine(void);
|
||||
void MEMORY_StateSave(UBYTE SaveVerbose);
|
||||
void MEMORY_StateRead(UBYTE SaveVerbose, UBYTE StateVersion);
|
||||
void MEMORY_CopyFromMem(UWORD from, UBYTE *to, int size);
|
||||
void MEMORY_CopyToMem(const UBYTE *from, UWORD to, int size);
|
||||
void MEMORY_HandlePORTB(UBYTE byte, UBYTE oldval);
|
||||
void MEMORY_Cart809fDisable(void);
|
||||
void MEMORY_Cart809fEnable(void);
|
||||
void MEMORY_CartA0bfDisable(void);
|
||||
void MEMORY_CartA0bfEnable(void);
|
||||
#define MEMORY_CopyROM(addr1, addr2, src) memcpy(MEMORY_mem + (addr1), src, (addr2) - (addr1) + 1)
|
||||
void MEMORY_GetCharset(UBYTE *cs);
|
||||
|
||||
/* Mosaic and Axlon 400/800 RAM extensions */
|
||||
extern int MEMORY_mosaic_maxbank;
|
||||
extern int MEMORY_mosaic_enabled;
|
||||
extern int MEMORY_axlon_enabled;
|
||||
extern int MEMORY_axlon_0f_mirror;
|
||||
extern int MEMORY_axlon_bankmask;
|
||||
|
||||
#ifndef PAGED_MEM
|
||||
/* Reads a byte from the specified special address (not RAM or ROM). */
|
||||
UBYTE MEMORY_HwGetByte(UWORD addr);
|
||||
|
||||
/* Stores a byte at the specified special address (not RAM or ROM). */
|
||||
void MEMORY_HwPutByte(UWORD addr, UBYTE byte);
|
||||
#endif /* PAGED_MEM */
|
||||
|
||||
#endif /* MEMORY_H_ */
|
||||
@@ -1,208 +0,0 @@
|
||||
/*
|
||||
* mkimg.c - Make an image or .h file from a binary
|
||||
*
|
||||
* Copyright (C) 1995-1998 David Firth
|
||||
* Copyright (C) 1998-2005 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Usage: mkimg -input filename
|
||||
* -image filename
|
||||
* -header filename
|
||||
* hexaddr1
|
||||
* hexaddr2
|
||||
*
|
||||
* Loads the input file into a 64K area of memory. The
|
||||
* input file is in standard Atari Binary load format.
|
||||
* The memory is initially filled with zeros. After the
|
||||
* memory has been loaded the program creates either an
|
||||
* image file or a standard C header file that contains
|
||||
* the memory starting with hexaddr1 at going up to,
|
||||
* but not including, hexaddr2.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef enum {
|
||||
Expect_Header1,
|
||||
Expect_Header2,
|
||||
Expect_StartLo,
|
||||
Expect_StartHi,
|
||||
Expect_FinishLo,
|
||||
Expect_FinishHi,
|
||||
Expect_Data
|
||||
} State;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned char image[65536];
|
||||
char *in_filename = NULL;
|
||||
char *image_filename = NULL;
|
||||
char *header_filename = NULL;
|
||||
int error = 0;
|
||||
int start_addr = 0;
|
||||
int finish_addr = 0;
|
||||
int addr1 = -1;
|
||||
int addr2 = -1;
|
||||
int addr;
|
||||
FILE *f;
|
||||
int i;
|
||||
|
||||
State state = Expect_Header1;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-input") == 0)
|
||||
in_filename = argv[++i];
|
||||
else if (strcmp(argv[i], "-image") == 0)
|
||||
image_filename = argv[++i];
|
||||
else if (strcmp(argv[i], "-header") == 0)
|
||||
header_filename = argv[++i];
|
||||
else if (addr1 == -1)
|
||||
sscanf(argv[i], "%x", &addr1);
|
||||
else if (addr2 == -1)
|
||||
sscanf(argv[i], "%x", &addr2);
|
||||
else
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if (!in_filename || (!image_filename && !header_filename) ||
|
||||
error || (addr1 == -1) || (addr2 == -1)) {
|
||||
printf("Usage: %s -input in_fname {-image image_fname|-header header_fname} hexaddr1 hexaddr2\n",
|
||||
argv[0]);
|
||||
return 0;
|
||||
}
|
||||
memset(image, 0, 65536);
|
||||
|
||||
f = fopen(in_filename, "rb");
|
||||
if (!f) {
|
||||
perror(in_filename);
|
||||
return 1;
|
||||
}
|
||||
while (1) {
|
||||
unsigned char byte;
|
||||
|
||||
if (fread(&byte, 1, 1, f) != 1)
|
||||
break;
|
||||
|
||||
switch (state) {
|
||||
case Expect_Header1:
|
||||
if (byte == 0xff)
|
||||
state = Expect_Header2;
|
||||
else
|
||||
printf("Error: Expecting Header1\n");
|
||||
break;
|
||||
case Expect_Header2:
|
||||
if (byte == 0xff)
|
||||
state = Expect_StartLo;
|
||||
else
|
||||
printf("Error: Expecting Header2\n");
|
||||
break;
|
||||
case Expect_StartLo:
|
||||
start_addr = (start_addr & 0xff00) | byte;
|
||||
state = Expect_StartHi;
|
||||
break;
|
||||
case Expect_StartHi:
|
||||
start_addr = (start_addr & 0x00ff) | (byte << 8);
|
||||
state = Expect_FinishLo;
|
||||
printf("StartAddr = %x\n", start_addr);
|
||||
if (start_addr == 0xffff) {
|
||||
printf("Oops thats a header\n");
|
||||
state = Expect_StartLo;
|
||||
}
|
||||
break;
|
||||
case Expect_FinishLo:
|
||||
finish_addr = (finish_addr & 0xff00) | byte;
|
||||
state = Expect_FinishHi;
|
||||
break;
|
||||
case Expect_FinishHi:
|
||||
finish_addr = (finish_addr & 0x00ff) | (byte << 8);
|
||||
state = Expect_Data;
|
||||
addr = start_addr;
|
||||
printf("FinishAddr = %x\n", finish_addr);
|
||||
break;
|
||||
case Expect_Data:
|
||||
image[addr++] = byte;
|
||||
if (addr > finish_addr)
|
||||
state = Expect_StartLo;
|
||||
break;
|
||||
default:
|
||||
printf("Error: Invalid State\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
/*
|
||||
* Write image to file
|
||||
*/
|
||||
|
||||
if (image_filename) {
|
||||
f = fopen(image_filename, "wb");
|
||||
if (!f) {
|
||||
perror(image_filename);
|
||||
return 1;
|
||||
}
|
||||
fwrite(&image[addr1], 1, addr2 - addr1 + 1, f);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
if (header_filename) {
|
||||
FILE *fp;
|
||||
char *ptr;
|
||||
int j;
|
||||
|
||||
fp = fopen(header_filename, "wb");
|
||||
if (!fp) {
|
||||
perror(header_filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (ptr = header_filename; *ptr; ptr++) {
|
||||
if (!( (*ptr >= 'a' && *ptr <= 'z')
|
||||
|| (*ptr >= 'A' && *ptr <= 'Z')
|
||||
|| (*ptr >= '0' && *ptr <= '9') ))
|
||||
*ptr = '_';
|
||||
}
|
||||
|
||||
fprintf(fp, "#ifndef _%s_\n", header_filename);
|
||||
fprintf(fp, "#define _%s_\n\n", header_filename);
|
||||
|
||||
fprintf(fp, "static unsigned char %s[] =\n{\n\t", header_filename);
|
||||
|
||||
for (i = addr1, j = 0; i < addr2; i++) {
|
||||
fprintf(fp, "0x%02x,", image[i]);
|
||||
|
||||
if (++j == 8) {
|
||||
fprintf(fp, "\n\t");
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp, "0x%02x\n", image[addr2]);
|
||||
fprintf(fp, "};\n");
|
||||
|
||||
fprintf(fp, "\n#endif\n");
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,63 +0,0 @@
|
||||
#ifndef MONITOR_H_
|
||||
#define MONITOR_H_
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "atari.h"
|
||||
|
||||
int MONITOR_Run(void);
|
||||
|
||||
#ifdef MONITOR_TRACE
|
||||
extern FILE *MONITOR_trace_file;
|
||||
#endif
|
||||
|
||||
#ifdef MONITOR_BREAK
|
||||
extern UWORD MONITOR_break_addr;
|
||||
extern UBYTE MONITOR_break_step;
|
||||
extern UBYTE MONITOR_break_ret;
|
||||
extern UBYTE MONITOR_break_brk;
|
||||
extern int MONITOR_ret_nesting;
|
||||
#endif
|
||||
|
||||
extern const UBYTE MONITOR_optype6502[256];
|
||||
|
||||
void MONITOR_ShowState(FILE *fp, UWORD pc, UBYTE a, UBYTE x, UBYTE y, UBYTE s,
|
||||
char n, char v, char z, char c);
|
||||
|
||||
#ifdef MONITOR_BREAKPOINTS
|
||||
|
||||
/* Breakpoint conditions */
|
||||
|
||||
#define MONITOR_BREAKPOINT_OR 1
|
||||
#define MONITOR_BREAKPOINT_FLAG_CLEAR 2
|
||||
#define MONITOR_BREAKPOINT_FLAG_SET 3
|
||||
|
||||
/* these three may be ORed together and must be ORed with MONITOR_BREAKPOINT_PC .. MONITOR_BREAKPOINT_WRITE */
|
||||
#define MONITOR_BREAKPOINT_LESS 1
|
||||
#define MONITOR_BREAKPOINT_EQUAL 2
|
||||
#define MONITOR_BREAKPOINT_GREATER 4
|
||||
|
||||
#define MONITOR_BREAKPOINT_PC 8
|
||||
#define MONITOR_BREAKPOINT_A 16
|
||||
#define MONITOR_BREAKPOINT_X 32
|
||||
#define MONITOR_BREAKPOINT_Y 40
|
||||
#define MONITOR_BREAKPOINT_S 48
|
||||
#define MONITOR_BREAKPOINT_READ 64
|
||||
#define MONITOR_BREAKPOINT_WRITE 128
|
||||
#define MONITOR_BREAKPOINT_ACCESS (MONITOR_BREAKPOINT_READ | MONITOR_BREAKPOINT_WRITE)
|
||||
|
||||
typedef struct {
|
||||
UBYTE enabled;
|
||||
UBYTE condition;
|
||||
UWORD value;
|
||||
} MONITOR_breakpoint_cond;
|
||||
|
||||
#define MONITOR_BREAKPOINT_TABLE_MAX 20
|
||||
extern MONITOR_breakpoint_cond MONITOR_breakpoint_table[MONITOR_BREAKPOINT_TABLE_MAX];
|
||||
extern int MONITOR_breakpoint_table_size;
|
||||
extern int MONITOR_breakpoints_enabled;
|
||||
|
||||
#endif /* MONITOR_BREAKPOINTS */
|
||||
|
||||
#endif /* MONITOR_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +0,0 @@
|
||||
#ifndef MZPOKEYSND_H_
|
||||
#define MZPOKEYSND_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "pokeysnd.h"
|
||||
#include "atari.h"
|
||||
|
||||
int MZPOKEYSND_Init(ULONG freq17,
|
||||
int playback_freq,
|
||||
UBYTE num_pokeys,
|
||||
int flags,
|
||||
int quality
|
||||
#ifdef __PLUS
|
||||
, int clear_regs
|
||||
#endif
|
||||
);
|
||||
|
||||
#endif /* MZPOKEYSND_H_ */
|
||||
@@ -1,301 +0,0 @@
|
||||
/*
|
||||
* pbi.c - Parallel bus emulation
|
||||
*
|
||||
* Copyright (C) 2002 Jason Duerstock <jason@cluephone.com>
|
||||
* Copyright (C) 2007-2008 Perry McFarlane
|
||||
* Copyright (C) 2002-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "atari.h"
|
||||
#include "pbi.h"
|
||||
#include "memory.h"
|
||||
#include "pia.h"
|
||||
#include "cpu.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "statesav.h"
|
||||
#include <stdlib.h>
|
||||
#ifdef PBI_MIO
|
||||
#include "pbi_mio.h"
|
||||
#endif
|
||||
#ifdef PBI_BB
|
||||
#include "pbi_bb.h"
|
||||
#endif
|
||||
#ifdef PBI_XLD
|
||||
#include "pbi_xld.h"
|
||||
#endif
|
||||
#ifdef PBI_PROTO80
|
||||
#include "pbi_proto80.h"
|
||||
#endif
|
||||
|
||||
/* stores the current state of the D1FF register, real hardware has 1
|
||||
* bit per device, the bits are on the devices themselves */
|
||||
static UBYTE D1FF_LATCH = 0;
|
||||
|
||||
/* 1400XL/1450XLD and 1090 have ram here */
|
||||
int PBI_D6D7ram = FALSE;
|
||||
|
||||
/* So far as is currently implemented: PBI_IRQ can be generated by the 1400/1450 Votrax and the Black Box button */
|
||||
/* Each emulated PBI device will set a bit in this variable to indicate IRQ status */
|
||||
/* The actual hardware has only one common line. The device driver rom has to
|
||||
* figure it out*/
|
||||
int PBI_IRQ = 0;
|
||||
|
||||
#ifdef PBI_DEBUG
|
||||
#define D(a) a
|
||||
#else
|
||||
#define D(a) do{}while(0)
|
||||
#endif
|
||||
|
||||
int PBI_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
return TRUE
|
||||
#ifdef PBI_XLD
|
||||
&& PBI_XLD_Initialise(argc, argv)
|
||||
#endif
|
||||
#ifdef PBI_BB
|
||||
&& PBI_BB_Initialise(argc, argv)
|
||||
#endif
|
||||
#ifdef PBI_MIO
|
||||
&& PBI_MIO_Initialise(argc, argv)
|
||||
#endif
|
||||
#ifdef PBI_PROTO80
|
||||
&& PBI_PROTO80_Initialise(argc, argv)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
int PBI_ReadConfig(char *string, char *ptr)
|
||||
{
|
||||
if (0) {
|
||||
}
|
||||
#ifdef PBI_XLD
|
||||
else if (PBI_XLD_ReadConfig(string, ptr)) {
|
||||
}
|
||||
#endif
|
||||
#ifdef PBI_MIO
|
||||
else if (PBI_MIO_ReadConfig(string, ptr)) {
|
||||
}
|
||||
#endif
|
||||
#ifdef PBI_BB
|
||||
else if (PBI_BB_ReadConfig(string, ptr)) {
|
||||
}
|
||||
#endif
|
||||
#ifdef PBI_PROTO80
|
||||
else if (PBI_PROTO80_ReadConfig(string, ptr)) {
|
||||
}
|
||||
#endif
|
||||
else return FALSE; /* no match */
|
||||
return TRUE; /* matched something */
|
||||
}
|
||||
|
||||
void PBI_WriteConfig(FILE *fp)
|
||||
{
|
||||
#ifdef PBI_MIO
|
||||
PBI_MIO_WriteConfig(fp);
|
||||
#endif
|
||||
#ifdef PBI_BB
|
||||
PBI_BB_WriteConfig(fp);
|
||||
#endif
|
||||
#ifdef PBI_XLD
|
||||
PBI_XLD_WriteConfig(fp);
|
||||
#endif
|
||||
#ifdef PBI_PROTO80
|
||||
PBI_PROTO80_WriteConfig(fp);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PBI_Reset(void)
|
||||
{
|
||||
/* Reset all PBI ROMs */
|
||||
PBI_D1PutByte(0xd1ff, 0);
|
||||
#ifdef PBI_XLD
|
||||
if (PBI_XLD_enabled) PBI_XLD_Reset();
|
||||
#endif
|
||||
PBI_IRQ = 0;
|
||||
}
|
||||
|
||||
UBYTE PBI_D1GetByte(UWORD addr)
|
||||
{
|
||||
int result = 0xff;
|
||||
/* MIO and BB do not follow the spec, they take over the bus: */
|
||||
#ifdef PBI_MIO
|
||||
if (PBI_MIO_enabled) return PBI_MIO_D1GetByte(addr);
|
||||
#endif
|
||||
#ifdef PBI_BB
|
||||
if (PBI_BB_enabled) return PBI_BB_D1GetByte(addr);
|
||||
#endif
|
||||
/* Remaining PBI devices cooperate, following spec */
|
||||
#ifdef PBI_XLD
|
||||
if (PBI_XLD_enabled) result = PBI_XLD_D1GetByte(addr);
|
||||
#endif
|
||||
#ifdef PBI_PROTO80
|
||||
if (result == PBI_NOT_HANDLED && PBI_PROTO80_enabled) result = PBI_PROTO80_D1GetByte(addr);
|
||||
#endif
|
||||
if(result != PBI_NOT_HANDLED) return (UBYTE)result;
|
||||
/* Each bit of D1FF is set by one of the 8 PBI devices to signal IRQ */
|
||||
/* The XLD devices have been combined into a single handler */
|
||||
if (addr == 0xd1ff) {
|
||||
/* D1FF IRQ status: */
|
||||
result = 0;
|
||||
#ifdef PBI_XLD
|
||||
if (PBI_XLD_enabled) result |= PBI_XLD_D1ffGetByte();
|
||||
#endif
|
||||
/* add more devices here... */
|
||||
return result;
|
||||
}
|
||||
/* addr was not handled: */
|
||||
D(printf("PBI_GetByte:%4x:%2x PC:%4x IRQ:%d\n",addr,result,CPU_regPC,IRQ));
|
||||
return result; /* 0xff */
|
||||
}
|
||||
|
||||
void PBI_D1PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
static int fp_active = TRUE;
|
||||
#ifdef PBI_MIO
|
||||
if (PBI_MIO_enabled) {
|
||||
PBI_MIO_D1PutByte(addr, byte);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef PBI_BB
|
||||
if (PBI_BB_enabled) {
|
||||
PBI_BB_D1PutByte(addr, byte);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* Remaining PBI devices cooperate, following spec */
|
||||
if (addr != 0xd1ff) {
|
||||
D(printf("PBI_PutByte:%4x <- %2x\n", addr, byte));
|
||||
#ifdef PBI_XLD
|
||||
if (PBI_XLD_enabled) PBI_XLD_D1PutByte(addr, byte);
|
||||
#endif
|
||||
#ifdef PBI_PROTO_80
|
||||
if (PBI_PROTO80_enabled) PBI_PROTO80_D1PutByte(addr, byte);
|
||||
#endif
|
||||
/* add more devices here... */
|
||||
}
|
||||
else if (addr == 0xd1ff) {
|
||||
/* D1FF pbi rom bank select */
|
||||
D(printf("D1FF write:%x\n", byte));
|
||||
if (D1FF_LATCH != byte) {
|
||||
/* if it's not valid, ignore it */
|
||||
if (byte != 0 && byte != 1 && byte != 2 && byte != 4 && byte != 8 && byte != 0x10 && byte !=0x20 && byte != 0x40 && byte != 0x80){
|
||||
D(printf("*****INVALID d1ff write:%2x********\n",byte));
|
||||
return;
|
||||
}
|
||||
/* otherwise, update the latch */
|
||||
D1FF_LATCH = byte;
|
||||
#ifdef PBI_XLD
|
||||
if (PBI_XLD_enabled && PBI_XLD_D1ffPutByte(byte) != PBI_NOT_HANDLED) {
|
||||
/* handled */
|
||||
fp_active = FALSE;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef PBI_PROTO80
|
||||
if (PBI_PROTO80_enabled && PBI_PROTO80_D1ffPutByte(byte) != PBI_NOT_HANDLED) {
|
||||
/* handled */
|
||||
fp_active = FALSE;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* add more devices here... */
|
||||
/* reactivate the floating point rom */
|
||||
if (!fp_active) {
|
||||
memcpy(MEMORY_mem + 0xd800, MEMORY_os + 0x1800, 0x800);
|
||||
D(printf("Floating point rom activated\n"));
|
||||
fp_active = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* $D6xx */
|
||||
UBYTE PBI_D6GetByte(UWORD addr)
|
||||
{
|
||||
#ifdef PBI_MIO
|
||||
if (PBI_MIO_enabled) return PBI_MIO_D6GetByte(addr);
|
||||
#endif
|
||||
#ifdef PBI_BB
|
||||
if(PBI_BB_enabled) return PBI_BB_D6GetByte(addr);
|
||||
#endif
|
||||
/* XLD/1090 has ram here */
|
||||
if (PBI_D6D7ram) return MEMORY_mem[addr];
|
||||
else return 0xff;
|
||||
}
|
||||
|
||||
/* $D6xx */
|
||||
void PBI_D6PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
#ifdef PBI_MIO
|
||||
if (PBI_MIO_enabled) {
|
||||
PBI_MIO_D6PutByte(addr,byte);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef PBI_BB
|
||||
if(PBI_BB_enabled) {
|
||||
PBI_BB_D6PutByte(addr,byte);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* XLD/1090 has ram here */
|
||||
if (PBI_D6D7ram) MEMORY_mem[addr]=byte;
|
||||
}
|
||||
|
||||
/* read page $D7xx */
|
||||
/* XLD/1090 has ram here */
|
||||
UBYTE PBI_D7GetByte(UWORD addr)
|
||||
{
|
||||
D(printf("PBI_D7GetByte:%4x\n",addr));
|
||||
if (PBI_D6D7ram) return MEMORY_mem[addr];
|
||||
else return 0xff;
|
||||
}
|
||||
|
||||
/* write page $D7xx */
|
||||
/* XLD/1090 has ram here */
|
||||
void PBI_D7PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
D(printf("PBI_D7PutByte:%4x <- %2x\n",addr,byte));
|
||||
if (PBI_D6D7ram) MEMORY_mem[addr]=byte;
|
||||
}
|
||||
|
||||
#ifndef BASIC
|
||||
|
||||
void PBI_StateSave(void)
|
||||
{
|
||||
StateSav_SaveUBYTE(&D1FF_LATCH, 1);
|
||||
StateSav_SaveINT(&PBI_D6D7ram, 1);
|
||||
StateSav_SaveINT(&PBI_IRQ, 1);
|
||||
}
|
||||
|
||||
void PBI_StateRead(void)
|
||||
{
|
||||
StateSav_ReadUBYTE(&D1FF_LATCH, 1);
|
||||
StateSav_ReadINT(&PBI_D6D7ram, 1);
|
||||
StateSav_ReadINT(&PBI_IRQ, 1);
|
||||
}
|
||||
|
||||
#endif /* #ifndef BASIC */
|
||||
|
||||
/*
|
||||
vim:ts=4:sw=4:
|
||||
*/
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef PBI_H_
|
||||
#define PBI_H_
|
||||
|
||||
#include "atari.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int PBI_Initialise(int *argc, char *argv[]);
|
||||
int PBI_ReadConfig(char *string, char *ptr);
|
||||
void PBI_WriteConfig(FILE *fp);
|
||||
void PBI_Reset(void);
|
||||
UBYTE PBI_D1GetByte(UWORD addr);
|
||||
void PBI_D1PutByte(UWORD addr, UBYTE byte);
|
||||
UBYTE PBI_D6GetByte(UWORD addr);
|
||||
void PBI_D6PutByte(UWORD addr, UBYTE byte);
|
||||
UBYTE PBI_D7GetByte(UWORD addr);
|
||||
void PBI_D7PutByte(UWORD addr, UBYTE byte);
|
||||
extern int PBI_IRQ;
|
||||
extern int PBI_D6D7ram;
|
||||
void PBI_StateSave(void);
|
||||
void PBI_StateRead(void);
|
||||
#define PBI_NOT_HANDLED -1
|
||||
/* #define PBI_DEBUG */
|
||||
#endif /* PBI_H_ */
|
||||
@@ -1,314 +0,0 @@
|
||||
/*
|
||||
* pbi_bb.c - CSS Black Box emulation
|
||||
*
|
||||
* Copyright (C) 2007-2008 Perry McFarlane
|
||||
* Copyright (C) 1998-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "atari.h"
|
||||
#include "pbi_bb.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "pbi.h"
|
||||
#include "memory.h"
|
||||
#include "pia.h"
|
||||
#include "pokey.h"
|
||||
#include "cpu.h"
|
||||
#include "pbi_scsi.h"
|
||||
#include "statesav.h"
|
||||
#include "util.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef PBI_DEBUG
|
||||
#define D(a) a
|
||||
#else
|
||||
#define D(a) do{}while(0)
|
||||
#endif
|
||||
|
||||
/* CSS Black Box emulation */
|
||||
/* information source: http://www.mathyvannisselroy.nl/bbdoku.txt*/
|
||||
#define BB_BUTTON_IRQ_MASK 1
|
||||
|
||||
int PBI_BB_enabled = FALSE;
|
||||
|
||||
static UBYTE *bb_rom;
|
||||
static int bb_ram_bank_offset = 0;
|
||||
static UBYTE *bb_ram;
|
||||
#define BB_RAM_SIZE 0x10000
|
||||
static UBYTE bb_rom_bank = 0;
|
||||
static int bb_rom_size;
|
||||
static int bb_rom_high_bit = 0x00;/*0x10*/
|
||||
static char bb_rom_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
static UBYTE bb_PCR = 0; /* VIA Peripheral control register*/
|
||||
static int bb_scsi_enabled = FALSE;
|
||||
static char bb_scsi_disk_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
|
||||
static void init_bb(void)
|
||||
{
|
||||
FILE *bbfp;
|
||||
bbfp = fopen(bb_rom_filename,"rb");
|
||||
bb_rom_size = Util_flen(bbfp);
|
||||
fclose(bbfp);
|
||||
if (bb_rom_size != 0x10000 && bb_rom_size != 0x4000) {
|
||||
Log_print("Invalid black box rom size\n");
|
||||
return;
|
||||
}
|
||||
bb_rom = (UBYTE *)Util_malloc(bb_rom_size);
|
||||
if (!Atari800_LoadImage(bb_rom_filename, bb_rom, bb_rom_size)) {
|
||||
free(bb_rom);
|
||||
return;
|
||||
}
|
||||
D(printf("loaded black box rom image\n"));
|
||||
PBI_BB_enabled = TRUE;
|
||||
if (PBI_SCSI_disk != NULL) fclose(PBI_SCSI_disk);
|
||||
if (!Util_filenamenotset(bb_scsi_disk_filename)) {
|
||||
PBI_SCSI_disk = fopen(bb_scsi_disk_filename, "rb+");
|
||||
if (PBI_SCSI_disk == NULL) {
|
||||
Log_print("Error opening BB SCSI disk image:%s", bb_scsi_disk_filename);
|
||||
}
|
||||
else {
|
||||
D(printf("Opened BB SCSI disk image\n"));
|
||||
bb_scsi_enabled = TRUE;
|
||||
}
|
||||
}
|
||||
if (!bb_scsi_enabled) {
|
||||
PBI_SCSI_BSY = TRUE; /* makes BB give up easier? */
|
||||
}
|
||||
bb_ram = (UBYTE *)Util_malloc(BB_RAM_SIZE);
|
||||
memset(bb_ram,0,BB_RAM_SIZE);
|
||||
}
|
||||
|
||||
int PBI_BB_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 1; i < *argc; i++) {
|
||||
if (strcmp(argv[i], "-bb") == 0) {
|
||||
init_bb();
|
||||
}
|
||||
else {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
Log_print("\t-bb Emulate the CSS Black Box");
|
||||
}
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
}
|
||||
*argc = j;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int PBI_BB_ReadConfig(char *string, char *ptr)
|
||||
{
|
||||
if (strcmp(string, "BLACK_BOX_ROM") == 0)
|
||||
Util_strlcpy(bb_rom_filename, ptr, sizeof(bb_rom_filename));
|
||||
else if (strcmp(string, "BB_SCSI_DISK") == 0)
|
||||
Util_strlcpy(bb_scsi_disk_filename, ptr, sizeof(bb_scsi_disk_filename));
|
||||
else return FALSE; /* no match */
|
||||
return TRUE; /* matched something */
|
||||
}
|
||||
|
||||
void PBI_BB_WriteConfig(FILE *fp)
|
||||
{
|
||||
fprintf(fp, "BLACK_BOX_ROM=%s\n", bb_rom_filename);
|
||||
if (!Util_filenamenotset(bb_scsi_disk_filename)) {
|
||||
fprintf(fp, "BB_SCSI_DISK=%s\n", bb_scsi_disk_filename);
|
||||
}
|
||||
}
|
||||
|
||||
UBYTE PBI_BB_D1GetByte(UWORD addr)
|
||||
{
|
||||
UBYTE result = 0x00;/*ff;*/
|
||||
if (addr == 0xd1be) result = 0xff;
|
||||
else if (addr == 0xd170) {
|
||||
/* status */
|
||||
result = ((!(PBI_SCSI_REQ))<<7)|((!PBI_SCSI_BSY)<<6)|((!PBI_SCSI_SEL)<<2)|((!PBI_SCSI_CD)<<1)|(!PBI_SCSI_IO);
|
||||
}
|
||||
else if (addr == 0xd171) {
|
||||
if (bb_scsi_enabled) {
|
||||
result = PBI_SCSI_GetByte();
|
||||
if (((bb_PCR & 0x0e)>>1) == 0x04) {
|
||||
/* handshake output */
|
||||
PBI_SCSI_PutACK(1);
|
||||
PBI_SCSI_PutACK(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (addr == 0xd1bc) result = (bb_ram_bank_offset >> 8);/*RAMPAGE*/
|
||||
else if (addr == 0xd1be) {
|
||||
/* SWITCH */
|
||||
result = 0x02;
|
||||
}
|
||||
else if (addr == 0xd1ff) result = PBI_IRQ ? (0x08 | 0x02) : 0 ;
|
||||
D(if (addr!=0xd1ff) printf("BB Read:%4x PC:%4x byte=%2x\n", addr, CPU_remember_PC[(CPU_remember_PC_curpos-1)%CPU_REMEMBER_PC_STEPS], result));
|
||||
return result;
|
||||
}
|
||||
|
||||
void PBI_BB_D1PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
D(printf("BB Write addr:%4x byte:%2x, cpu:%4x\n", addr, byte, CPU_remember_PC[(CPU_remember_PC_curpos-1)%CPU_REMEMBER_PC_STEPS]));
|
||||
if (addr == 0xd170) {
|
||||
if (bb_scsi_enabled) PBI_SCSI_PutSEL(!(byte&0x04));
|
||||
}
|
||||
else if (addr == 0xd171) {
|
||||
if (bb_scsi_enabled) {
|
||||
PBI_SCSI_PutByte(byte);
|
||||
if (((bb_PCR & 0x0e)>>1) == 0x04) {
|
||||
/* handshake output */
|
||||
PBI_SCSI_PutACK(1);
|
||||
PBI_SCSI_PutACK(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (addr == 0xd17c) { /* PCR */
|
||||
bb_PCR = byte;
|
||||
if (((bb_PCR & 0x0e)>>1) == 0x06) {
|
||||
/* low output */
|
||||
if (bb_scsi_enabled) PBI_SCSI_PutACK(1);
|
||||
}
|
||||
else if (((bb_PCR & 0x0e)>>1) == 0x07) {
|
||||
/* high output */
|
||||
if (bb_scsi_enabled) PBI_SCSI_PutACK(0);
|
||||
}
|
||||
}
|
||||
else if (addr == 0xd1bc) {
|
||||
/* RAMPAGE */
|
||||
/* Copy old page to buffer, Copy new page from buffer */
|
||||
memcpy(bb_ram+bb_ram_bank_offset,MEMORY_mem + 0xd600,0x100);
|
||||
bb_ram_bank_offset = (byte << 8);
|
||||
memcpy(MEMORY_mem + 0xd600, bb_ram+bb_ram_bank_offset, 0x100);
|
||||
}
|
||||
else if (addr == 0xd1be) {
|
||||
/* high rom bit */
|
||||
if (bb_rom_high_bit != ((byte & 0x04) << 2) && bb_rom_size == 0x10000) {
|
||||
/* high bit has changed */
|
||||
bb_rom_high_bit = ((byte & 0x04) << 2);
|
||||
if (bb_rom_bank > 0 && bb_rom_bank < 8) {
|
||||
memcpy(MEMORY_mem + 0xd800, bb_rom + (bb_rom_bank + bb_rom_high_bit)*0x800, 0x800);
|
||||
D(printf("black box bank:%2x activated\n", bb_rom_bank+bb_rom_high_bit));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((addr & 0xffc0) == 0xd1c0) {
|
||||
/* byte &= 0x0f; */
|
||||
if (bb_rom_bank != byte) {
|
||||
/* PDVS (d1ff) rom bank */
|
||||
int offset = -1;
|
||||
if (bb_rom_size == 0x4000) {
|
||||
if (byte >= 8 && byte <= 0x0f) offset = (byte - 8)*0x800;
|
||||
else if (byte > 0 && byte < 0x08) offset = byte*0x800;
|
||||
}
|
||||
else { /* bb_rom_size == 0x10000 */
|
||||
if (byte > 0 && byte < 0x10) offset = (byte + bb_rom_high_bit)*0x800;
|
||||
}
|
||||
|
||||
if (offset != -1) {
|
||||
memcpy(MEMORY_mem + 0xd800, bb_rom + offset, 0x800);
|
||||
D(printf("black box bank:%2x activated\n", byte + bb_rom_high_bit));
|
||||
}
|
||||
else {
|
||||
memcpy(MEMORY_mem + 0xd800, MEMORY_os + 0x1800, 0x800);
|
||||
if (byte != 0) D(printf("d1ff ERROR: byte=%2x\n", byte));
|
||||
D(printf("Floating point rom activated\n"));
|
||||
}
|
||||
bb_rom_bank = byte;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Black Box RAM page at D600-D6ff*/
|
||||
/* Possible to put code in this ram, so we can't avoid using MEMORY_mem[]
|
||||
* because opcode fetch doesn't call this function*/
|
||||
UBYTE PBI_BB_D6GetByte(UWORD addr)
|
||||
{
|
||||
return MEMORY_mem[addr];
|
||||
}
|
||||
|
||||
/* $D6xx */
|
||||
void PBI_BB_D6PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
MEMORY_mem[addr]=byte;
|
||||
}
|
||||
|
||||
static int buttondown;
|
||||
|
||||
void PBI_BB_Menu(void)
|
||||
{
|
||||
if (!PBI_BB_enabled) return;
|
||||
if (buttondown == FALSE) {
|
||||
D(printf("blackbox button down interrupt generated\n"));
|
||||
CPU_GenerateIRQ();
|
||||
PBI_IRQ |= BB_BUTTON_IRQ_MASK;
|
||||
buttondown = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void PBI_BB_Frame(void)
|
||||
{
|
||||
static int count = 0;
|
||||
if (buttondown) {
|
||||
if (count < 1) count++;
|
||||
else {
|
||||
D(printf("blackbox button up\n"));
|
||||
PBI_IRQ &= ~BB_BUTTON_IRQ_MASK;
|
||||
/* update pokey IRQ status */
|
||||
POKEY_PutByte(POKEY_OFFSET_IRQEN, POKEY_IRQEN);
|
||||
buttondown = FALSE;
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BASIC
|
||||
|
||||
void PBI_BB_StateSave(void)
|
||||
{
|
||||
StateSav_SaveINT(&PBI_BB_enabled, 1);
|
||||
if (PBI_BB_enabled) {
|
||||
StateSav_SaveFNAME(bb_scsi_disk_filename);
|
||||
StateSav_SaveFNAME(bb_rom_filename);
|
||||
|
||||
StateSav_SaveINT(&bb_ram_bank_offset, 1);
|
||||
StateSav_SaveUBYTE(bb_ram, BB_RAM_SIZE);
|
||||
StateSav_SaveUBYTE(&bb_rom_bank, 1);
|
||||
StateSav_SaveINT(&bb_rom_high_bit, 1);
|
||||
StateSav_SaveUBYTE(&bb_PCR, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void PBI_BB_StateRead(void)
|
||||
{
|
||||
StateSav_ReadINT(&PBI_BB_enabled, 1);
|
||||
if (PBI_BB_enabled) {
|
||||
StateSav_ReadFNAME(bb_scsi_disk_filename);
|
||||
StateSav_ReadFNAME(bb_rom_filename);
|
||||
init_bb();
|
||||
StateSav_ReadINT(&bb_ram_bank_offset, 1);
|
||||
StateSav_ReadUBYTE(bb_ram, BB_RAM_SIZE);
|
||||
StateSav_ReadUBYTE(&bb_rom_bank, 1);
|
||||
StateSav_ReadINT(&bb_rom_high_bit, 1);
|
||||
StateSav_ReadUBYTE(&bb_PCR, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #ifndef BASIC */
|
||||
|
||||
/*
|
||||
vim:ts=4:sw=4:
|
||||
*/
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef PBI_BB_H_
|
||||
#define PBI_BB_H_
|
||||
|
||||
#include "atari.h"
|
||||
#include <stdio.h>
|
||||
|
||||
extern int PBI_BB_enabled;
|
||||
void PBI_BB_Menu(void);
|
||||
void PBI_BB_Frame(void);
|
||||
int PBI_BB_Initialise(int *argc, char *argv[]);
|
||||
UBYTE PBI_BB_D1GetByte(UWORD addr);
|
||||
void PBI_BB_D1PutByte(UWORD addr, UBYTE byte);
|
||||
UBYTE PBI_BB_D6GetByte(UWORD addr);
|
||||
void PBI_BB_D6PutByte(UWORD addr, UBYTE byte);
|
||||
int PBI_BB_ReadConfig(char *string, char *ptr);
|
||||
void PBI_BB_WriteConfig(FILE *fp);
|
||||
void PBI_BB_StateSave(void);
|
||||
void PBI_BB_StateRead(void);
|
||||
|
||||
#endif /* PBI_BB_H_ */
|
||||
@@ -1,258 +0,0 @@
|
||||
/*
|
||||
* pbi_mio.c - ICD MIO board emulation
|
||||
*
|
||||
* Copyright (C) 2007-2008 Perry McFarlane
|
||||
* Copyright (C) 1998-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "atari.h"
|
||||
#include "pbi_mio.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "pia.h"
|
||||
#include "pbi.h"
|
||||
#include "cpu.h"
|
||||
#include "stdlib.h"
|
||||
#include "pbi_scsi.h"
|
||||
#include "statesav.h"
|
||||
|
||||
#ifdef PBI_DEBUG
|
||||
#define D(a) a
|
||||
#else
|
||||
#define D(a) do{}while(0)
|
||||
#endif
|
||||
|
||||
int PBI_MIO_enabled = FALSE;
|
||||
|
||||
static UBYTE *mio_rom;
|
||||
static int mio_rom_size = 0x4000;
|
||||
static int mio_ram_bank_offset = 0;
|
||||
static UBYTE *mio_ram;
|
||||
static int mio_ram_size = 0x100000;
|
||||
static UBYTE mio_rom_bank = 0;
|
||||
static int mio_ram_enabled = FALSE;
|
||||
static char mio_rom_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
static char mio_scsi_disk_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
static int mio_scsi_enabled = FALSE;
|
||||
|
||||
static void init_mio(void)
|
||||
{
|
||||
free(mio_rom);
|
||||
mio_rom = (UBYTE *)Util_malloc(mio_rom_size);
|
||||
if (!Atari800_LoadImage(mio_rom_filename, mio_rom, mio_rom_size)) {
|
||||
free(mio_rom);
|
||||
return;
|
||||
}
|
||||
D(printf("Loaded mio rom image\n"));
|
||||
PBI_MIO_enabled = TRUE;
|
||||
if (PBI_SCSI_disk != NULL) fclose(PBI_SCSI_disk);
|
||||
if (!Util_filenamenotset(mio_scsi_disk_filename)) {
|
||||
PBI_SCSI_disk = fopen(mio_scsi_disk_filename, "rb+");
|
||||
if (PBI_SCSI_disk == NULL) {
|
||||
Log_print("Error opening SCSI disk image:%s", mio_scsi_disk_filename);
|
||||
}
|
||||
else {
|
||||
D(printf("Opened SCSI disk image\n"));
|
||||
mio_scsi_enabled = TRUE;
|
||||
}
|
||||
}
|
||||
if (!mio_scsi_enabled) {
|
||||
PBI_SCSI_BSY = TRUE; /* makes MIO give up easier */
|
||||
}
|
||||
free(mio_ram);
|
||||
mio_ram = (UBYTE *)Util_malloc(mio_ram_size);
|
||||
memset(mio_ram, 0, mio_ram_size);
|
||||
}
|
||||
|
||||
|
||||
int PBI_MIO_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 1; i < *argc; i++) {
|
||||
if (strcmp(argv[i], "-mio") == 0) {
|
||||
init_mio();
|
||||
}
|
||||
else {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
Log_print("\t-mio Emulate the ICD MIO board");
|
||||
}
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
}
|
||||
*argc = j;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int PBI_MIO_ReadConfig(char *string, char *ptr)
|
||||
{
|
||||
if (strcmp(string, "MIO_ROM") == 0)
|
||||
Util_strlcpy(mio_rom_filename, ptr, sizeof(mio_rom_filename));
|
||||
else if (strcmp(string, "MIO_SCSI_DISK") == 0)
|
||||
Util_strlcpy(mio_scsi_disk_filename, ptr, sizeof(mio_scsi_disk_filename));
|
||||
else return FALSE; /* no match */
|
||||
return TRUE; /* matched something */
|
||||
}
|
||||
|
||||
void PBI_MIO_WriteConfig(FILE *fp)
|
||||
{
|
||||
fprintf(fp, "MIO_ROM=%s\n", mio_rom_filename);
|
||||
if (!Util_filenamenotset(mio_scsi_disk_filename)) {
|
||||
fprintf(fp, "MIO_SCSI_DISK=%s\n", mio_scsi_disk_filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* $D1xx */
|
||||
UBYTE PBI_MIO_D1GetByte(UWORD addr)
|
||||
{
|
||||
UBYTE result = 0x00;/*ff*/;
|
||||
addr &= 0xffe3; /* 7 mirrors */
|
||||
D(printf("MIO Read:%4x PC:%4x\n", addr, CPU_remember_PC[(CPU_remember_PC_curpos-1)%CPU_REMEMBER_PC_STEPS]));
|
||||
if (addr == 0xd1e2) {
|
||||
result = ((!PBI_SCSI_CD) | (!PBI_SCSI_MSG<<1) | (!PBI_SCSI_IO<<2) | (!PBI_SCSI_BSY<<5) | (!PBI_SCSI_REQ<<7));
|
||||
}
|
||||
else if (addr == 0xd1e1) {
|
||||
if (mio_scsi_enabled) {
|
||||
result = PBI_SCSI_GetByte()^0xff;
|
||||
PBI_SCSI_PutACK(1);
|
||||
PBI_SCSI_PutACK(0);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* $D1xx */
|
||||
void PBI_MIO_D1PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
int old_mio_ram_bank_offset = mio_ram_bank_offset;
|
||||
int old_mio_ram_enabled = mio_ram_enabled;
|
||||
int offset_changed;
|
||||
int ram_enabled_changed;
|
||||
addr &= 0xffe3; /* 7 mirrors */
|
||||
if (addr == 0xd1e0) {
|
||||
/* ram bank A15-A8 */
|
||||
mio_ram_bank_offset &= 0xf0000;
|
||||
mio_ram_bank_offset |= (byte << 8);
|
||||
}
|
||||
else if (addr == 0xd1e1) {
|
||||
if (mio_scsi_enabled) {
|
||||
PBI_SCSI_PutByte(byte^0xff);
|
||||
PBI_SCSI_PutACK(1);
|
||||
PBI_SCSI_PutACK(0);
|
||||
}
|
||||
}
|
||||
else if (addr == 0xd1e2) {
|
||||
/* ram bank A19-A16, ram enable, other stuff */
|
||||
mio_ram_bank_offset &= 0x0ffff;
|
||||
mio_ram_bank_offset |= ( (byte & 0x0f) << 16);
|
||||
mio_ram_enabled = (byte & 0x20);
|
||||
if (mio_scsi_enabled) PBI_SCSI_PutSEL(!!(byte & 0x10));
|
||||
}
|
||||
else if (addr == 0xd1e3) {
|
||||
/* or 0xd1ff. rom bank. */
|
||||
if (mio_rom_bank != byte){
|
||||
int offset = -1;
|
||||
if (byte == 4) offset = 0x2000;
|
||||
else if (byte == 8) offset = 0x2800;
|
||||
else if (byte == 0x10) offset = 0x3000;
|
||||
else if (byte == 0x20) offset = 0x3800;
|
||||
if (offset != -1) {
|
||||
memcpy(MEMORY_mem + 0xd800, mio_rom+offset, 0x800);
|
||||
D(printf("mio bank:%2x activated\n", byte));
|
||||
}else{
|
||||
memcpy(MEMORY_mem + 0xd800, MEMORY_os + 0x1800, 0x800);
|
||||
D(printf("Floating point rom activated\n"));
|
||||
|
||||
}
|
||||
mio_rom_bank = byte;
|
||||
}
|
||||
|
||||
}
|
||||
offset_changed = (old_mio_ram_bank_offset != mio_ram_bank_offset);
|
||||
ram_enabled_changed = (old_mio_ram_enabled != mio_ram_enabled);
|
||||
if (mio_ram_enabled && ram_enabled_changed) {
|
||||
/* Copy new page from buffer, overwrite ff page */
|
||||
memcpy(MEMORY_mem + 0xd600, mio_ram + mio_ram_bank_offset, 0x100);
|
||||
} else if (mio_ram_enabled && offset_changed) {
|
||||
/* Copy old page to buffer, copy new page from buffer */
|
||||
memcpy(mio_ram + old_mio_ram_bank_offset,MEMORY_mem + 0xd600, 0x100);
|
||||
memcpy(MEMORY_mem + 0xd600, mio_ram + mio_ram_bank_offset, 0x100);
|
||||
} else if (!mio_ram_enabled && ram_enabled_changed) {
|
||||
/* Copy old page to buffer, set new page to ff */
|
||||
memcpy(mio_ram + old_mio_ram_bank_offset, MEMORY_mem + 0xd600, 0x100);
|
||||
memset(MEMORY_mem + 0xd600, 0xff, 0x100);
|
||||
}
|
||||
D(printf("MIO Write addr:%4x byte:%2x, cpu:%4x\n", addr, byte,CPU_remember_PC[(CPU_remember_PC_curpos-1)%CPU_REMEMBER_PC_STEPS]));
|
||||
}
|
||||
|
||||
/* MIO RAM page at D600-D6ff */
|
||||
/* Possible to put code in this ram, so we can't avoid using MEMORY_mem[] */
|
||||
/* because opcode fetch doesn't call this function */
|
||||
UBYTE PBI_MIO_D6GetByte(UWORD addr)
|
||||
{
|
||||
if (!mio_ram_enabled) return 0xff;
|
||||
return MEMORY_mem[addr];
|
||||
}
|
||||
|
||||
/* $D6xx */
|
||||
void PBI_MIO_D6PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
if (!mio_ram_enabled) return;
|
||||
MEMORY_mem[addr]=byte;
|
||||
}
|
||||
|
||||
#ifndef BASIC
|
||||
|
||||
void PBI_MIO_StateSave(void)
|
||||
{
|
||||
StateSav_SaveINT(&PBI_MIO_enabled, 1);
|
||||
if (PBI_MIO_enabled) {
|
||||
StateSav_SaveFNAME(mio_scsi_disk_filename);
|
||||
StateSav_SaveFNAME(mio_rom_filename);
|
||||
StateSav_SaveINT(&mio_ram_size, 1);
|
||||
|
||||
StateSav_SaveINT(&mio_ram_bank_offset, 1);
|
||||
StateSav_SaveUBYTE(mio_ram, mio_ram_size);
|
||||
StateSav_SaveUBYTE(&mio_rom_bank, 1);
|
||||
StateSav_SaveINT(&mio_ram_enabled, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void PBI_MIO_StateRead(void)
|
||||
{
|
||||
StateSav_ReadINT(&PBI_MIO_enabled, 1);
|
||||
if (PBI_MIO_enabled) {
|
||||
StateSav_ReadFNAME(mio_scsi_disk_filename);
|
||||
StateSav_ReadFNAME(mio_rom_filename);
|
||||
StateSav_ReadINT(&mio_ram_size, 1);
|
||||
init_mio();
|
||||
StateSav_ReadINT(&mio_ram_bank_offset, 1);
|
||||
StateSav_ReadUBYTE(mio_ram, mio_ram_size);
|
||||
StateSav_ReadUBYTE(&mio_rom_bank, 1);
|
||||
StateSav_ReadINT(&mio_ram_enabled, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #ifndef BASIC */
|
||||
|
||||
/*
|
||||
vim:ts=4:sw=4:
|
||||
*/
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef PBI_MIO_H_
|
||||
#define PBI_MIO_H_
|
||||
|
||||
#include "atari.h"
|
||||
#include <stdio.h>
|
||||
|
||||
extern int PBI_MIO_enabled;
|
||||
|
||||
int PBI_MIO_Initialise(int *argc, char *argv[]);
|
||||
UBYTE PBI_MIO_D1GetByte(UWORD addr);
|
||||
void PBI_MIO_D1PutByte(UWORD addr, UBYTE byte);
|
||||
UBYTE PBI_MIO_D6GetByte(UWORD addr);
|
||||
void PBI_MIO_D6PutByte(UWORD addr, UBYTE byte);
|
||||
int PBI_MIO_ReadConfig(char *string, char *ptr);
|
||||
void PBI_MIO_WriteConfig(FILE *fp);
|
||||
void PBI_MIO_StateSave(void);
|
||||
void PBI_MIO_StateRead(void);
|
||||
|
||||
#endif /* PBI_MIO_H_ */
|
||||
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* pbi_proto.c - Emulation of a prototype 80 column board for the
|
||||
* Atari 1090 expansion interface.
|
||||
*
|
||||
* Copyright (C) 2007-2008 Perry McFarlane
|
||||
* Copyright (C) 2002-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "atari.h"
|
||||
#include "pbi.h"
|
||||
#include "pbi_proto80.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PROTO80_PBI_NUM 2
|
||||
#define PROTO80_MASK (1 << PROTO80_PBI_NUM)
|
||||
|
||||
static UBYTE *proto80rom;
|
||||
static char proto80_rom_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
|
||||
int PBI_PROTO80_enabled = FALSE;
|
||||
|
||||
#ifdef PBI_DEBUG
|
||||
#define D(a) a
|
||||
#else
|
||||
#define D(a) do{}while(0)
|
||||
#endif
|
||||
|
||||
int PBI_PROTO80_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 1; i < *argc; i++) {
|
||||
if (strcmp(argv[i], "-proto80") == 0) {
|
||||
Log_print("proto80 enabled");
|
||||
PBI_PROTO80_enabled = TRUE;
|
||||
}
|
||||
else {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
Log_print("\t-proto80 Emulate a prototype 80 column board for the 1090");
|
||||
}
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
}
|
||||
*argc = j;
|
||||
|
||||
if (PBI_PROTO80_enabled) {
|
||||
proto80rom = (UBYTE *)Util_malloc(0x800);
|
||||
if (!Atari800_LoadImage(proto80_rom_filename, proto80rom, 0x800)) {
|
||||
free(proto80rom);
|
||||
PBI_PROTO80_enabled = FALSE;
|
||||
Log_print("Couldn't load proto80 rom image");
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
Log_print("loaded proto80 rom image");
|
||||
PBI_D6D7ram = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int PBI_PROTO80_ReadConfig(char *string, char *ptr)
|
||||
{
|
||||
if (strcmp(string, "PROTO80_ROM") == 0)
|
||||
Util_strlcpy(proto80_rom_filename, ptr, sizeof(proto80_rom_filename));
|
||||
else return FALSE; /* no match */
|
||||
return TRUE; /* matched something */
|
||||
}
|
||||
|
||||
void PBI_PROTO80_WriteConfig(FILE *fp)
|
||||
{
|
||||
fprintf(fp, "PROTO80_ROM=%s\n", proto80_rom_filename);
|
||||
}
|
||||
|
||||
int PBI_PROTO80_D1GetByte(UWORD addr)
|
||||
{
|
||||
int result = PBI_NOT_HANDLED;
|
||||
if (PBI_PROTO80_enabled) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void PBI_PROTO80_D1PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int PBI_PROTO80_D1ffPutByte(UBYTE byte)
|
||||
{
|
||||
int result = 0; /* handled */
|
||||
if (PBI_PROTO80_enabled && byte == PROTO80_MASK) {
|
||||
memcpy(MEMORY_mem + 0xd800, proto80rom, 0x800);
|
||||
D(printf("PROTO80 rom activated\n"));
|
||||
}
|
||||
else result = PBI_NOT_HANDLED;
|
||||
return result;
|
||||
}
|
||||
|
||||
UBYTE PBI_PROTO80_GetPixels(int scanline, int column)
|
||||
{
|
||||
#define PROTO80_ROWS 24
|
||||
#define PROTO80_CELL_HEIGHT 8
|
||||
UBYTE character;
|
||||
UBYTE invert;
|
||||
UBYTE font_data;
|
||||
int row = scanline / PROTO80_CELL_HEIGHT;
|
||||
int line = scanline % PROTO80_CELL_HEIGHT;
|
||||
if (row >= PROTO80_ROWS) {
|
||||
return 0;
|
||||
}
|
||||
character = MEMORY_mem[0x9800 + row*80 + column];
|
||||
invert = 0x00;
|
||||
if (character & 0x80) {
|
||||
invert = 0xff;
|
||||
character &= 0x7f;
|
||||
}
|
||||
font_data = MEMORY_mem[0xe000 + character*8 + line];
|
||||
font_data ^= invert;
|
||||
return font_data;
|
||||
}
|
||||
|
||||
/*
|
||||
vim:ts=4:sw=4:
|
||||
*/
|
||||
@@ -1,14 +0,0 @@
|
||||
#ifndef PBI_PROTO80_H_
|
||||
#define PBI_PROTO80_H_
|
||||
|
||||
#include "atari.h"
|
||||
int PBI_PROTO80_Initialise(int *argc, char *argv[]);
|
||||
int PBI_PROTO80_ReadConfig(char *string, char *ptr);
|
||||
void PBI_PROTO80_WriteConfig(FILE *fp);
|
||||
int PBI_PROTO80_D1GetByte(UWORD addr);
|
||||
void PBI_PROTO80_D1PutByte(UWORD addr, UBYTE byte);
|
||||
int PBI_PROTO80_D1ffPutByte(UBYTE byte);
|
||||
UBYTE PBI_PROTO80_GetPixels(int scanline, int column);
|
||||
extern int PBI_PROTO80_enabled;
|
||||
|
||||
#endif /* PBI_PROTO80_H_ */
|
||||
@@ -1,241 +0,0 @@
|
||||
/*
|
||||
* pbi_scsi.c - SCSI emulation for the MIO and Black Box
|
||||
*
|
||||
* Copyright (C) 2007-2008 Perry McFarlane
|
||||
* Copyright (C) 1998-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "atari.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "pbi_scsi.h"
|
||||
|
||||
#ifdef PBI_DEBUG
|
||||
#define D(a) a
|
||||
#else
|
||||
#define D(a) do{}while(0)
|
||||
#endif
|
||||
|
||||
int PBI_SCSI_CD = FALSE;
|
||||
int PBI_SCSI_MSG = FALSE;
|
||||
int PBI_SCSI_IO = FALSE;
|
||||
int PBI_SCSI_BSY = FALSE;
|
||||
int PBI_SCSI_REQ = FALSE;
|
||||
int PBI_SCSI_ACK = FALSE;
|
||||
|
||||
int PBI_SCSI_SEL = FALSE;
|
||||
|
||||
static UBYTE scsi_byte;
|
||||
|
||||
#define SCSI_PHASE_SELECTION 0
|
||||
#define SCSI_PHASE_DATAIN 1
|
||||
#define SCSI_PHASE_DATAOUT 2
|
||||
#define SCSI_PHASE_COMMAND 3
|
||||
#define SCSI_PHASE_STATUS 4
|
||||
#define SCSI_PHASE_MSGIN 5
|
||||
|
||||
static int scsi_phase = SCSI_PHASE_SELECTION;
|
||||
static int scsi_bufpos = 0;
|
||||
static UBYTE scsi_buffer[256];
|
||||
static int scsi_count = 0;
|
||||
|
||||
FILE *PBI_SCSI_disk = NULL;
|
||||
|
||||
static void scsi_changephase(int phase)
|
||||
{
|
||||
D(printf("scsi_changephase:%d\n",phase));
|
||||
switch(phase) {
|
||||
case SCSI_PHASE_SELECTION:
|
||||
PBI_SCSI_REQ = FALSE;
|
||||
PBI_SCSI_BSY = FALSE;
|
||||
PBI_SCSI_CD = FALSE;
|
||||
PBI_SCSI_IO = FALSE;
|
||||
PBI_SCSI_MSG = FALSE;
|
||||
break;
|
||||
case SCSI_PHASE_DATAOUT:
|
||||
PBI_SCSI_REQ = TRUE;
|
||||
PBI_SCSI_BSY = TRUE;
|
||||
PBI_SCSI_CD = FALSE;
|
||||
PBI_SCSI_IO = FALSE;
|
||||
PBI_SCSI_MSG = FALSE;
|
||||
break;
|
||||
case SCSI_PHASE_DATAIN:
|
||||
PBI_SCSI_REQ = TRUE;
|
||||
PBI_SCSI_BSY = TRUE;
|
||||
PBI_SCSI_CD = FALSE;
|
||||
PBI_SCSI_IO = TRUE;
|
||||
PBI_SCSI_MSG = FALSE;
|
||||
break;
|
||||
case SCSI_PHASE_COMMAND:
|
||||
PBI_SCSI_REQ = TRUE;
|
||||
PBI_SCSI_BSY = TRUE;
|
||||
PBI_SCSI_CD = TRUE;
|
||||
PBI_SCSI_IO = FALSE;
|
||||
PBI_SCSI_MSG = FALSE;
|
||||
break;
|
||||
case SCSI_PHASE_STATUS:
|
||||
PBI_SCSI_REQ = TRUE;
|
||||
PBI_SCSI_BSY = TRUE;
|
||||
PBI_SCSI_CD = TRUE;
|
||||
PBI_SCSI_IO = TRUE;
|
||||
PBI_SCSI_MSG = FALSE;
|
||||
break;
|
||||
case SCSI_PHASE_MSGIN:
|
||||
PBI_SCSI_REQ = TRUE;
|
||||
PBI_SCSI_BSY = TRUE;
|
||||
PBI_SCSI_CD = TRUE;
|
||||
PBI_SCSI_IO = FALSE;
|
||||
PBI_SCSI_MSG = TRUE;
|
||||
break;
|
||||
}
|
||||
scsi_bufpos = 0;
|
||||
scsi_phase = phase;
|
||||
}
|
||||
|
||||
static void scsi_process_command(void)
|
||||
{
|
||||
int i;
|
||||
int lba;
|
||||
int lun;
|
||||
D(printf("SCSI command:"));
|
||||
for (i = 0; i < 6; i++) {
|
||||
D(printf(" %02x",scsi_buffer[i]));
|
||||
}
|
||||
D(printf("\n"));
|
||||
switch (scsi_buffer[0]) {
|
||||
case 0x00:
|
||||
/* test unit ready */
|
||||
D(printf("SCSI: test unit ready\n"));
|
||||
scsi_changephase(SCSI_PHASE_STATUS);
|
||||
scsi_buffer[0] = 0;
|
||||
break;
|
||||
case 0x03:
|
||||
/* request sense */
|
||||
D(printf("SCSI: request sense\n"));
|
||||
scsi_changephase(SCSI_PHASE_DATAIN);
|
||||
memset(scsi_buffer,0,1);
|
||||
scsi_count = 4;
|
||||
break;
|
||||
case 0x08:
|
||||
/* read */
|
||||
lun = ((scsi_buffer[1]&0xe0)>>5);
|
||||
lba = (((scsi_buffer[1]&0x1f)<<16)|(scsi_buffer[2]<<8)|(scsi_buffer[3]));
|
||||
D(printf("SCSI: read lun:%d lba:%d\n",lun,lba));
|
||||
fseek(PBI_SCSI_disk, lba*256, SEEK_SET);
|
||||
fread(scsi_buffer, 1, 256, PBI_SCSI_disk);
|
||||
scsi_changephase(SCSI_PHASE_DATAIN);
|
||||
scsi_count = 256;
|
||||
break;
|
||||
case 0x0a:
|
||||
/* write */
|
||||
lun = ((scsi_buffer[1]&0xe0)>>5);
|
||||
lba = (((scsi_buffer[1]&0x1f)<<16)|(scsi_buffer[2]<<8)|(scsi_buffer[3]));
|
||||
D(printf("SCSI: write lun:%d lba:%d\n",lun,lba));
|
||||
fseek(PBI_SCSI_disk, lba*256, SEEK_SET);
|
||||
scsi_changephase(SCSI_PHASE_DATAOUT);
|
||||
scsi_count = 256;
|
||||
break;
|
||||
default:
|
||||
D(printf("SCSI: unknown command:%2x\n", scsi_buffer[0]));
|
||||
scsi_changephase(SCSI_PHASE_SELECTION);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void scsi_nextbyte(void)
|
||||
{
|
||||
if (scsi_phase == SCSI_PHASE_DATAIN) {
|
||||
scsi_bufpos++;
|
||||
if (scsi_bufpos >= scsi_count) {
|
||||
scsi_changephase(SCSI_PHASE_STATUS);
|
||||
scsi_buffer[0] = 0;
|
||||
}
|
||||
}
|
||||
else if (scsi_phase == SCSI_PHASE_STATUS) {
|
||||
D(printf("SCSI status\n"));
|
||||
scsi_changephase(SCSI_PHASE_MSGIN);
|
||||
scsi_buffer[0] = 0;
|
||||
}
|
||||
else if (scsi_phase == SCSI_PHASE_MSGIN) {
|
||||
D(printf("SCSI msg\n"));
|
||||
scsi_changephase(SCSI_PHASE_SELECTION);
|
||||
}
|
||||
else if (scsi_phase == SCSI_PHASE_COMMAND) {
|
||||
scsi_buffer[scsi_bufpos++] = scsi_byte;
|
||||
if (scsi_bufpos >= 0x06) {
|
||||
scsi_process_command();
|
||||
scsi_bufpos = 0;
|
||||
}
|
||||
}
|
||||
else if (scsi_phase == SCSI_PHASE_DATAOUT) {
|
||||
D(printf("SCSI data out:%2x\n", scsi_byte));
|
||||
scsi_buffer[scsi_bufpos++] = scsi_byte;
|
||||
if (scsi_bufpos >= scsi_count) {
|
||||
fwrite(scsi_buffer, 1, 256, PBI_SCSI_disk);
|
||||
scsi_changephase(SCSI_PHASE_STATUS);
|
||||
scsi_buffer[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PBI_SCSI_PutSEL(int newsel)
|
||||
{
|
||||
if (newsel != PBI_SCSI_SEL) {
|
||||
/* SEL changed state */
|
||||
PBI_SCSI_SEL = newsel;
|
||||
if (PBI_SCSI_SEL && scsi_phase == SCSI_PHASE_SELECTION && scsi_byte == 0x01) {
|
||||
scsi_changephase(SCSI_PHASE_COMMAND);
|
||||
}
|
||||
D(printf("changed SEL:%d scsi_byte:%2x\n",PBI_SCSI_SEL, scsi_byte));
|
||||
}
|
||||
}
|
||||
|
||||
void PBI_SCSI_PutACK(int newack)
|
||||
{
|
||||
if (newack != PBI_SCSI_ACK) {
|
||||
/* ACK changed state */
|
||||
PBI_SCSI_ACK = newack;
|
||||
if (PBI_SCSI_ACK) {
|
||||
/* REQ goes false when ACK goes true */
|
||||
PBI_SCSI_REQ = FALSE;
|
||||
}
|
||||
else {
|
||||
/* falling ACK triggers next byte */
|
||||
if (scsi_phase != SCSI_PHASE_SELECTION) {
|
||||
PBI_SCSI_REQ = TRUE;
|
||||
scsi_nextbyte();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UBYTE PBI_SCSI_GetByte(void)
|
||||
{
|
||||
return (scsi_buffer[scsi_bufpos]);
|
||||
}
|
||||
|
||||
void PBI_SCSI_PutByte(UBYTE byte)
|
||||
{
|
||||
scsi_byte = byte;
|
||||
}
|
||||
|
||||
/*
|
||||
vim:ts=4:sw=4:
|
||||
*/
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef PBI_SCSI_H_
|
||||
#define PBI_SCSI_H_
|
||||
|
||||
#include "atari.h"
|
||||
#include <stdio.h>
|
||||
|
||||
extern int PBI_SCSI_CD;
|
||||
extern int PBI_SCSI_MSG;
|
||||
extern int PBI_SCSI_IO;
|
||||
extern int PBI_SCSI_BSY;
|
||||
extern int PBI_SCSI_REQ;
|
||||
extern int PBI_SCSI_SEL;
|
||||
extern int PBI_SCSI_ACK;
|
||||
extern FILE *PBI_SCSI_disk;
|
||||
|
||||
void PBI_SCSI_PutByte(UBYTE byte);
|
||||
UBYTE PBI_SCSI_GetByte(void);
|
||||
void PBI_SCSI_PutSEL(int newsel);
|
||||
void PBI_SCSI_PutACK(int newack);
|
||||
|
||||
#endif /* PBI_MIO_H_ */
|
||||
@@ -1,921 +0,0 @@
|
||||
/*
|
||||
* pbi_xld.c - 1450XLD and 1400XL emulation
|
||||
*
|
||||
* Copyright (C) 2007-2008 Perry McFarlane
|
||||
* Copyright (C) 2002-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "atari.h"
|
||||
#include "votrax.h"
|
||||
#include "pbi_xld.h"
|
||||
#include "pbi.h"
|
||||
#include "util.h"
|
||||
#include "sio.h"
|
||||
#include "log.h"
|
||||
#include "pokey.h"
|
||||
#include "cpu.h"
|
||||
#include "memory.h"
|
||||
#include "statesav.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DISK_PBI_NUM 0
|
||||
#define MODEM_PBI_NUM 1
|
||||
#define VOICE_PBI_NUM 7
|
||||
|
||||
#define DISK_MASK (1 << DISK_PBI_NUM)
|
||||
#define MODEM_MASK (1 << MODEM_PBI_NUM)
|
||||
#define VOICE_MASK (1 << VOICE_PBI_NUM)
|
||||
|
||||
static UBYTE *voicerom;
|
||||
static UBYTE *diskrom;
|
||||
static char xld_d_rom_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
static char xld_v_rom_filename[FILENAME_MAX] = Util_FILENAME_NOT_SET;
|
||||
|
||||
static UBYTE votrax_latch = 0;
|
||||
static UBYTE modem_latch = 0;
|
||||
|
||||
int PBI_XLD_enabled = FALSE;
|
||||
static int xld_v_enabled = FALSE;
|
||||
static int xld_d_enabled = FALSE;
|
||||
|
||||
/* Parallel Disk I/O emulation support */
|
||||
#define PIO_NoFrame (0x00)
|
||||
#define PIO_CommandFrame (0x01)
|
||||
#define PIO_StatusRead (0x02)
|
||||
#define PIO_ReadFrame (0x03)
|
||||
#define PIO_WriteFrame (0x04)
|
||||
#define PIO_FinalStatus (0x05)
|
||||
#define PIO_FormatFrame (0x06)
|
||||
static UBYTE CommandFrame[6];
|
||||
static int CommandIndex = 0;
|
||||
static UBYTE DataBuffer[256 + 3];
|
||||
static int DataIndex = 0;
|
||||
static int TransferStatus = PIO_CommandFrame;
|
||||
static int ExpectedBytes = 5;
|
||||
static void PIO_PutByte(int byte);
|
||||
static int PIO_GetByte(void);
|
||||
static UBYTE PIO_Command_Frame(void);
|
||||
|
||||
/* Votrax */
|
||||
static double ratio;
|
||||
static int bit16;
|
||||
#define VTRX_BLOCK_SIZE 1024
|
||||
SWORD *temp_votrax_buffer = NULL;
|
||||
SWORD *votrax_buffer = NULL;
|
||||
static int votrax_busy = FALSE;
|
||||
static volatile int votrax_written = FALSE;
|
||||
static volatile int votrax_written_byte = 0x3f;
|
||||
static int votrax_sync_samples;
|
||||
static void votrax_busy_callback(int busy_status);
|
||||
static int dsprate;
|
||||
static int num_pokeys;
|
||||
static int samples_per_frame;
|
||||
|
||||
#ifdef PBI_DEBUG
|
||||
#define D(a) a
|
||||
#else
|
||||
#define D(a) do{}while(0)
|
||||
#endif
|
||||
|
||||
#define VTRX_RATE 24500
|
||||
|
||||
static void init_xld_v(void)
|
||||
{
|
||||
free(voicerom);
|
||||
voicerom = (UBYTE *)Util_malloc(0x1000);
|
||||
if (!Atari800_LoadImage(xld_v_rom_filename, voicerom, 0x1000)) {
|
||||
free(voicerom);
|
||||
xld_v_enabled = FALSE;
|
||||
}
|
||||
else {
|
||||
printf("loaded XLD voice rom image\n");
|
||||
PBI_D6D7ram = TRUE;
|
||||
}
|
||||
votrax_busy = FALSE;
|
||||
votrax_sync_samples = 0;
|
||||
}
|
||||
|
||||
static void init_xld_d(void)
|
||||
{
|
||||
free(diskrom);
|
||||
diskrom = (UBYTE *)Util_malloc(0x800);
|
||||
if (!Atari800_LoadImage(xld_d_rom_filename, diskrom, 0x800)) {
|
||||
free(diskrom);
|
||||
xld_d_enabled = FALSE;
|
||||
}
|
||||
else {
|
||||
D(printf("loaded 1450XLD D: device driver rom image\n"));
|
||||
PBI_D6D7ram = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
int PBI_XLD_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
int i, j;
|
||||
for (i = j = 1; i < *argc; i++) {
|
||||
if (strcmp(argv[i], "-1400") == 0) {
|
||||
xld_v_enabled = TRUE;
|
||||
PBI_XLD_enabled = TRUE;
|
||||
}else if (strcmp(argv[i], "-xld") == 0){
|
||||
xld_v_enabled = TRUE;
|
||||
xld_d_enabled = TRUE;
|
||||
PBI_XLD_enabled = TRUE;
|
||||
}
|
||||
else {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
Log_print("\t-1400 Emulate the Atari 1400XL");
|
||||
Log_print("\t-xld Emulate the Atari 1450XLD");
|
||||
}
|
||||
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
|
||||
}
|
||||
*argc = j;
|
||||
|
||||
if (xld_v_enabled) {
|
||||
init_xld_v();
|
||||
}
|
||||
|
||||
/* If you set the drive to empty in the UI, the message is displayed */
|
||||
/* If you press select, I believe it tries to slow the I/O down */
|
||||
/* in order to increase compatibility. */
|
||||
/* dskcnt6 works. dskcnt10 does not */
|
||||
if (xld_d_enabled) {
|
||||
init_xld_d();
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int PBI_XLD_ReadConfig(char *string, char *ptr)
|
||||
{
|
||||
if (strcmp(string, "XLD_D_ROM") == 0)
|
||||
Util_strlcpy(xld_d_rom_filename, ptr, sizeof(xld_d_rom_filename));
|
||||
else if (strcmp(string, "XLD_V_ROM") == 0)
|
||||
Util_strlcpy(xld_v_rom_filename, ptr, sizeof(xld_v_rom_filename));
|
||||
else return FALSE; /* no match */
|
||||
return TRUE; /* matched something */
|
||||
}
|
||||
|
||||
void PBI_XLD_WriteConfig(FILE *fp)
|
||||
{
|
||||
fprintf(fp, "XLD_D_ROM=%s\n", xld_d_rom_filename);
|
||||
fprintf(fp, "XLD_V_ROM=%s\n", xld_v_rom_filename);
|
||||
}
|
||||
|
||||
void PBI_XLD_Reset(void)
|
||||
{
|
||||
votrax_latch = 0;
|
||||
}
|
||||
|
||||
int PBI_XLD_D1GetByte(UWORD addr)
|
||||
{
|
||||
int result = PBI_NOT_HANDLED;
|
||||
if (xld_d_enabled && addr == 0xd114) {
|
||||
/* XLD input from disk to atari byte latch */
|
||||
result = (int)PIO_GetByte();
|
||||
D(printf("d114: disk read byte:%2x\n",result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* D1FF: each bit indicates IRQ status of a device */
|
||||
UBYTE PBI_XLD_D1ffGetByte()
|
||||
{
|
||||
UBYTE result = 0;
|
||||
/* VOTRAX BUSY IRQ bit */
|
||||
/*if (!votraxsc01_status_r()) {*/
|
||||
if (!votrax_busy) {
|
||||
result |= VOICE_MASK;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void PBI_XLD_D1PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
if ((addr & ~3) == 0xd104) {
|
||||
/* XLD disk strobe line */
|
||||
D(printf("votrax write:%4x\n",addr));
|
||||
votrax_sync_samples = (int)((1.0/ratio)*(double)Votrax_Samples(votrax_written_byte, votrax_latch & 0x3f, votrax_sync_samples));
|
||||
votrax_written = TRUE;
|
||||
votrax_written_byte = votrax_latch & 0x3f;
|
||||
if (!votrax_busy) {
|
||||
votrax_busy = TRUE;
|
||||
votrax_busy_callback(TRUE); /* idle -> busy */
|
||||
}
|
||||
|
||||
}
|
||||
else if ((addr & ~3) == 0xd100 ) {
|
||||
/* votrax phoneme+irq-enable latch */
|
||||
if ( !(votrax_latch & 0x80) && (byte & 0x80) && (!Votrax_GetStatus())) {
|
||||
/* IRQ disabled -> enabled, and votrax idle: generate IRQ */
|
||||
D(printf("votrax IRQ generated: IRQ enable changed and idle\n"));
|
||||
CPU_GenerateIRQ();
|
||||
PBI_IRQ |= VOICE_MASK;
|
||||
} else if ((votrax_latch & 0x80) && !(byte & 0x80) ){
|
||||
/* IRQ enabled -> disabled : stop IRQ */
|
||||
PBI_IRQ &= ~VOICE_MASK;
|
||||
/* update pokey IRQ status */
|
||||
POKEY_PutByte(POKEY_OFFSET_IRQEN, POKEY_IRQEN);
|
||||
}
|
||||
votrax_latch = byte;
|
||||
}
|
||||
else if (addr == 0xd108) {
|
||||
/* modem latch and XLD 8040 T1 input */
|
||||
D(printf("XLD 8040 T1:%d loop-back:%d modem+phone:%d offhook(modem relay):%d phaudio:%d DTMF:%d O/!A(originate/answer):%d SQT(squelch transmitter):%d\n",!!(byte&0x80),!!(byte&0x40),!!(byte&0x20),!!(byte&0x10),!!(byte&0x08),!!(byte&0x04),!!(byte&0x02),!!(byte&0x01)));
|
||||
modem_latch = byte;
|
||||
}
|
||||
else if (xld_d_enabled && addr == 0xd110) {
|
||||
/* XLD byte output from atari to disk latch */
|
||||
D(printf("d110: disk output byte:%2x\n",byte));
|
||||
if (modem_latch & 0x80){
|
||||
/* 8040 T1=1 */
|
||||
CommandIndex = 0;
|
||||
DataIndex = 0;
|
||||
TransferStatus = PIO_CommandFrame;
|
||||
ExpectedBytes = 5;
|
||||
D(printf("command frame expected\n"));
|
||||
}
|
||||
else if (TransferStatus == PIO_StatusRead || TransferStatus == PIO_ReadFrame) {
|
||||
D(printf("read ack strobe\n"));
|
||||
}
|
||||
else {
|
||||
PIO_PutByte(byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PBI_XLD_D1ffPutByte(UBYTE byte)
|
||||
{
|
||||
int result = 0; /* handled */
|
||||
if (xld_d_enabled && byte == DISK_MASK) {
|
||||
memcpy(MEMORY_mem + 0xd800, diskrom, 0x800);
|
||||
D(printf("DISK rom activated\n"));
|
||||
}
|
||||
else if (byte == MODEM_MASK) {
|
||||
memcpy(MEMORY_mem + 0xd800, voicerom + 0x800, 0x800);
|
||||
D(printf("MODEM rom activated\n"));
|
||||
}
|
||||
else if (byte == VOICE_MASK) {
|
||||
memcpy(MEMORY_mem + 0xd800, voicerom, 0x800);
|
||||
D(printf("VOICE rom activated\n"));
|
||||
}
|
||||
else result = PBI_NOT_HANDLED;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void votrax_busy_callback(int busy_status)
|
||||
{
|
||||
if (!busy_status && (votrax_latch & 0x80)){
|
||||
/* busy->idle and IRQ enabled */
|
||||
D(printf("votrax IRQ generated\n"));
|
||||
CPU_GenerateIRQ();
|
||||
PBI_IRQ |= VOICE_MASK;
|
||||
}
|
||||
else if (busy_status && (PBI_IRQ & VOICE_MASK)) {
|
||||
/* idle->busy and PBI_IRQ set */
|
||||
PBI_IRQ &= ~VOICE_MASK;
|
||||
/* update pokey IRQ status */
|
||||
POKEY_PutByte(POKEY_OFFSET_IRQEN, POKEY_IRQEN);
|
||||
}
|
||||
}
|
||||
|
||||
static void votrax_busy_callback_async(int busy_status)
|
||||
{
|
||||
return;
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
/* from sio.c */
|
||||
static UBYTE WriteSectorBack(void)
|
||||
{
|
||||
UWORD sector;
|
||||
UBYTE unit;
|
||||
|
||||
sector = CommandFrame[2] + (CommandFrame[3] << 8);
|
||||
unit = CommandFrame[0] - '1';
|
||||
if (unit >= SIO_MAX_DRIVES) /* UBYTE range ! */
|
||||
return 0;
|
||||
switch (CommandFrame[1]) {
|
||||
case 0x4f: /* Write Status Block */
|
||||
return SIO_WriteStatusBlock(unit, DataBuffer);
|
||||
case 0x50: /* Write */
|
||||
case 0x57:
|
||||
case 0xD0: /* xf551 hispeed */
|
||||
case 0xD7:
|
||||
return SIO_WriteSector(unit, sector, DataBuffer);
|
||||
default:
|
||||
return 'E';
|
||||
}
|
||||
}
|
||||
|
||||
/* Put a byte that comes from the parallel bus */
|
||||
static void PIO_PutByte(int byte)
|
||||
{
|
||||
D(printf("TransferStatus:%d\n",TransferStatus));
|
||||
switch (TransferStatus) {
|
||||
case PIO_CommandFrame:
|
||||
D(printf("CommandIndex:%d ExpectedBytes:%d\n",CommandIndex,ExpectedBytes));
|
||||
if (CommandIndex < ExpectedBytes) {
|
||||
CommandFrame[CommandIndex++] = byte;
|
||||
if (CommandIndex >= ExpectedBytes) {
|
||||
if (CommandFrame[0] >= 0x31 && CommandFrame[0] <= 0x38) {
|
||||
TransferStatus = PIO_StatusRead;
|
||||
/*DELAYED_SERIN_IRQ = SERIN_INTERVAL + ACK_INTERVAL;*/
|
||||
D(printf("TransferStatus = PIO_StatusRead\n"));
|
||||
}
|
||||
else{
|
||||
TransferStatus = PIO_NoFrame;
|
||||
D(printf("TransferStatus = PIO_NoFrame\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log_print("Invalid command frame!");
|
||||
TransferStatus = PIO_NoFrame;
|
||||
}
|
||||
break;
|
||||
case PIO_WriteFrame: /* Expect data */
|
||||
if (DataIndex < ExpectedBytes) {
|
||||
DataBuffer[DataIndex++] = byte;
|
||||
if (DataIndex >= ExpectedBytes) {
|
||||
UBYTE sum = SIO_ChkSum(DataBuffer, ExpectedBytes - 1);
|
||||
if (sum == DataBuffer[ExpectedBytes - 1]) {
|
||||
UBYTE result = WriteSectorBack();
|
||||
if (result != 0) {
|
||||
DataBuffer[0] = 'A';
|
||||
DataBuffer[1] = result;
|
||||
DataIndex = 0;
|
||||
ExpectedBytes = 2;
|
||||
/*DELAYED_SERIN_IRQ = SERIN_INTERVAL + ACK_INTERVAL;*/
|
||||
TransferStatus = PIO_FinalStatus;
|
||||
}
|
||||
else
|
||||
TransferStatus = PIO_NoFrame;
|
||||
}
|
||||
else {
|
||||
DataBuffer[0] = 'E';
|
||||
DataIndex = 0;
|
||||
ExpectedBytes = 1;
|
||||
/*DELAYED_SERIN_IRQ = SERIN_INTERVAL + ACK_INTERVAL;*/
|
||||
TransferStatus = PIO_FinalStatus;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Log_print("Invalid data frame!");
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*DELAYED_SEROUT_IRQ = SEROUT_INTERVAL;*/
|
||||
}
|
||||
|
||||
/* Get a byte from the floppy to the parallel bus. */
|
||||
static int PIO_GetByte(void)
|
||||
{
|
||||
int byte = 0;
|
||||
D(printf("PIO_GetByte TransferStatus:%d\n",TransferStatus));
|
||||
|
||||
switch (TransferStatus) {
|
||||
case PIO_StatusRead:
|
||||
byte = PIO_Command_Frame(); /* Handle now the command */
|
||||
break;
|
||||
case PIO_FormatFrame:
|
||||
TransferStatus = PIO_ReadFrame;
|
||||
/*DELAYED_SERIN_IRQ = SERIN_INTERVAL << 3;*/
|
||||
/* FALL THROUGH */
|
||||
case PIO_ReadFrame:
|
||||
D(printf("ReadFrame: DataIndex:%d ExpectedBytes:%d\n",DataIndex,ExpectedBytes));
|
||||
if (DataIndex < ExpectedBytes) {
|
||||
byte = DataBuffer[DataIndex++];
|
||||
if (DataIndex >= ExpectedBytes) {
|
||||
TransferStatus = PIO_NoFrame;
|
||||
}
|
||||
/*else {*/
|
||||
/* set delay using the expected transfer speed */
|
||||
/*DELAYED_SERIN_IRQ = (DataIndex == 1) ? SERIN_INTERVAL*/
|
||||
/*: ((SERIN_INTERVAL * AUDF[CHAN3] - 1) / 0x28 + 1);*/
|
||||
/*}*/
|
||||
}
|
||||
else {
|
||||
Log_print("Invalid read frame!");
|
||||
TransferStatus = PIO_NoFrame;
|
||||
}
|
||||
break;
|
||||
case PIO_FinalStatus:
|
||||
if (DataIndex < ExpectedBytes) {
|
||||
byte = DataBuffer[DataIndex++];
|
||||
if (DataIndex >= ExpectedBytes) {
|
||||
TransferStatus = PIO_NoFrame;
|
||||
}
|
||||
/*else {
|
||||
if (DataIndex == 0)
|
||||
DELAYED_SERIN_IRQ = SERIN_INTERVAL + ACK_INTERVAL;
|
||||
else
|
||||
DELAYED_SERIN_IRQ = SERIN_INTERVAL;
|
||||
}*/
|
||||
}
|
||||
else {
|
||||
Log_print("Invalid read frame!");
|
||||
TransferStatus = PIO_NoFrame;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
static UBYTE PIO_Command_Frame(void)
|
||||
{
|
||||
int unit;
|
||||
int sector;
|
||||
int realsize;
|
||||
|
||||
sector = CommandFrame[2] | (((UWORD) CommandFrame[3]) << 8);
|
||||
unit = CommandFrame[0] - '1';
|
||||
|
||||
if (unit < 0 || unit >= SIO_MAX_DRIVES) {
|
||||
/* Unknown device */
|
||||
Log_print("Unknown command frame: %02x %02x %02x %02x %02x",
|
||||
CommandFrame[0], CommandFrame[1], CommandFrame[2],
|
||||
CommandFrame[3], CommandFrame[4]);
|
||||
TransferStatus = PIO_NoFrame;
|
||||
return 0;
|
||||
}
|
||||
switch (CommandFrame[1]) {
|
||||
case 0x01:
|
||||
Log_print("PIO DISK: Set large mode (unimplemented)");
|
||||
return 'E';
|
||||
case 0x02:
|
||||
Log_print("PIO DISK: Set small mode (unimplemented)");
|
||||
return 'E';
|
||||
case 0x23:
|
||||
Log_print("PIO DISK: Drive Diagnostic In (unimplemented)");
|
||||
return 'E';
|
||||
case 0x24:
|
||||
Log_print("PIO DISK: Drive Diagnostic Out (unimplemented)");
|
||||
return 'E';
|
||||
case 0x4e: /* Read Status */
|
||||
#ifdef PBI_DEBUG
|
||||
Log_print("PIO DISK: Read-status frame: %02x %02x %02x %02x %02x",
|
||||
CommandFrame[0], CommandFrame[1], CommandFrame[2],
|
||||
CommandFrame[3], CommandFrame[4]);
|
||||
#endif
|
||||
DataBuffer[0] = SIO_ReadStatusBlock(unit, DataBuffer + 1);
|
||||
DataBuffer[13] = SIO_ChkSum(DataBuffer + 1, 12);
|
||||
DataIndex = 0;
|
||||
ExpectedBytes = 14;
|
||||
TransferStatus = PIO_ReadFrame;
|
||||
/*DELAYED_SERIN_IRQ = SERIN_INTERVAL;*/
|
||||
return 'A';
|
||||
case 0x4f: /* Write status */
|
||||
#ifdef PBI_DEBUG
|
||||
Log_print("PIO DISK: Write-status frame: %02x %02x %02x %02x %02x",
|
||||
CommandFrame[0], CommandFrame[1], CommandFrame[2],
|
||||
CommandFrame[3], CommandFrame[4]);
|
||||
#endif
|
||||
ExpectedBytes = 13;
|
||||
DataIndex = 0;
|
||||
TransferStatus = PIO_WriteFrame;
|
||||
return 'A';
|
||||
case 0x50: /* Write */
|
||||
case 0x57:
|
||||
#ifdef PBI_DEBUG
|
||||
Log_print("PIO DISK: Write-sector frame: %02x %02x %02x %02x %02x",
|
||||
CommandFrame[0], CommandFrame[1], CommandFrame[2],
|
||||
CommandFrame[3], CommandFrame[4]);
|
||||
#endif
|
||||
SIO_SizeOfSector((UBYTE) unit, sector, &realsize, NULL);
|
||||
ExpectedBytes = realsize + 1;
|
||||
DataIndex = 0;
|
||||
TransferStatus = PIO_WriteFrame;
|
||||
SIO_last_op = SIO_LAST_WRITE;
|
||||
SIO_last_op_time = 10;
|
||||
SIO_last_drive = unit + 1;
|
||||
return 'A';
|
||||
case 0x52: /* Read */
|
||||
#ifdef PBI_DEBUG
|
||||
Log_print("PIO DISK: Read-sector frame: %02x %02x %02x %02x %02x",
|
||||
CommandFrame[0], CommandFrame[1], CommandFrame[2],
|
||||
CommandFrame[3], CommandFrame[4]);
|
||||
#endif
|
||||
SIO_SizeOfSector((UBYTE) unit, sector, &realsize, NULL);
|
||||
DataBuffer[0] = SIO_ReadSector(unit, sector, DataBuffer + 1);
|
||||
DataBuffer[1 + realsize] = SIO_ChkSum(DataBuffer + 1, realsize);
|
||||
DataIndex = 0;
|
||||
ExpectedBytes = 2 + realsize;
|
||||
TransferStatus = PIO_ReadFrame;
|
||||
/* wait longer before confirmation because bytes could be lost */
|
||||
/* before the buffer was set (see $E9FB & $EA37 in XL-OS) */
|
||||
/*DELAYED_SERIN_IRQ = SERIN_INTERVAL << 2;*/
|
||||
/*
|
||||
#ifndef NO_SECTOR_DELAY
|
||||
if (sector == 1) {
|
||||
//DELAYED_SERIN_IRQ += delay_counter;
|
||||
delay_counter = SECTOR_DELAY;
|
||||
}
|
||||
else {
|
||||
delay_counter = 0;
|
||||
}
|
||||
#endif*/
|
||||
SIO_last_op = SIO_LAST_READ;
|
||||
SIO_last_op_time = 10;
|
||||
SIO_last_drive = unit + 1;
|
||||
return 'A';
|
||||
case 0x53: /* Status */
|
||||
/*
|
||||
from spec doc:
|
||||
BYTE 1 - DISK STATUS
|
||||
|
||||
BIT 0 = 1 indicates an invalid
|
||||
command frame was receiv-
|
||||
ed.
|
||||
BIT 1 = 1 indicates an invalid
|
||||
data frame was received.
|
||||
BIT 2 = 1 indicates an opera-
|
||||
tion was unsuccessful.
|
||||
BIT 3 = 1 indicates the disk-
|
||||
ette is write protected.
|
||||
BIT 4 = 1 indicates drive is
|
||||
active.
|
||||
BITS 5-7 = 100 indicates single
|
||||
density format.
|
||||
BITS 5-7 = 101 indicates double
|
||||
density format.
|
||||
|
||||
BYTE 2 - DISK CONTROLLER HARDWARE
|
||||
STATUS
|
||||
|
||||
This byte shall contain the in-
|
||||
verted value of the disk con-
|
||||
troller hardware status regis-
|
||||
ter as of the last operation.
|
||||
The hardware status value for
|
||||
no errors shall be $FF. A zero
|
||||
in any bit position shall indi-
|
||||
cate an error. The definition
|
||||
of the bit positions shall be:
|
||||
|
||||
BIT 0 = 0 indicates device busy
|
||||
BIT 1 = 0 indicates data re-
|
||||
quest is full on a read
|
||||
operation.
|
||||
BIT 2 = 0 indicates data lost
|
||||
BIT 3 = 0 indicates CRC error
|
||||
BIT 4 = 0 indicates desired
|
||||
track and sector not found
|
||||
BIT 5 = 0 indicates record
|
||||
type/write fault
|
||||
BIT 6 NOT USED
|
||||
*BIT 7 = 0 indicates device not
|
||||
ready (door open)
|
||||
|
||||
BYTES 3 & 4 - TIMEOUT
|
||||
|
||||
These bytes shall contain a
|
||||
disk controller provided maxi-
|
||||
mum timeout value, in seconds,
|
||||
for the worst case command. The
|
||||
worst case operation is for a
|
||||
disk format command (time TBD
|
||||
seconds). Byte 4 is not used,
|
||||
currently.*/
|
||||
/*****Compare with:******/
|
||||
/*
|
||||
Status Request from Atari 400/800 Technical Reference Notes
|
||||
|
||||
DVSTAT + 0 Command Status
|
||||
DVSTAT + 1 Hardware Status
|
||||
DVSTAT + 2 Timeout
|
||||
DVSTAT + 3 Unused
|
||||
|
||||
Command Status Bits
|
||||
|
||||
Bit 0 = 1 indicates an invalid command frame was received(same)
|
||||
Bit 1 = 1 indicates an invalid data frame was received(same)
|
||||
Bit 2 = 1 indicates that last read/write operation was unsuccessful(same)
|
||||
Bit 3 = 1 indicates that the diskette is write protected(same)
|
||||
Bit 4 = 1 indicates active/standby(same)
|
||||
|
||||
plus
|
||||
|
||||
Bit 5 = 1 indicates double density
|
||||
Bit 7 = 1 indicates dual density disk (1050 format)
|
||||
*/
|
||||
|
||||
#ifdef PBI_DEBUG
|
||||
Log_print("PIO DISK: Status frame: %02x %02x %02x %02x %02x",
|
||||
CommandFrame[0], CommandFrame[1], CommandFrame[2],
|
||||
CommandFrame[3], CommandFrame[4]);
|
||||
#endif
|
||||
/*if (SIO_drive_status[unit]==SIO_OFF) SIO_drive_status[unit]=SIO_NO_DISK;*/
|
||||
/*need to modify the line below also for SIO_OFF==SIO_NO_DISK*/
|
||||
DataBuffer[0] = SIO_DriveStatus(unit, DataBuffer + 1);
|
||||
DataBuffer[2] = 0xff;/*/1;//SIO_DriveStatus(unit, DataBuffer + 1);*/
|
||||
if (SIO_drive_status[unit]==SIO_NO_DISK || SIO_drive_status[unit]==SIO_OFF){
|
||||
/*Can't turn 1450XLD drives off, so make SIO_OFF==SIO_NO_DISK*/
|
||||
DataBuffer[2]=0x7f;
|
||||
}
|
||||
DataBuffer[1 + 4] = SIO_ChkSum(DataBuffer + 1, 4);
|
||||
DataIndex = 0;
|
||||
ExpectedBytes = 6;
|
||||
TransferStatus = PIO_ReadFrame;
|
||||
/*DELAYED_SERIN_IRQ = SERIN_INTERVAL;*/
|
||||
return 'A';
|
||||
case 0x21: /* Format Disk */
|
||||
#ifdef PBI_DEBUG
|
||||
Log_print("PIO DISK: Format-disk frame: %02x %02x %02x %02x %02x",
|
||||
CommandFrame[0], CommandFrame[1], CommandFrame[2],
|
||||
CommandFrame[3], CommandFrame[4]);
|
||||
#endif
|
||||
realsize = SIO_format_sectorsize[unit];
|
||||
DataBuffer[0] = SIO_FormatDisk(unit, DataBuffer + 1, realsize, SIO_format_sectorcount[unit]);
|
||||
DataBuffer[1 + realsize] = SIO_ChkSum(DataBuffer + 1, realsize);
|
||||
DataIndex = 0;
|
||||
ExpectedBytes = 2 + realsize;
|
||||
TransferStatus = PIO_FormatFrame;
|
||||
/*DELAYED_SERIN_IRQ = SERIN_INTERVAL;*/
|
||||
return 'A';
|
||||
case 0x22: /* Dual Density Format */
|
||||
#ifdef PBI_DEBUG
|
||||
Log_print("PIO DISK: Format-Medium frame: %02x %02x %02x %02x %02x",
|
||||
CommandFrame[0], CommandFrame[1], CommandFrame[2],
|
||||
CommandFrame[3], CommandFrame[4]);
|
||||
#endif
|
||||
DataBuffer[0] = SIO_FormatDisk(unit, DataBuffer + 1, 128, 1040);
|
||||
DataBuffer[1 + 128] = SIO_ChkSum(DataBuffer + 1, 128);
|
||||
DataIndex = 0;
|
||||
ExpectedBytes = 2 + 128;
|
||||
TransferStatus = PIO_FormatFrame;
|
||||
/*DELAYED_SERIN_IRQ = SERIN_INTERVAL;*/
|
||||
return 'A';
|
||||
|
||||
/*
|
||||
The Integral Disk Drive uses COMMAND BYTE $B1 and
|
||||
$B2 for internal use. These COMMAND BYTES may not
|
||||
be used by any other drivers.*/
|
||||
case 0xb1:
|
||||
Log_print("PIO DISK: Internal Command 0xb1 (unimplemented)");
|
||||
return 'E';
|
||||
case 0xb2:
|
||||
Log_print("PIO DISK: Internal Command 0xb2 (unimplemented)");
|
||||
return 'E';
|
||||
|
||||
|
||||
default:
|
||||
/* Unknown command for a disk drive */
|
||||
#ifdef PBI_DEBUG
|
||||
Log_print("PIO DISK: Unknown Command frame: %02x %02x %02x %02x %02x",
|
||||
CommandFrame[0], CommandFrame[1], CommandFrame[2],
|
||||
CommandFrame[3], CommandFrame[4]);
|
||||
#endif
|
||||
TransferStatus = PIO_NoFrame;
|
||||
return 'E';
|
||||
}
|
||||
}
|
||||
|
||||
/* called from POKEYSND_Init */
|
||||
void PBI_XLD_VInit(int playback_freq, int n_pokeys, int b16)
|
||||
{
|
||||
static struct Votrax_interface vi;
|
||||
int temp_votrax_buffer_size;
|
||||
bit16 = b16;
|
||||
dsprate = playback_freq;
|
||||
num_pokeys = n_pokeys;
|
||||
if (!xld_v_enabled) return;
|
||||
if (num_pokeys != 1 && num_pokeys != 2) {
|
||||
Log_print("PBI_XLD_VInit: cannot handle num_pokeys=%d", num_pokeys);
|
||||
xld_v_enabled = FALSE;
|
||||
return;
|
||||
}
|
||||
vi.num = 1;
|
||||
vi.BusyCallback = votrax_busy_callback_async;
|
||||
Votrax_Stop();
|
||||
Votrax_Start((void *)&vi);
|
||||
samples_per_frame = dsprate/(Atari800_tv_mode == Atari800_TV_PAL ? 50 : 60);
|
||||
ratio = (double)VTRX_RATE/(double)dsprate;
|
||||
temp_votrax_buffer_size = (int)(VTRX_BLOCK_SIZE*ratio + 10); /* +10 .. little extra? */
|
||||
free(temp_votrax_buffer);
|
||||
temp_votrax_buffer = (SWORD *)Util_malloc(temp_votrax_buffer_size*sizeof(SWORD));
|
||||
free(votrax_buffer);
|
||||
votrax_buffer = (SWORD *)Util_malloc(VTRX_BLOCK_SIZE*sizeof(SWORD));
|
||||
}
|
||||
|
||||
/* process votrax and interpolate samples */
|
||||
static void votrax_process(SWORD *v_buffer, int len, SWORD *temp_v_buffer)
|
||||
{
|
||||
static SWORD last_sample;
|
||||
static SWORD last_sample2;
|
||||
static double startpos;
|
||||
static int have;
|
||||
int max_left_sample_index = (int)(startpos + (double)(len - 1)*ratio);
|
||||
int pos = 0;
|
||||
double fraction = 0;
|
||||
int i;
|
||||
int floor_next_pos;
|
||||
|
||||
if (have == 2) {
|
||||
temp_v_buffer[0] = last_sample;
|
||||
temp_v_buffer[1] = last_sample2;
|
||||
Votrax_Update(0, temp_v_buffer + 2, (max_left_sample_index + 1 + 1) - 2);
|
||||
}
|
||||
else if (have == 1) {
|
||||
temp_v_buffer[0] = last_sample;
|
||||
Votrax_Update(0, temp_v_buffer + 1, (max_left_sample_index + 1 + 1) - 1);
|
||||
}
|
||||
else if (have == 0) {
|
||||
Votrax_Update(0, temp_v_buffer, max_left_sample_index + 1 + 1);
|
||||
}
|
||||
else if (have < 0) {
|
||||
Votrax_Update(0, temp_v_buffer, -have);
|
||||
Votrax_Update(0, temp_v_buffer, max_left_sample_index + 1 + 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
SWORD left_sample;
|
||||
SWORD right_sample;
|
||||
SWORD interp_sample;
|
||||
pos = (int)(startpos + (double)i*ratio);
|
||||
fraction = startpos + (double)i*ratio - (double)pos;
|
||||
left_sample = temp_v_buffer[pos];
|
||||
right_sample = temp_v_buffer[pos+1];
|
||||
interp_sample = (int)(left_sample + fraction*(double)(right_sample-left_sample));
|
||||
v_buffer[i] = interp_sample;
|
||||
}
|
||||
floor_next_pos = (int)(startpos + (double)len*ratio);
|
||||
startpos = (startpos + (double)len*ratio) - (double)floor_next_pos;
|
||||
if (floor_next_pos == max_left_sample_index)
|
||||
{
|
||||
have = 2;
|
||||
last_sample = temp_v_buffer[floor_next_pos];
|
||||
last_sample2 = temp_v_buffer[floor_next_pos+1];
|
||||
}
|
||||
else if (floor_next_pos == max_left_sample_index + 1) {
|
||||
have = 1;
|
||||
last_sample = temp_v_buffer[floor_next_pos];
|
||||
}
|
||||
else {
|
||||
have = (floor_next_pos - (max_left_sample_index + 2));
|
||||
}
|
||||
}
|
||||
|
||||
/* 16 bit mixing */
|
||||
static void mix(SWORD *dst, SWORD *src, int sndn, int volume)
|
||||
{
|
||||
SWORD s1, s2;
|
||||
int val;
|
||||
int channel = 0;
|
||||
|
||||
while (sndn--) {
|
||||
s1 = *src;
|
||||
s1 = s1*volume/128;
|
||||
s2 = *dst;
|
||||
src++;
|
||||
val = s1 + s2;
|
||||
if (val > 32767) val = 32767;
|
||||
if (val < -32768) val = -32768;
|
||||
*dst++ = val;
|
||||
if (num_pokeys == 2) {
|
||||
if (!channel) {
|
||||
channel = !channel;
|
||||
sndn++;
|
||||
src--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 8 bit mixing */
|
||||
static void mix8(UBYTE *dst, SWORD *src, int sndn, int volume)
|
||||
{
|
||||
SWORD s1, s2;
|
||||
int val;
|
||||
int channel = 0;
|
||||
|
||||
while (sndn--) {
|
||||
s1 = *src;
|
||||
s1 = s1*volume/128;
|
||||
s2 = ((int)(*dst) - 0x80)*256;
|
||||
src++;
|
||||
val = s1 + s2;
|
||||
if (val > 32767) val = 32767;
|
||||
if (val < -32768) val = -32768;
|
||||
*dst++ = (UBYTE)((val/256) + 0x80);
|
||||
if (num_pokeys == 2) {
|
||||
if (!channel) {
|
||||
channel = !channel;
|
||||
sndn++;
|
||||
src--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PBI_XLD_VFrame(void)
|
||||
{
|
||||
if (!xld_v_enabled) return;
|
||||
votrax_sync_samples -= samples_per_frame;
|
||||
if (votrax_sync_samples <= 0 ) {
|
||||
votrax_sync_samples = 0;
|
||||
votrax_busy = FALSE;
|
||||
votrax_busy_callback(FALSE); /* busy -> idle */
|
||||
}
|
||||
}
|
||||
|
||||
void PBI_XLD_VProcess(void *sndbuffer, int sndn)
|
||||
{
|
||||
if (!xld_v_enabled) return;
|
||||
|
||||
if(votrax_written) {
|
||||
votrax_written = FALSE;
|
||||
Votrax_PutByte(votrax_written_byte);
|
||||
}
|
||||
while (sndn > 0) {
|
||||
int amount = ((sndn > VTRX_BLOCK_SIZE) ? VTRX_BLOCK_SIZE : sndn);
|
||||
votrax_process(votrax_buffer, amount, temp_votrax_buffer);
|
||||
if (bit16) mix((SWORD *)sndbuffer, votrax_buffer, amount, 128/4);
|
||||
else mix8((UBYTE *)sndbuffer, votrax_buffer, amount, 128/4);
|
||||
sndbuffer = (char *) sndbuffer + VTRX_BLOCK_SIZE*(bit16 ? 2 : 1)*((num_pokeys == 2) ? 2: 1);
|
||||
sndn -= VTRX_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BASIC
|
||||
|
||||
void PBI_XLD_StateSave(void)
|
||||
{
|
||||
StateSav_SaveINT(&PBI_XLD_enabled, 1);
|
||||
if (PBI_XLD_enabled) {
|
||||
StateSav_SaveINT(&xld_v_enabled, 1);
|
||||
StateSav_SaveINT(&xld_d_enabled, 1);
|
||||
StateSav_SaveFNAME(xld_d_rom_filename);
|
||||
StateSav_SaveFNAME(xld_v_rom_filename);
|
||||
|
||||
StateSav_SaveUBYTE(&votrax_latch, 1);
|
||||
StateSav_SaveUBYTE(&modem_latch, 1);
|
||||
StateSav_SaveUBYTE(CommandFrame, sizeof(CommandFrame));
|
||||
StateSav_SaveINT(&CommandIndex, 1);
|
||||
StateSav_SaveUBYTE(DataBuffer, sizeof(DataBuffer));
|
||||
StateSav_SaveINT(&DataIndex, 1);
|
||||
StateSav_SaveINT(&TransferStatus, 1);
|
||||
StateSav_SaveINT(&ExpectedBytes, 1);
|
||||
StateSav_SaveINT(&votrax_busy, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void PBI_XLD_StateRead(void)
|
||||
{
|
||||
StateSav_ReadINT(&PBI_XLD_enabled, 1);
|
||||
if (PBI_XLD_enabled) {
|
||||
/* UI should have paused sound while doing this */
|
||||
StateSav_ReadINT(&xld_v_enabled, 1);
|
||||
StateSav_ReadINT(&xld_d_enabled, 1);
|
||||
StateSav_ReadFNAME(xld_d_rom_filename);
|
||||
StateSav_ReadFNAME(xld_v_rom_filename);
|
||||
if (xld_v_enabled) {
|
||||
init_xld_v();
|
||||
if (dsprate) PBI_XLD_VInit(dsprate, num_pokeys, bit16);
|
||||
}
|
||||
if (xld_d_enabled) init_xld_d();
|
||||
StateSav_ReadUBYTE(&votrax_latch, 1);
|
||||
StateSav_ReadUBYTE(&modem_latch, 1);
|
||||
StateSav_ReadUBYTE(CommandFrame, sizeof(CommandFrame));
|
||||
StateSav_ReadINT(&CommandIndex, 1);
|
||||
StateSav_ReadUBYTE(DataBuffer, sizeof(DataBuffer));
|
||||
StateSav_ReadINT(&DataIndex, 1);
|
||||
StateSav_ReadINT(&TransferStatus, 1);
|
||||
StateSav_ReadINT(&ExpectedBytes, 1);
|
||||
StateSav_ReadINT(&votrax_busy, 1);
|
||||
}
|
||||
else {
|
||||
xld_v_enabled = FALSE;
|
||||
xld_d_enabled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #ifndef BASIC */
|
||||
|
||||
/*
|
||||
vim:ts=4:sw=4:
|
||||
*/
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef PBI_XLD_H_
|
||||
#define PBI_XLD_H_
|
||||
|
||||
#include "atari.h"
|
||||
int PBI_XLD_Initialise(int *argc, char *argv[]);
|
||||
int PBI_XLD_ReadConfig(char *string, char *ptr);
|
||||
void PBI_XLD_WriteConfig(FILE *fp);
|
||||
void PBI_XLD_Reset(void);
|
||||
int PBI_XLD_D1GetByte(UWORD addr);
|
||||
UBYTE PBI_XLD_D1ffGetByte(void);
|
||||
void PBI_XLD_D1PutByte(UWORD addr, UBYTE byte);
|
||||
int PBI_XLD_D1ffPutByte(UBYTE byte);
|
||||
extern int PBI_XLD_enabled;
|
||||
void PBI_XLD_VInit(int playback_freq, int num_pokeys, int bit16);
|
||||
void PBI_XLD_VFrame(void);
|
||||
void PBI_XLD_VProcess(void *sndbuffer, int sndn);
|
||||
void PBI_XLD_StateSave(void);
|
||||
void PBI_XLD_StateRead(void);
|
||||
|
||||
#endif /* PBI_XLD_H_ */
|
||||
@@ -1,17 +0,0 @@
|
||||
/* joystick types for DOS port of David Firth's Atari800 emulator */
|
||||
|
||||
#define joy_off 0
|
||||
#define joy_analog 1
|
||||
#define joy_lpt1 2
|
||||
#define joy_lpt2 3
|
||||
#define joy_lpt3 4
|
||||
#define joy_keyset0 5
|
||||
#define joy_keyset1 6
|
||||
#define joy_keyset2 7
|
||||
#define joy_keyset3 8
|
||||
|
||||
#define JOYSTICKTYPES 9
|
||||
|
||||
char joyparams[JOYSTICKTYPES][10]={"OFF","PC","LPT1","LPT2",
|
||||
"LPT3","KEYSET_0","KEYSET_1","KEYSET_2","KEYSET_3"};
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
/*
|
||||
* pia.c - PIA chip emulation
|
||||
*
|
||||
* Copyright (C) 1995-1998 David Firth
|
||||
* Copyright (C) 1998-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "atari.h"
|
||||
#include "cpu.h"
|
||||
#include "memory.h"
|
||||
#include "pia.h"
|
||||
#include "sio.h"
|
||||
#ifdef XEP80_EMULATION
|
||||
#include "xep80.h"
|
||||
#endif
|
||||
#ifndef BASIC
|
||||
#include "input.h"
|
||||
#include "statesav.h"
|
||||
#endif
|
||||
|
||||
UBYTE PIA_PACTL;
|
||||
UBYTE PIA_PBCTL;
|
||||
UBYTE PIA_PORTA;
|
||||
UBYTE PIA_PORTB;
|
||||
UBYTE PIA_PORT_input[2];
|
||||
|
||||
UBYTE PIA_PORTA_mask;
|
||||
UBYTE PIA_PORTB_mask;
|
||||
|
||||
int PIA_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
PIA_PACTL = 0x3f;
|
||||
PIA_PBCTL = 0x3f;
|
||||
PIA_PORTA = 0xff;
|
||||
PIA_PORTB = 0xff;
|
||||
PIA_PORTA_mask = 0xff;
|
||||
PIA_PORTB_mask = 0xff;
|
||||
PIA_PORT_input[0] = 0xff;
|
||||
PIA_PORT_input[1] = 0xff;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void PIA_Reset(void)
|
||||
{
|
||||
PIA_PORTA = 0xff;
|
||||
if (Atari800_machine_type == Atari800_MACHINE_XLXE) {
|
||||
MEMORY_HandlePORTB(0xff, (UBYTE) (PIA_PORTB | PIA_PORTB_mask));
|
||||
}
|
||||
PIA_PORTB = 0xff;
|
||||
}
|
||||
|
||||
UBYTE PIA_GetByte(UWORD addr)
|
||||
{
|
||||
switch (addr & 0x03) {
|
||||
case PIA_OFFSET_PACTL:
|
||||
return PIA_PACTL & 0x3f;
|
||||
case PIA_OFFSET_PBCTL:
|
||||
return PIA_PBCTL & 0x3f;
|
||||
case PIA_OFFSET_PORTA:
|
||||
if ((PIA_PACTL & 0x04) == 0) {
|
||||
/* direction register */
|
||||
return ~PIA_PORTA_mask;
|
||||
}
|
||||
else {
|
||||
/* port state */
|
||||
#ifdef XEP80_EMULATION
|
||||
if (XEP80_enabled) {
|
||||
return(XEP80_GetBit() & PIA_PORT_input[0] & (PIA_PORTA | PIA_PORTA_mask));
|
||||
}
|
||||
#endif /* XEP80_EMULATION */
|
||||
return PIA_PORT_input[0] & (PIA_PORTA | PIA_PORTA_mask);
|
||||
}
|
||||
case PIA_OFFSET_PORTB:
|
||||
if ((PIA_PBCTL & 0x04) == 0) {
|
||||
/* direction register */
|
||||
return ~PIA_PORTB_mask;
|
||||
}
|
||||
else {
|
||||
/* port state */
|
||||
if (Atari800_machine_type == Atari800_MACHINE_XLXE) {
|
||||
return PIA_PORTB | PIA_PORTB_mask;
|
||||
}
|
||||
else {
|
||||
return PIA_PORT_input[1] & (PIA_PORTB | PIA_PORTB_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* for stupid compilers */
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
void PIA_PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
switch (addr & 0x03) {
|
||||
case PIA_OFFSET_PACTL:
|
||||
/* This code is part of the cassette emulation */
|
||||
/* The motor status has changed */
|
||||
SIO_TapeMotor(byte & 0x08 ? 0 : 1);
|
||||
|
||||
PIA_PACTL = byte;
|
||||
break;
|
||||
case PIA_OFFSET_PBCTL:
|
||||
/* This code is part of the serial I/O emulation */
|
||||
if ((PIA_PBCTL ^ byte) & 0x08) {
|
||||
/* The command line status has changed */
|
||||
SIO_SwitchCommandFrame(byte & 0x08 ? 0 : 1);
|
||||
}
|
||||
PIA_PBCTL = byte;
|
||||
break;
|
||||
case PIA_OFFSET_PORTA:
|
||||
if ((PIA_PACTL & 0x04) == 0) {
|
||||
/* set direction register */
|
||||
PIA_PORTA_mask = ~byte;
|
||||
}
|
||||
else {
|
||||
/* set output register */
|
||||
#ifdef XEP80_EMULATION
|
||||
if (XEP80_enabled && (~PIA_PORTA_mask & 0x11)) {
|
||||
XEP80_PutBit(byte);
|
||||
}
|
||||
#endif /* XEP80_EMULATION */
|
||||
PIA_PORTA = byte; /* change from thor */
|
||||
}
|
||||
#ifndef BASIC
|
||||
INPUT_SelectMultiJoy((PIA_PORTA | PIA_PORTA_mask) >> 4);
|
||||
#endif
|
||||
break;
|
||||
case PIA_OFFSET_PORTB:
|
||||
if (Atari800_machine_type == Atari800_MACHINE_XLXE) {
|
||||
if ((PIA_PBCTL & 0x04) == 0) {
|
||||
/* direction register */
|
||||
MEMORY_HandlePORTB((UBYTE) (PIA_PORTB | ~byte), (UBYTE) (PIA_PORTB | PIA_PORTB_mask));
|
||||
PIA_PORTB_mask = ~byte;
|
||||
}
|
||||
else {
|
||||
/* output register */
|
||||
MEMORY_HandlePORTB((UBYTE) (byte | PIA_PORTB_mask), (UBYTE) (PIA_PORTB | PIA_PORTB_mask));
|
||||
PIA_PORTB = byte;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((PIA_PBCTL & 0x04) == 0) {
|
||||
/* direction register */
|
||||
PIA_PORTB_mask = ~byte;
|
||||
}
|
||||
else {
|
||||
/* output register */
|
||||
PIA_PORTB = byte;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BASIC
|
||||
|
||||
void PIA_StateSave(void)
|
||||
{
|
||||
int Ram256 = 0;
|
||||
if (MEMORY_ram_size == MEMORY_RAM_320_RAMBO)
|
||||
Ram256 = 1;
|
||||
else if (MEMORY_ram_size == MEMORY_RAM_320_COMPY_SHOP)
|
||||
Ram256 = 2;
|
||||
|
||||
StateSav_SaveUBYTE( &PIA_PACTL, 1 );
|
||||
StateSav_SaveUBYTE( &PIA_PBCTL, 1 );
|
||||
StateSav_SaveUBYTE( &PIA_PORTA, 1 );
|
||||
StateSav_SaveUBYTE( &PIA_PORTB, 1 );
|
||||
|
||||
StateSav_SaveINT( &MEMORY_xe_bank, 1 );
|
||||
StateSav_SaveINT( &MEMORY_selftest_enabled, 1 );
|
||||
StateSav_SaveINT( &Ram256, 1 );
|
||||
|
||||
StateSav_SaveINT( &MEMORY_cartA0BF_enabled, 1 );
|
||||
|
||||
StateSav_SaveUBYTE( &PIA_PORTA_mask, 1 );
|
||||
StateSav_SaveUBYTE( &PIA_PORTB_mask, 1 );
|
||||
}
|
||||
|
||||
void PIA_StateRead(void)
|
||||
{
|
||||
int Ram256 = 0;
|
||||
|
||||
StateSav_ReadUBYTE( &PIA_PACTL, 1 );
|
||||
StateSav_ReadUBYTE( &PIA_PBCTL, 1 );
|
||||
StateSav_ReadUBYTE( &PIA_PORTA, 1 );
|
||||
StateSav_ReadUBYTE( &PIA_PORTB, 1 );
|
||||
|
||||
StateSav_ReadINT( &MEMORY_xe_bank, 1 );
|
||||
StateSav_ReadINT( &MEMORY_selftest_enabled, 1 );
|
||||
StateSav_ReadINT( &Ram256, 1 );
|
||||
|
||||
if (Ram256 == 1 && Atari800_machine_type == Atari800_MACHINE_XLXE && MEMORY_ram_size == MEMORY_RAM_320_COMPY_SHOP)
|
||||
MEMORY_ram_size = MEMORY_RAM_320_RAMBO;
|
||||
|
||||
StateSav_ReadINT( &MEMORY_cartA0BF_enabled, 1 );
|
||||
|
||||
StateSav_ReadUBYTE( &PIA_PORTA_mask, 1 );
|
||||
StateSav_ReadUBYTE( &PIA_PORTB_mask, 1 );
|
||||
}
|
||||
|
||||
#endif /* BASIC */
|
||||
@@ -1,26 +0,0 @@
|
||||
#ifndef PIA_H_
|
||||
#define PIA_H_
|
||||
|
||||
#include "atari.h"
|
||||
|
||||
#define PIA_OFFSET_PORTA 0x00
|
||||
#define PIA_OFFSET_PORTB 0x01
|
||||
#define PIA_OFFSET_PACTL 0x02
|
||||
#define PIA_OFFSET_PBCTL 0x03
|
||||
|
||||
extern UBYTE PIA_PACTL;
|
||||
extern UBYTE PIA_PBCTL;
|
||||
extern UBYTE PIA_PORTA;
|
||||
extern UBYTE PIA_PORTB;
|
||||
extern UBYTE PIA_PORTA_mask;
|
||||
extern UBYTE PIA_PORTB_mask;
|
||||
extern UBYTE PIA_PORT_input[2];
|
||||
|
||||
int PIA_Initialise(int *argc, char *argv[]);
|
||||
void PIA_Reset(void);
|
||||
UBYTE PIA_GetByte(UWORD addr);
|
||||
void PIA_PutByte(UWORD addr, UBYTE byte);
|
||||
void PIA_StateSave(void);
|
||||
void PIA_StateRead(void);
|
||||
|
||||
#endif /* PIA_H_ */
|
||||
@@ -1,75 +0,0 @@
|
||||
#ifndef PLATFORM_H_
|
||||
#define PLATFORM_H_
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/* This include file defines prototypes for platform-specific functions. */
|
||||
|
||||
int PLATFORM_Initialise(int *argc, char *argv[]);
|
||||
int PLATFORM_Exit(int run_monitor);
|
||||
int PLATFORM_Keyboard(void);
|
||||
void PLATFORM_DisplayScreen(void);
|
||||
|
||||
int PLATFORM_PORT(int num);
|
||||
int PLATFORM_TRIG(int num);
|
||||
|
||||
#ifdef SUPPORTS_PLATFORM_CONFIGINIT
|
||||
/* This function sets the configuration parameters to default values */
|
||||
void PLATFORM_ConfigInit(void);
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORTS_PLATFORM_CONFIGURE
|
||||
/* This procedure processes lines not recognized by RtConfigLoad. */
|
||||
int PLATFORM_Configure(char *option, char *parameters);
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORTS_PLATFORM_CONFIGSAVE
|
||||
/* This function saves additional config lines */
|
||||
void PLATFORM_ConfigSave(FILE *fp);
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORTS_PLATFORM_PALETTEUPDATE
|
||||
/* This function updates the palette */
|
||||
/* If the platform does a conversion of colortable when it initialises
|
||||
* and the user changes colortable (such as changing from PAL to NTSC)
|
||||
* then this function should update the platform palette */
|
||||
void PLATFORM_PaletteUpdate(void);
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORTS_PLATFORM_SLEEP
|
||||
/* This function is for those ports that need their own version of sleep */
|
||||
void PLATFORM_Sleep(double s);
|
||||
#endif
|
||||
|
||||
#ifdef SDL
|
||||
/* used in UI to show how the keyboard joystick is mapped */
|
||||
extern int PLATFORM_kbd_joy_0_enabled;
|
||||
extern int PLATFORM_kbd_joy_1_enabled;
|
||||
int PLATFORM_GetRawKey(void);
|
||||
#endif
|
||||
|
||||
#ifdef XEP80_EMULATION
|
||||
/* Switch between the Atari and XEP80 screen */
|
||||
void PLATFORM_SwitchXep80(void);
|
||||
/* TRUE if the XEP80 screen is visible */
|
||||
extern int PLATFORM_xep80;
|
||||
#endif
|
||||
|
||||
#ifdef NTSC_FILTER
|
||||
enum PLATFORM_filter_t {
|
||||
PLATFORM_FILTER_NONE,
|
||||
PLATFORM_FILTER_NTSC
|
||||
};
|
||||
|
||||
/* Represents whether the NTSC filter is turned on. Don't set this value
|
||||
directly. */
|
||||
extern enum PLATFORM_filter_t PLATFORM_filter;
|
||||
|
||||
/* This function turns the NTSC filter on or off. Changing the
|
||||
PLATFORM_filter variable directly is not allowed; use this function
|
||||
instead. */
|
||||
void PLATFORM_SetFilter(const enum PLATFORM_filter_t filter);
|
||||
#endif /* NTSC_FILTER */
|
||||
|
||||
#endif /* PLATFORM_H_ */
|
||||
@@ -1,667 +0,0 @@
|
||||
/*
|
||||
* pokey.c - POKEY sound chip emulation
|
||||
*
|
||||
* Copyright (C) 1995-1998 David Firth
|
||||
* Copyright (C) 1998-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "atari.h"
|
||||
#include "cpu.h"
|
||||
#include "esc.h"
|
||||
#include "pia.h"
|
||||
#include "pokey.h"
|
||||
#include "gtia.h"
|
||||
#include "sio.h"
|
||||
#ifndef BASIC
|
||||
#include "input.h"
|
||||
#include "statesav.h"
|
||||
#endif
|
||||
#ifdef SOUND
|
||||
#include "pokeysnd.h"
|
||||
#endif
|
||||
#include "antic.h"
|
||||
#include "cassette.h"
|
||||
#include "log.h"
|
||||
#include "input.h"
|
||||
#include "pbi.h"
|
||||
|
||||
#ifdef POKEY_UPDATE
|
||||
void pokey_update(void);
|
||||
#endif
|
||||
|
||||
UBYTE POKEY_KBCODE;
|
||||
UBYTE POKEY_SERIN;
|
||||
UBYTE POKEY_IRQST;
|
||||
UBYTE POKEY_IRQEN;
|
||||
UBYTE POKEY_SKSTAT;
|
||||
UBYTE POKEY_SKCTL;
|
||||
int POKEY_DELAYED_SERIN_IRQ;
|
||||
int POKEY_DELAYED_SEROUT_IRQ;
|
||||
int POKEY_DELAYED_XMTDONE_IRQ;
|
||||
|
||||
/* structures to hold the 9 pokey control bytes */
|
||||
UBYTE POKEY_AUDF[4 * POKEY_MAXPOKEYS]; /* AUDFx (D200, D202, D204, D206) */
|
||||
UBYTE POKEY_AUDC[4 * POKEY_MAXPOKEYS]; /* AUDCx (D201, D203, D205, D207) */
|
||||
UBYTE POKEY_AUDCTL[POKEY_MAXPOKEYS]; /* AUDCTL (D208) */
|
||||
int POKEY_DivNIRQ[4], POKEY_DivNMax[4];
|
||||
int POKEY_Base_mult[POKEY_MAXPOKEYS]; /* selects either 64Khz or 15Khz clock mult */
|
||||
|
||||
UBYTE POKEY_POT_input[8] = {228, 228, 228, 228, 228, 228, 228, 228};
|
||||
static int pot_scanline;
|
||||
|
||||
UBYTE POKEY_poly9_lookup[511];
|
||||
UBYTE POKEY_poly17_lookup[16385];
|
||||
static ULONG random_scanline_counter;
|
||||
|
||||
ULONG POKEY_GetRandomCounter(void)
|
||||
{
|
||||
return random_scanline_counter;
|
||||
}
|
||||
|
||||
void POKEY_SetRandomCounter(ULONG value)
|
||||
{
|
||||
random_scanline_counter = value;
|
||||
}
|
||||
|
||||
UBYTE POKEY_GetByte(UWORD addr)
|
||||
{
|
||||
UBYTE byte = 0xff;
|
||||
|
||||
#ifdef STEREO_SOUND
|
||||
if (addr & 0x0010 && POKEYSND_stereo_enabled)
|
||||
return 0;
|
||||
#endif
|
||||
addr &= 0x0f;
|
||||
if (addr < 8) {
|
||||
byte = POKEY_POT_input[addr];
|
||||
if (byte <= pot_scanline)
|
||||
return byte;
|
||||
return pot_scanline;
|
||||
}
|
||||
switch (addr) {
|
||||
case POKEY_OFFSET_ALLPOT:
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
if (POKEY_POT_input[i] <= pot_scanline)
|
||||
byte &= ~(1 << i); /* reset bit if pot value known */
|
||||
}
|
||||
break;
|
||||
case POKEY_OFFSET_KBCODE:
|
||||
byte = POKEY_KBCODE;
|
||||
break;
|
||||
case POKEY_OFFSET_RANDOM:
|
||||
if ((POKEY_SKCTL & 0x03) != 0) {
|
||||
int i = random_scanline_counter + ANTIC_XPOS;
|
||||
if (POKEY_AUDCTL[0] & POKEY_POLY9)
|
||||
byte = POKEY_poly9_lookup[i % POKEY_POLY9_SIZE];
|
||||
else {
|
||||
const UBYTE *ptr;
|
||||
i %= POKEY_POLY17_SIZE;
|
||||
ptr = POKEY_poly17_lookup + (i >> 3);
|
||||
i &= 7;
|
||||
byte = (UBYTE) ((ptr[0] >> i) + (ptr[1] << (8 - i)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case POKEY_OFFSET_SERIN:
|
||||
byte = POKEY_SERIN;
|
||||
#ifdef DEBUG3
|
||||
printf("SERIO: SERIN read, bytevalue %02x\n", POKEY_SERIN);
|
||||
#endif
|
||||
#ifdef SERIO_SOUND
|
||||
POKEYSND_UpdateSerio(0,byte);
|
||||
#endif
|
||||
break;
|
||||
case POKEY_OFFSET_IRQST:
|
||||
byte = POKEY_IRQST;
|
||||
break;
|
||||
case POKEY_OFFSET_SKSTAT:
|
||||
byte = POKEY_SKSTAT + (CASSETTE_IOLineStatus() << 4);
|
||||
break;
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
static void Update_Counter(int chan_mask);
|
||||
|
||||
static int POKEY_siocheck(void)
|
||||
{
|
||||
return (((POKEY_AUDF[POKEY_CHAN3] == 0x28 || POKEY_AUDF[POKEY_CHAN3] == 0x10
|
||||
|| POKEY_AUDF[POKEY_CHAN3] == 0x08 || POKEY_AUDF[POKEY_CHAN3] == 0x0a)
|
||||
&& POKEY_AUDF[POKEY_CHAN4] == 0x00) /* intelligent peripherals speeds */
|
||||
|| (POKEY_SKCTL & 0x78) == 0x28) /* cassette save mode */
|
||||
&& (POKEY_AUDCTL[0] & 0x28) == 0x28;
|
||||
}
|
||||
|
||||
#ifndef SOUND_GAIN /* sound gain can be pre-defined in the configure/Makefile */
|
||||
#define SOUND_GAIN 4
|
||||
#endif
|
||||
|
||||
#ifndef SOUND
|
||||
#define POKEYSND_Update(addr, val, chip, gain)
|
||||
#endif
|
||||
|
||||
void POKEY_PutByte(UWORD addr, UBYTE byte)
|
||||
{
|
||||
#ifdef STEREO_SOUND
|
||||
addr &= POKEYSND_stereo_enabled ? 0x1f : 0x0f;
|
||||
#else
|
||||
addr &= 0x0f;
|
||||
#endif
|
||||
switch (addr) {
|
||||
case POKEY_OFFSET_AUDC1:
|
||||
POKEY_AUDC[POKEY_CHAN1] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDC1, byte, 0, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDC2:
|
||||
POKEY_AUDC[POKEY_CHAN2] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDC2, byte, 0, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDC3:
|
||||
POKEY_AUDC[POKEY_CHAN3] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDC3, byte, 0, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDC4:
|
||||
POKEY_AUDC[POKEY_CHAN4] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDC4, byte, 0, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDCTL:
|
||||
POKEY_AUDCTL[0] = byte;
|
||||
|
||||
/* determine the base multiplier for the 'div by n' calculations */
|
||||
if (byte & POKEY_CLOCK_15)
|
||||
POKEY_Base_mult[0] = POKEY_DIV_15;
|
||||
else
|
||||
POKEY_Base_mult[0] = POKEY_DIV_64;
|
||||
|
||||
Update_Counter((1 << POKEY_CHAN1) | (1 << POKEY_CHAN2) | (1 << POKEY_CHAN3) | (1 << POKEY_CHAN4));
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDCTL, byte, 0, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDF1:
|
||||
POKEY_AUDF[POKEY_CHAN1] = byte;
|
||||
Update_Counter((POKEY_AUDCTL[0] & POKEY_CH1_CH2) ? ((1 << POKEY_CHAN2) | (1 << POKEY_CHAN1)) : (1 << POKEY_CHAN1));
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDF1, byte, 0, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDF2:
|
||||
POKEY_AUDF[POKEY_CHAN2] = byte;
|
||||
Update_Counter(1 << POKEY_CHAN2);
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDF2, byte, 0, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDF3:
|
||||
POKEY_AUDF[POKEY_CHAN3] = byte;
|
||||
Update_Counter((POKEY_AUDCTL[0] & POKEY_CH3_CH4) ? ((1 << POKEY_CHAN4) | (1 << POKEY_CHAN3)) : (1 << POKEY_CHAN3));
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDF3, byte, 0, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDF4:
|
||||
POKEY_AUDF[POKEY_CHAN4] = byte;
|
||||
Update_Counter(1 << POKEY_CHAN4);
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDF4, byte, 0, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_IRQEN:
|
||||
POKEY_IRQEN = byte;
|
||||
#ifdef DEBUG1
|
||||
printf("WR: IRQEN = %x, PC = %x\n", POKEY_IRQEN, PC);
|
||||
#endif
|
||||
POKEY_IRQST |= ~byte & 0xf7; /* Reset disabled IRQs except XMTDONE */
|
||||
if (POKEY_IRQEN & 0x20) {
|
||||
SLONG delay;
|
||||
delay = CASSETTE_GetInputIRQDelay();
|
||||
if (delay > 0)
|
||||
POKEY_DELAYED_SERIN_IRQ = delay;
|
||||
}
|
||||
if ((~POKEY_IRQST & POKEY_IRQEN) == 0 && PBI_IRQ == 0)
|
||||
CPU_IRQ = 0;
|
||||
else
|
||||
CPU_GenerateIRQ();
|
||||
break;
|
||||
case POKEY_OFFSET_SKRES:
|
||||
POKEY_SKSTAT |= 0xe0;
|
||||
break;
|
||||
case POKEY_OFFSET_POTGO:
|
||||
if (!(POKEY_SKCTL & 4))
|
||||
pot_scanline = 0; /* slow pot mode */
|
||||
break;
|
||||
case POKEY_OFFSET_SEROUT:
|
||||
if ((POKEY_SKCTL & 0x70) == 0x20 && POKEY_siocheck())
|
||||
SIO_PutByte(byte);
|
||||
/* check if cassette 2-tone mode has been enabled */
|
||||
if ((POKEY_SKCTL & 0x08) == 0x00) {
|
||||
/* intelligent device */
|
||||
POKEY_DELAYED_SEROUT_IRQ = SIO_SEROUT_INTERVAL;
|
||||
POKEY_IRQST |= 0x08;
|
||||
POKEY_DELAYED_XMTDONE_IRQ = SIO_XMTDONE_INTERVAL;
|
||||
}
|
||||
else {
|
||||
/* cassette */
|
||||
/* some savers patch the cassette baud rate, so we evaluate it here */
|
||||
/* scanlines per second*10 bit*audiofrequency/(1.79 MHz/2) */
|
||||
POKEY_DELAYED_SEROUT_IRQ = 312*50*10*(POKEY_AUDF[POKEY_CHAN3] + POKEY_AUDF[POKEY_CHAN4]*0x100)/895000;
|
||||
/* safety check */
|
||||
if (POKEY_DELAYED_SEROUT_IRQ >= 3) {
|
||||
POKEY_IRQST |= 0x08;
|
||||
POKEY_DELAYED_XMTDONE_IRQ = 2*POKEY_DELAYED_SEROUT_IRQ - 2;
|
||||
}
|
||||
else {
|
||||
POKEY_DELAYED_SEROUT_IRQ = 0;
|
||||
POKEY_DELAYED_XMTDONE_IRQ = 0;
|
||||
}
|
||||
};
|
||||
#ifdef SERIO_SOUND
|
||||
POKEYSND_UpdateSerio(1, byte);
|
||||
#endif
|
||||
break;
|
||||
case POKEY_OFFSET_STIMER:
|
||||
POKEY_DivNIRQ[POKEY_CHAN1] = POKEY_DivNMax[POKEY_CHAN1];
|
||||
POKEY_DivNIRQ[POKEY_CHAN2] = POKEY_DivNMax[POKEY_CHAN2];
|
||||
POKEY_DivNIRQ[POKEY_CHAN4] = POKEY_DivNMax[POKEY_CHAN4];
|
||||
POKEYSND_Update(POKEY_OFFSET_STIMER, byte, 0, SOUND_GAIN);
|
||||
#ifdef DEBUG1
|
||||
printf("WR: STIMER = %x\n", byte);
|
||||
#endif
|
||||
break;
|
||||
case POKEY_OFFSET_SKCTL:
|
||||
POKEY_SKCTL = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_SKCTL, byte, 0, SOUND_GAIN);
|
||||
if (byte & 4)
|
||||
pot_scanline = 228; /* fast pot mode - return results immediately */
|
||||
break;
|
||||
#ifdef STEREO_SOUND
|
||||
case POKEY_OFFSET_AUDC1 + POKEY_OFFSET_POKEY2:
|
||||
POKEY_AUDC[POKEY_CHAN1 + POKEY_CHIP2] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDC1, byte, 1, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDC2 + POKEY_OFFSET_POKEY2:
|
||||
POKEY_AUDC[POKEY_CHAN2 + POKEY_CHIP2] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDC2, byte, 1, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDC3 + POKEY_OFFSET_POKEY2:
|
||||
POKEY_AUDC[POKEY_CHAN3 + POKEY_CHIP2] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDC3, byte, 1, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDC4 + POKEY_OFFSET_POKEY2:
|
||||
POKEY_AUDC[POKEY_CHAN4 + POKEY_CHIP2] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDC4, byte, 1, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDCTL + POKEY_OFFSET_POKEY2:
|
||||
POKEY_AUDCTL[1] = byte;
|
||||
/* determine the base multiplier for the 'div by n' calculations */
|
||||
if (byte & POKEY_CLOCK_15)
|
||||
POKEY_Base_mult[1] = POKEY_DIV_15;
|
||||
else
|
||||
POKEY_Base_mult[1] = POKEY_DIV_64;
|
||||
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDCTL, byte, 1, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDF1 + POKEY_OFFSET_POKEY2:
|
||||
POKEY_AUDF[POKEY_CHAN1 + POKEY_CHIP2] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDF1, byte, 1, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDF2 + POKEY_OFFSET_POKEY2:
|
||||
POKEY_AUDF[POKEY_CHAN2 + POKEY_CHIP2] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDF2, byte, 1, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDF3 + POKEY_OFFSET_POKEY2:
|
||||
POKEY_AUDF[POKEY_CHAN3 + POKEY_CHIP2] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDF3, byte, 1, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_AUDF4 + POKEY_OFFSET_POKEY2:
|
||||
POKEY_AUDF[POKEY_CHAN4 + POKEY_CHIP2] = byte;
|
||||
POKEYSND_Update(POKEY_OFFSET_AUDF4, byte, 1, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_STIMER + POKEY_OFFSET_POKEY2:
|
||||
POKEYSND_Update(POKEY_OFFSET_STIMER, byte, 1, SOUND_GAIN);
|
||||
break;
|
||||
case POKEY_OFFSET_SKCTL + POKEY_OFFSET_POKEY2:
|
||||
POKEYSND_Update(POKEY_OFFSET_SKCTL, byte, 1, SOUND_GAIN);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int POKEY_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
ULONG reg;
|
||||
|
||||
/* Initialise Serial Port Interrupts */
|
||||
POKEY_DELAYED_SERIN_IRQ = 0;
|
||||
POKEY_DELAYED_SEROUT_IRQ = 0;
|
||||
POKEY_DELAYED_XMTDONE_IRQ = 0;
|
||||
|
||||
POKEY_KBCODE = 0xff;
|
||||
POKEY_SERIN = 0x00; /* or 0xff ? */
|
||||
POKEY_IRQST = 0xff;
|
||||
POKEY_IRQEN = 0x00;
|
||||
POKEY_SKSTAT = 0xef;
|
||||
POKEY_SKCTL = 0x00;
|
||||
|
||||
for (i = 0; i < (POKEY_MAXPOKEYS * 4); i++) {
|
||||
POKEY_AUDC[i] = 0;
|
||||
POKEY_AUDF[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < POKEY_MAXPOKEYS; i++) {
|
||||
POKEY_AUDCTL[i] = 0;
|
||||
POKEY_Base_mult[i] = POKEY_DIV_64;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
POKEY_DivNIRQ[i] = POKEY_DivNMax[i] = 0;
|
||||
|
||||
pot_scanline = 0;
|
||||
|
||||
/* initialise poly9_lookup */
|
||||
reg = 0x1ff;
|
||||
for (i = 0; i < 511; i++) {
|
||||
reg = ((((reg >> 5) ^ reg) & 1) << 8) + (reg >> 1);
|
||||
POKEY_poly9_lookup[i] = (UBYTE) reg;
|
||||
}
|
||||
/* initialise poly17_lookup */
|
||||
reg = 0x1ffff;
|
||||
for (i = 0; i < 16385; i++) {
|
||||
reg = ((((reg >> 5) ^ reg) & 0xff) << 9) + (reg >> 8);
|
||||
POKEY_poly17_lookup[i] = (UBYTE) (reg >> 1);
|
||||
}
|
||||
|
||||
#ifndef BASIC
|
||||
if (INPUT_Playingback()) {
|
||||
random_scanline_counter = INPUT_PlaybackInt();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
random_scanline_counter =
|
||||
#ifdef WIN32
|
||||
GetTickCount() % POKEY_POLY17_SIZE;
|
||||
#elif defined(HAVE_TIME)
|
||||
time(NULL) % POKEY_POLY17_SIZE;
|
||||
#else
|
||||
0;
|
||||
#endif
|
||||
}
|
||||
#ifndef BASIC
|
||||
if (INPUT_Recording()) {
|
||||
INPUT_RecordInt(random_scanline_counter);
|
||||
}
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void POKEY_Frame(void)
|
||||
{
|
||||
random_scanline_counter %= (POKEY_AUDCTL[0] & POKEY_POLY9) ? POKEY_POLY9_SIZE : POKEY_POLY17_SIZE;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** Generate POKEY Timer IRQs if required **
|
||||
** called on a per-scanline basis, not very precise, but good enough **
|
||||
** for most applications **
|
||||
***************************************************************************/
|
||||
|
||||
void POKEY_Scanline(void)
|
||||
{
|
||||
#ifdef POKEY_UPDATE
|
||||
pokey_update();
|
||||
#endif
|
||||
|
||||
#ifdef VOL_ONLY_SOUND
|
||||
POKEYSND_UpdateVolOnly();
|
||||
#endif
|
||||
|
||||
#ifndef BASIC
|
||||
INPUT_Scanline(); /* Handle Amiga and ST mice. */
|
||||
/* It's not a part of POKEY emulation, */
|
||||
/* but it looks to be the best place to put it. */
|
||||
#endif
|
||||
|
||||
if (pot_scanline < 228)
|
||||
pot_scanline++;
|
||||
|
||||
random_scanline_counter += ANTIC_LINE_C;
|
||||
|
||||
/* on nonpatched i/o-operation, enable the cassette timing */
|
||||
if (!ESC_enable_sio_patch)
|
||||
CASSETTE_AddScanLine();
|
||||
|
||||
if (POKEY_DELAYED_SERIN_IRQ > 0) {
|
||||
if (--POKEY_DELAYED_SERIN_IRQ == 0) {
|
||||
if (POKEY_IRQEN & 0x20) {
|
||||
if (POKEY_IRQST & 0x20) {
|
||||
POKEY_IRQST &= 0xdf;
|
||||
POKEY_SERIN = SIO_GetByte();
|
||||
#ifdef DEBUG2
|
||||
printf("SERIO: SERIN Interrupt triggered, bytevalue %02x\n", POKEY_SERIN);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
POKEY_SKSTAT &= 0xdf;
|
||||
#ifdef DEBUG2
|
||||
printf("SERIO: SERIN Interrupt triggered\n");
|
||||
#endif
|
||||
}
|
||||
CPU_GenerateIRQ();
|
||||
}
|
||||
#ifdef DEBUG2
|
||||
else {
|
||||
printf("SERIO: SERIN Interrupt missed\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (POKEY_DELAYED_SEROUT_IRQ > 0) {
|
||||
if (--POKEY_DELAYED_SEROUT_IRQ == 0) {
|
||||
if (POKEY_IRQEN & 0x10) {
|
||||
#ifdef DEBUG2
|
||||
printf("SERIO: SEROUT Interrupt triggered\n");
|
||||
#endif
|
||||
POKEY_IRQST &= 0xef;
|
||||
CPU_GenerateIRQ();
|
||||
}
|
||||
#ifdef DEBUG2
|
||||
else {
|
||||
printf("SERIO: SEROUT Interrupt missed\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (POKEY_DELAYED_XMTDONE_IRQ > 0)
|
||||
if (--POKEY_DELAYED_XMTDONE_IRQ == 0) {
|
||||
POKEY_IRQST &= 0xf7;
|
||||
if (POKEY_IRQEN & 0x08) {
|
||||
#ifdef DEBUG2
|
||||
printf("SERIO: XMTDONE Interrupt triggered\n");
|
||||
#endif
|
||||
CPU_GenerateIRQ();
|
||||
}
|
||||
#ifdef DEBUG2
|
||||
else
|
||||
printf("SERIO: XMTDONE Interrupt missed\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((POKEY_DivNIRQ[POKEY_CHAN1] -= ANTIC_LINE_C) < 0 ) {
|
||||
POKEY_DivNIRQ[POKEY_CHAN1] += POKEY_DivNMax[POKEY_CHAN1];
|
||||
if (POKEY_IRQEN & 0x01) {
|
||||
POKEY_IRQST &= 0xfe;
|
||||
CPU_GenerateIRQ();
|
||||
}
|
||||
}
|
||||
|
||||
if ((POKEY_DivNIRQ[POKEY_CHAN2] -= ANTIC_LINE_C) < 0 ) {
|
||||
POKEY_DivNIRQ[POKEY_CHAN2] += POKEY_DivNMax[POKEY_CHAN2];
|
||||
if (POKEY_IRQEN & 0x02) {
|
||||
POKEY_IRQST &= 0xfd;
|
||||
CPU_GenerateIRQ();
|
||||
}
|
||||
}
|
||||
|
||||
if ((POKEY_DivNIRQ[POKEY_CHAN4] -= ANTIC_LINE_C) < 0 ) {
|
||||
POKEY_DivNIRQ[POKEY_CHAN4] += POKEY_DivNMax[POKEY_CHAN4];
|
||||
if (POKEY_IRQEN & 0x04) {
|
||||
POKEY_IRQST &= 0xfb;
|
||||
CPU_GenerateIRQ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Module: Update_Counter() */
|
||||
/* Purpose: To process the latest control values stored in the AUDF, AUDC, */
|
||||
/* and AUDCTL registers. It pre-calculates as much information as */
|
||||
/* possible for better performance. This routine has been added */
|
||||
/* here again as I need the precise frequency for the pokey timers */
|
||||
/* again. The pokey emulation is therefore somewhat sub-optimal */
|
||||
/* since the actual pokey emulation should grab the frequency values */
|
||||
/* directly from here instead of calculating them again. */
|
||||
/* */
|
||||
/* Author: Ron Fries,Thomas Richter */
|
||||
/* Date: March 27, 1998 */
|
||||
/* */
|
||||
/* Inputs: chan_mask: Channel mask, one bit per channel. */
|
||||
/* The channels that need to be updated */
|
||||
/* */
|
||||
/* Outputs: Adjusts local globals - no return value */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
static void Update_Counter(int chan_mask)
|
||||
{
|
||||
|
||||
/************************************************************/
|
||||
/* As defined in the manual, the exact Div_n_cnt values are */
|
||||
/* different depending on the frequency and resolution: */
|
||||
/* 64 kHz or 15 kHz - AUDF + 1 */
|
||||
/* 1 MHz, 8-bit - AUDF + 4 */
|
||||
/* 1 MHz, 16-bit - AUDF[CHAN1]+256*AUDF[CHAN2] + 7 */
|
||||
/************************************************************/
|
||||
|
||||
/* only reset the channels that have changed */
|
||||
|
||||
if (chan_mask & (1 << POKEY_CHAN1)) {
|
||||
/* process channel 1 frequency */
|
||||
if (POKEY_AUDCTL[0] & POKEY_CH1_179)
|
||||
POKEY_DivNMax[POKEY_CHAN1] = POKEY_AUDF[POKEY_CHAN1] + 4;
|
||||
else
|
||||
POKEY_DivNMax[POKEY_CHAN1] = (POKEY_AUDF[POKEY_CHAN1] + 1) * POKEY_Base_mult[0];
|
||||
if (POKEY_DivNMax[POKEY_CHAN1] < ANTIC_LINE_C)
|
||||
POKEY_DivNMax[POKEY_CHAN1] = ANTIC_LINE_C;
|
||||
}
|
||||
|
||||
if (chan_mask & (1 << POKEY_CHAN2)) {
|
||||
/* process channel 2 frequency */
|
||||
if (POKEY_AUDCTL[0] & POKEY_CH1_CH2) {
|
||||
if (POKEY_AUDCTL[0] & POKEY_CH1_179)
|
||||
POKEY_DivNMax[POKEY_CHAN2] = POKEY_AUDF[POKEY_CHAN2] * 256 + POKEY_AUDF[POKEY_CHAN1] + 7;
|
||||
else
|
||||
POKEY_DivNMax[POKEY_CHAN2] = (POKEY_AUDF[POKEY_CHAN2] * 256 + POKEY_AUDF[POKEY_CHAN1] + 1) * POKEY_Base_mult[0];
|
||||
}
|
||||
else
|
||||
POKEY_DivNMax[POKEY_CHAN2] = (POKEY_AUDF[POKEY_CHAN2] + 1) * POKEY_Base_mult[0];
|
||||
if (POKEY_DivNMax[POKEY_CHAN2] < ANTIC_LINE_C)
|
||||
POKEY_DivNMax[POKEY_CHAN2] = ANTIC_LINE_C;
|
||||
}
|
||||
|
||||
if (chan_mask & (1 << POKEY_CHAN4)) {
|
||||
/* process channel 4 frequency */
|
||||
if (POKEY_AUDCTL[0] & POKEY_CH3_CH4) {
|
||||
if (POKEY_AUDCTL[0] & POKEY_CH3_179)
|
||||
POKEY_DivNMax[POKEY_CHAN4] = POKEY_AUDF[POKEY_CHAN4] * 256 + POKEY_AUDF[POKEY_CHAN3] + 7;
|
||||
else
|
||||
POKEY_DivNMax[POKEY_CHAN4] = (POKEY_AUDF[POKEY_CHAN4] * 256 + POKEY_AUDF[POKEY_CHAN3] + 1) * POKEY_Base_mult[0];
|
||||
}
|
||||
else
|
||||
POKEY_DivNMax[POKEY_CHAN4] = (POKEY_AUDF[POKEY_CHAN4] + 1) * POKEY_Base_mult[0];
|
||||
if (POKEY_DivNMax[POKEY_CHAN4] < ANTIC_LINE_C)
|
||||
POKEY_DivNMax[POKEY_CHAN4] = ANTIC_LINE_C;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BASIC
|
||||
|
||||
void POKEY_StateSave(void)
|
||||
{
|
||||
int shift_key = 0;
|
||||
int keypressed = 0;
|
||||
|
||||
StateSav_SaveUBYTE(&POKEY_KBCODE, 1);
|
||||
StateSav_SaveUBYTE(&POKEY_IRQST, 1);
|
||||
StateSav_SaveUBYTE(&POKEY_IRQEN, 1);
|
||||
StateSav_SaveUBYTE(&POKEY_SKCTL, 1);
|
||||
|
||||
StateSav_SaveINT(&shift_key, 1);
|
||||
StateSav_SaveINT(&keypressed, 1);
|
||||
StateSav_SaveINT(&POKEY_DELAYED_SERIN_IRQ, 1);
|
||||
StateSav_SaveINT(&POKEY_DELAYED_SEROUT_IRQ, 1);
|
||||
StateSav_SaveINT(&POKEY_DELAYED_XMTDONE_IRQ, 1);
|
||||
|
||||
StateSav_SaveUBYTE(&POKEY_AUDF[0], 4);
|
||||
StateSav_SaveUBYTE(&POKEY_AUDC[0], 4);
|
||||
StateSav_SaveUBYTE(&POKEY_AUDCTL[0], 1);
|
||||
|
||||
StateSav_SaveINT(&POKEY_DivNIRQ[0], 4);
|
||||
StateSav_SaveINT(&POKEY_DivNMax[0], 4);
|
||||
StateSav_SaveINT(&POKEY_Base_mult[0], 1);
|
||||
}
|
||||
|
||||
void POKEY_StateRead(void)
|
||||
{
|
||||
int i;
|
||||
int shift_key;
|
||||
int keypressed;
|
||||
|
||||
StateSav_ReadUBYTE(&POKEY_KBCODE, 1);
|
||||
StateSav_ReadUBYTE(&POKEY_IRQST, 1);
|
||||
StateSav_ReadUBYTE(&POKEY_IRQEN, 1);
|
||||
StateSav_ReadUBYTE(&POKEY_SKCTL, 1);
|
||||
|
||||
StateSav_ReadINT(&shift_key, 1);
|
||||
StateSav_ReadINT(&keypressed, 1);
|
||||
StateSav_ReadINT(&POKEY_DELAYED_SERIN_IRQ, 1);
|
||||
StateSav_ReadINT(&POKEY_DELAYED_SEROUT_IRQ, 1);
|
||||
StateSav_ReadINT(&POKEY_DELAYED_XMTDONE_IRQ, 1);
|
||||
|
||||
StateSav_ReadUBYTE(&POKEY_AUDF[0], 4);
|
||||
StateSav_ReadUBYTE(&POKEY_AUDC[0], 4);
|
||||
StateSav_ReadUBYTE(&POKEY_AUDCTL[0], 1);
|
||||
for (i = 0; i < 4; i++) {
|
||||
POKEY_PutByte((UWORD) (POKEY_OFFSET_AUDF1 + i * 2), POKEY_AUDF[i]);
|
||||
POKEY_PutByte((UWORD) (POKEY_OFFSET_AUDC1 + i * 2), POKEY_AUDC[i]);
|
||||
}
|
||||
POKEY_PutByte(POKEY_OFFSET_AUDCTL, POKEY_AUDCTL[0]);
|
||||
|
||||
StateSav_ReadINT(&POKEY_DivNIRQ[0], 4);
|
||||
StateSav_ReadINT(&POKEY_DivNMax[0], 4);
|
||||
StateSav_ReadINT(&POKEY_Base_mult[0], 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,122 +0,0 @@
|
||||
#ifndef POKEY_H_
|
||||
#define POKEY_H_
|
||||
|
||||
#ifdef ASAP /* external project, see http://asap.sf.net */
|
||||
#include "asap_internal.h"
|
||||
#else
|
||||
#include "atari.h"
|
||||
#endif
|
||||
|
||||
#define POKEY_OFFSET_AUDF1 0x00
|
||||
#define POKEY_OFFSET_AUDC1 0x01
|
||||
#define POKEY_OFFSET_AUDF2 0x02
|
||||
#define POKEY_OFFSET_AUDC2 0x03
|
||||
#define POKEY_OFFSET_AUDF3 0x04
|
||||
#define POKEY_OFFSET_AUDC3 0x05
|
||||
#define POKEY_OFFSET_AUDF4 0x06
|
||||
#define POKEY_OFFSET_AUDC4 0x07
|
||||
#define POKEY_OFFSET_AUDCTL 0x08
|
||||
#define POKEY_OFFSET_STIMER 0x09
|
||||
#define POKEY_OFFSET_SKRES 0x0a
|
||||
#define POKEY_OFFSET_POTGO 0x0b
|
||||
#define POKEY_OFFSET_SEROUT 0x0d
|
||||
#define POKEY_OFFSET_IRQEN 0x0e
|
||||
#define POKEY_OFFSET_SKCTL 0x0f
|
||||
|
||||
#define POKEY_OFFSET_POT0 0x00
|
||||
#define POKEY_OFFSET_POT1 0x01
|
||||
#define POKEY_OFFSET_POT2 0x02
|
||||
#define POKEY_OFFSET_POT3 0x03
|
||||
#define POKEY_OFFSET_POT4 0x04
|
||||
#define POKEY_OFFSET_POT5 0x05
|
||||
#define POKEY_OFFSET_POT6 0x06
|
||||
#define POKEY_OFFSET_POT7 0x07
|
||||
#define POKEY_OFFSET_ALLPOT 0x08
|
||||
#define POKEY_OFFSET_KBCODE 0x09
|
||||
#define POKEY_OFFSET_RANDOM 0x0a
|
||||
#define POKEY_OFFSET_SERIN 0x0d
|
||||
#define POKEY_OFFSET_IRQST 0x0e
|
||||
#define POKEY_OFFSET_SKSTAT 0x0f
|
||||
|
||||
#define POKEY_OFFSET_POKEY2 0x10 /* offset to second pokey chip (STEREO expansion) */
|
||||
|
||||
#ifndef ASAP
|
||||
|
||||
extern UBYTE POKEY_KBCODE;
|
||||
extern UBYTE POKEY_IRQST;
|
||||
extern UBYTE POKEY_IRQEN;
|
||||
extern UBYTE POKEY_SKSTAT;
|
||||
extern UBYTE POKEY_SKCTL;
|
||||
extern int POKEY_DELAYED_SERIN_IRQ;
|
||||
extern int POKEY_DELAYED_SEROUT_IRQ;
|
||||
extern int POKEY_DELAYED_XMTDONE_IRQ;
|
||||
|
||||
extern UBYTE POKEY_POT_input[8];
|
||||
|
||||
ULONG POKEY_GetRandomCounter(void);
|
||||
void POKEY_SetRandomCounter(ULONG value);
|
||||
UBYTE POKEY_GetByte(UWORD addr);
|
||||
void POKEY_PutByte(UWORD addr, UBYTE byte);
|
||||
int POKEY_Initialise(int *argc, char *argv[]);
|
||||
void POKEY_Frame(void);
|
||||
void POKEY_Scanline(void);
|
||||
void POKEY_StateSave(void);
|
||||
void POKEY_StateRead(void);
|
||||
|
||||
#endif
|
||||
|
||||
/* CONSTANT DEFINITIONS */
|
||||
|
||||
/* definitions for AUDCx (D201, D203, D205, D207) */
|
||||
#define POKEY_NOTPOLY5 0x80 /* selects POLY5 or direct CLOCK */
|
||||
#define POKEY_POLY4 0x40 /* selects POLY4 or POLY17 */
|
||||
#define POKEY_PURETONE 0x20 /* selects POLY4/17 or PURE tone */
|
||||
#define POKEY_VOL_ONLY 0x10 /* selects VOLUME OUTPUT ONLY */
|
||||
#define POKEY_VOLUME_MASK 0x0f /* volume mask */
|
||||
|
||||
/* definitions for AUDCTL (D208) */
|
||||
#define POKEY_POLY9 0x80 /* selects POLY9 or POLY17 */
|
||||
#define POKEY_CH1_179 0x40 /* selects 1.78979 MHz for Ch 1 */
|
||||
#define POKEY_CH3_179 0x20 /* selects 1.78979 MHz for Ch 3 */
|
||||
#define POKEY_CH1_CH2 0x10 /* clocks channel 1 w/channel 2 */
|
||||
#define POKEY_CH3_CH4 0x08 /* clocks channel 3 w/channel 4 */
|
||||
#define POKEY_CH1_FILTER 0x04 /* selects channel 1 high pass filter */
|
||||
#define POKEY_CH2_FILTER 0x02 /* selects channel 2 high pass filter */
|
||||
#define POKEY_CLOCK_15 0x01 /* selects 15.6999kHz or 63.9210kHz */
|
||||
|
||||
/* for accuracy, the 64kHz and 15kHz clocks are exact divisions of
|
||||
the 1.79MHz clock */
|
||||
#define POKEY_DIV_64 28 /* divisor for 1.79MHz clock to 64 kHz */
|
||||
#define POKEY_DIV_15 114 /* divisor for 1.79MHz clock to 15 kHz */
|
||||
|
||||
/* the size (in entries) of the 4 polynomial tables */
|
||||
#define POKEY_POLY4_SIZE 0x000f
|
||||
#define POKEY_POLY5_SIZE 0x001f
|
||||
#define POKEY_POLY9_SIZE 0x01ff
|
||||
#define POKEY_POLY17_SIZE 0x0001ffff
|
||||
|
||||
#define POKEY_MAXPOKEYS 2 /* max number of emulated chips */
|
||||
|
||||
/* channel/chip definitions */
|
||||
#define POKEY_CHAN1 0
|
||||
#define POKEY_CHAN2 1
|
||||
#define POKEY_CHAN3 2
|
||||
#define POKEY_CHAN4 3
|
||||
#define POKEY_CHIP1 0
|
||||
#define POKEY_CHIP2 4
|
||||
#define POKEY_CHIP3 8
|
||||
#define POKEY_CHIP4 12
|
||||
#define POKEY_SAMPLE 127
|
||||
|
||||
/* structures to hold the 9 pokey control bytes */
|
||||
extern UBYTE POKEY_AUDF[4 * POKEY_MAXPOKEYS]; /* AUDFx (D200, D202, D204, D206) */
|
||||
extern UBYTE POKEY_AUDC[4 * POKEY_MAXPOKEYS]; /* AUDCx (D201, D203, D205, D207) */
|
||||
extern UBYTE POKEY_AUDCTL[POKEY_MAXPOKEYS]; /* AUDCTL (D208) */
|
||||
|
||||
extern int POKEY_DivNIRQ[4], POKEY_DivNMax[4];
|
||||
extern int POKEY_Base_mult[POKEY_MAXPOKEYS]; /* selects either 64Khz or 15Khz clock mult */
|
||||
|
||||
extern UBYTE POKEY_poly9_lookup[POKEY_POLY9_SIZE];
|
||||
extern UBYTE POKEY_poly17_lookup[16385];
|
||||
|
||||
#endif /* POKEY_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,130 +0,0 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Module: POKEY Chip Simulator Includes, V2.3 */
|
||||
/* Purpose: To emulate the sound generation hardware of the Atari POKEY chip. */
|
||||
/* Author: Ron Fries */
|
||||
/* */
|
||||
/* Revision History: */
|
||||
/* */
|
||||
/* 09/22/96 - Ron Fries - Initial Release */
|
||||
/* 04/06/97 - Brad Oliver - Some cross-platform modifications. Added */
|
||||
/* big/little endian #defines, removed <dos.h>, */
|
||||
/* conditional defines for TRUE/FALSE */
|
||||
/* 01/19/98 - Ron Fries - Changed signed/unsigned sample support to a */
|
||||
/* compile-time option. Defaults to unsigned - */
|
||||
/* define SIGNED_SAMPLES to create signed. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* License Information and Copyright Notice */
|
||||
/* ======================================== */
|
||||
/* */
|
||||
/* PokeySound is Copyright(c) 1996-1998 by Ron Fries */
|
||||
/* */
|
||||
/* This library is free software; you can redistribute it and/or modify it */
|
||||
/* under the terms of version 2 of the GNU Library General Public License */
|
||||
/* as published by the Free Software Foundation. */
|
||||
/* */
|
||||
/* This library 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 Library */
|
||||
/* General Public License for more details. */
|
||||
/* To obtain a copy of the GNU Library General Public License, write to the */
|
||||
/* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
/* */
|
||||
/* Any permitted reproduction of these routines, in whole or in part, must */
|
||||
/* bear this legend. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef POKEYSND_H_
|
||||
#define POKEYSND_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "pokey.h"
|
||||
|
||||
/* CONSTANT DEFINITIONS */
|
||||
|
||||
/* As an alternative to using the exact frequencies, selecting a playback
|
||||
frequency that is an exact division of the main clock provides a higher
|
||||
quality output due to less aliasing. For best results, a value of
|
||||
1787520 MHz is used for the main clock. With this value, both the
|
||||
64 kHz and 15 kHz clocks are evenly divisible. Selecting a playback
|
||||
frequency that is also a division of the clock provides the best
|
||||
results. The best options are FREQ_64 divided by either 2, 3, or 4.
|
||||
The best selection is based on a trade off between performance and
|
||||
sound quality.
|
||||
|
||||
Of course, using a main clock frequency that is not exact will affect
|
||||
the pitch of the output. With these numbers, the pitch will be low
|
||||
by 0.127%. (More than likely, an actual unit will vary by this much!) */
|
||||
|
||||
#define POKEYSND_FREQ_17_EXACT 1789790 /* exact 1.79 MHz clock freq */
|
||||
#define POKEYSND_FREQ_17_APPROX 1787520 /* approximate 1.79 MHz clock freq */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* #define SIGNED_SAMPLES */ /* define for signed output */
|
||||
|
||||
#ifdef POKEYSND_SIGNED_SAMPLES /* if signed output selected */
|
||||
#define POKEYSND_SAMP_MAX 127 /* then set signed 8-bit clipping ranges */
|
||||
#define POKEYSND_SAMP_MIN -128
|
||||
#define POKEYSND_SAMP_MID 0
|
||||
#else
|
||||
#define POKEYSND_SAMP_MAX 255 /* else set unsigned 8-bit clip ranges */
|
||||
#define POKEYSND_SAMP_MIN 0
|
||||
#define POKEYSND_SAMP_MID 128
|
||||
#endif
|
||||
|
||||
/* init flags */
|
||||
#define POKEYSND_BIT16 1
|
||||
|
||||
extern SLONG POKEYSND_playback_freq;
|
||||
extern UBYTE POKEYSND_num_pokeys;
|
||||
extern int POKEYSND_snd_flags;
|
||||
|
||||
extern int POKEYSND_enable_new_pokey;
|
||||
extern int POKEYSND_stereo_enabled;
|
||||
extern int POKEYSND_serio_sound_enabled;
|
||||
extern int POKEYSND_console_sound_enabled;
|
||||
extern int POKEYSND_bienias_fix;
|
||||
|
||||
extern void (*POKEYSND_Process_ptr)(void *sndbuffer, int sndn);
|
||||
extern void (*POKEYSND_Update)(UWORD addr, UBYTE val, UBYTE /*chip*/, UBYTE gain);
|
||||
extern void (*POKEYSND_UpdateSerio)(int out, UBYTE data);
|
||||
extern void (*POKEYSND_UpdateConsol)(int set);
|
||||
extern void (*POKEYSND_UpdateVolOnly)(void);
|
||||
|
||||
int POKEYSND_Init(ULONG freq17, int playback_freq, UBYTE num_pokeys,
|
||||
int flags
|
||||
#ifdef __PLUS
|
||||
, int clear_regs
|
||||
#endif
|
||||
);
|
||||
void POKEYSND_Process(void *sndbuffer, int sndn);
|
||||
int POKEYSND_DoInit(void);
|
||||
void POKEYSND_SetMzQuality(int quality);
|
||||
|
||||
/* Volume only emulations declarations */
|
||||
#ifdef VOL_ONLY_SOUND
|
||||
|
||||
#define POKEYSND_SAMPBUF_MAX 2000
|
||||
extern int POKEYSND_sampbuf_val[POKEYSND_SAMPBUF_MAX]; /* volume values */
|
||||
extern int POKEYSND_sampbuf_cnt[POKEYSND_SAMPBUF_MAX]; /* relative start time */
|
||||
extern int POKEYSND_sampbuf_ptr; /* pointer to sampbuf */
|
||||
extern int POKEYSND_sampbuf_rptr; /* pointer to read from sampbuf */
|
||||
extern int POKEYSND_sampbuf_last; /* last absolute time */
|
||||
extern int POKEYSND_sampbuf_AUDV[4 * POKEY_MAXPOKEYS]; /* prev. channel volume */
|
||||
extern int POKEYSND_sampbuf_lastval; /* last volume */
|
||||
extern int POKEYSND_sampout; /* last out volume */
|
||||
extern int POKEYSND_samp_freq;
|
||||
extern int POKEYSND_samp_consol_val; /* actual value of console sound */
|
||||
#endif /* VOL_ONLY_SOUND */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* POKEYSND_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* rdevice.h - Atari850 emulation header file
|
||||
*
|
||||
* Copyright (c) ???? Tom Hunt, Chris Martin
|
||||
* Copyright (c) 2003,2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef RDEVICE_H_
|
||||
#define RDEVICE_H_
|
||||
|
||||
extern void RDevice_OPEN(void);
|
||||
extern void RDevice_CLOS(void);
|
||||
extern void RDevice_READ(void);
|
||||
extern void RDevice_WRIT(void);
|
||||
extern void RDevice_STAT(void);
|
||||
extern void RDevice_SPEC(void);
|
||||
extern void RDevice_INIT(void);
|
||||
|
||||
extern int RDevice_serial_enabled;
|
||||
extern char RDevice_serial_device[];
|
||||
|
||||
extern void RDevice_Exit(void);
|
||||
|
||||
#endif /* RDEVICE_H_ */
|
||||
@@ -1,643 +0,0 @@
|
||||
/*
|
||||
* remez.c - Parks-McClellan algorithm for FIR filter design (C version)
|
||||
*
|
||||
* Copyright (C) 1995,1998 Jake Janovetz
|
||||
* Copyright (C) 1998-2005 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "remez.h"
|
||||
#ifdef ASAP /* external project, see http://asap.sf.net */
|
||||
#include "asap_internal.h"
|
||||
#else
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#endif
|
||||
|
||||
#define NEGATIVE 0
|
||||
#define POSITIVE 1
|
||||
|
||||
#define Pi 3.1415926535897932
|
||||
#define Pi2 6.2831853071795865
|
||||
|
||||
#define GRIDDENSITY 16
|
||||
#define MAXITERATIONS 40
|
||||
|
||||
/*******************
|
||||
* CreateDenseGrid
|
||||
*=================
|
||||
* Creates the dense grid of frequencies from the specified bands.
|
||||
* Also creates the Desired Frequency Response function (D[]) and
|
||||
* the Weight function (W[]) on that dense grid
|
||||
*
|
||||
*
|
||||
* INPUT:
|
||||
* ------
|
||||
* int r - 1/2 the number of filter coefficients
|
||||
* int numtaps - Number of taps in the resulting filter
|
||||
* int numband - Number of bands in user specification
|
||||
* double bands[] - User-specified band edges [2*numband]
|
||||
* double des[] - Desired response per band [numband]
|
||||
* double weight[] - Weight per band [numband]
|
||||
* int symmetry - Symmetry of filter - used for grid check
|
||||
*
|
||||
* OUTPUT:
|
||||
* -------
|
||||
* int gridsize - Number of elements in the dense frequency grid
|
||||
* double Grid[] - Frequencies (0 to 0.5) on the dense grid [gridsize]
|
||||
* double D[] - Desired response on the dense grid [gridsize]
|
||||
* double W[] - Weight function on the dense grid [gridsize]
|
||||
*******************/
|
||||
|
||||
static void CreateDenseGrid(int r, int numtaps, int numband, double bands[],
|
||||
const double des[], const double weight[],
|
||||
int *gridsize, double Grid[],
|
||||
double D[], double W[], int symmetry)
|
||||
{
|
||||
int i, j, k, band;
|
||||
double delf, lowf, highf;
|
||||
|
||||
delf = 0.5 / (GRIDDENSITY * r);
|
||||
|
||||
/* For differentiator, hilbert,
|
||||
* symmetry is odd and Grid[0] = max(delf, band[0]) */
|
||||
|
||||
if (symmetry == NEGATIVE && delf > bands[0])
|
||||
bands[0] = delf;
|
||||
|
||||
j = 0;
|
||||
for (band = 0; band < numband; band++) {
|
||||
Grid[j] = bands[2 * band];
|
||||
lowf = bands[2 * band];
|
||||
highf = bands[2 * band + 1];
|
||||
k = (int) ((highf - lowf) / delf + 0.5); /* .5 for rounding */
|
||||
for (i = 0; i < k; i++) {
|
||||
D[j] = des[band];
|
||||
W[j] = weight[band];
|
||||
Grid[j] = lowf;
|
||||
lowf += delf;
|
||||
j++;
|
||||
}
|
||||
Grid[j - 1] = highf;
|
||||
}
|
||||
|
||||
/* Similar to above, if odd symmetry, last grid point can't be .5
|
||||
* - but, if there are even taps, leave the last grid point at .5 */
|
||||
if ((symmetry == NEGATIVE) &&
|
||||
(Grid[*gridsize - 1] > (0.5 - delf)) &&
|
||||
(numtaps % 2))
|
||||
{
|
||||
Grid[*gridsize - 1] = 0.5 - delf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
* InitialGuess
|
||||
*==============
|
||||
* Places Extremal Frequencies evenly throughout the dense grid.
|
||||
*
|
||||
*
|
||||
* INPUT:
|
||||
* ------
|
||||
* int r - 1/2 the number of filter coefficients
|
||||
* int gridsize - Number of elements in the dense frequency grid
|
||||
*
|
||||
* OUTPUT:
|
||||
* -------
|
||||
* int Ext[] - Extremal indexes to dense frequency grid [r+1]
|
||||
********************/
|
||||
|
||||
static void InitialGuess(int r, int Ext[], int gridsize)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= r; i++)
|
||||
Ext[i] = i * (gridsize - 1) / r;
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
* CalcParms
|
||||
*===========
|
||||
*
|
||||
*
|
||||
* INPUT:
|
||||
* ------
|
||||
* int r - 1/2 the number of filter coefficients
|
||||
* int Ext[] - Extremal indexes to dense frequency grid [r+1]
|
||||
* double Grid[] - Frequencies (0 to 0.5) on the dense grid [gridsize]
|
||||
* double D[] - Desired response on the dense grid [gridsize]
|
||||
* double W[] - Weight function on the dense grid [gridsize]
|
||||
*
|
||||
* OUTPUT:
|
||||
* -------
|
||||
* double ad[] - 'b' in Oppenheim & Schafer [r+1]
|
||||
* double x[] - [r+1]
|
||||
* double y[] - 'C' in Oppenheim & Schafer [r+1]
|
||||
***********************/
|
||||
|
||||
static void CalcParms(int r, const int Ext[], const double Grid[],
|
||||
const double D[], const double W[],
|
||||
double ad[], double x[], double y[])
|
||||
{
|
||||
int i, j, k, ld;
|
||||
double sign, xi, delta, denom, numer;
|
||||
|
||||
/* Find x[] */
|
||||
for (i = 0; i <= r; i++)
|
||||
x[i] = cos(Pi2 * Grid[Ext[i]]);
|
||||
|
||||
/* Calculate ad[] - Oppenheim & Schafer eq 7.132 */
|
||||
ld = (r - 1) / 15 + 1; /* Skips around to avoid round errors */
|
||||
for (i = 0; i <= r; i++) {
|
||||
denom = 1.0;
|
||||
xi = x[i];
|
||||
for (j = 0; j < ld; j++) {
|
||||
for (k = j; k <= r; k += ld)
|
||||
if (k != i)
|
||||
denom *= 2.0 * (xi - x[k]);
|
||||
}
|
||||
if (fabs(denom) < 0.00001)
|
||||
denom = 0.00001;
|
||||
ad[i] = 1.0 / denom;
|
||||
}
|
||||
|
||||
/* Calculate delta - Oppenheim & Schafer eq 7.131 */
|
||||
numer = denom = 0;
|
||||
sign = 1;
|
||||
for (i = 0; i <= r; i++) {
|
||||
numer += ad[i] * D[Ext[i]];
|
||||
denom += sign * ad[i] / W[Ext[i]];
|
||||
sign = -sign;
|
||||
}
|
||||
delta = numer / denom;
|
||||
sign = 1;
|
||||
|
||||
/* Calculate y[] - Oppenheim & Schafer eq 7.133b */
|
||||
for (i = 0; i <= r; i++) {
|
||||
y[i] = D[Ext[i]] - sign * delta / W[Ext[i]];
|
||||
sign = -sign;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************
|
||||
* ComputeA
|
||||
*==========
|
||||
* Using values calculated in CalcParms, ComputeA calculates the
|
||||
* actual filter response at a given frequency (freq). Uses
|
||||
* eq 7.133a from Oppenheim & Schafer.
|
||||
*
|
||||
*
|
||||
* INPUT:
|
||||
* ------
|
||||
* double freq - Frequency (0 to 0.5) at which to calculate A
|
||||
* int r - 1/2 the number of filter coefficients
|
||||
* double ad[] - 'b' in Oppenheim & Schafer [r+1]
|
||||
* double x[] - [r+1]
|
||||
* double y[] - 'C' in Oppenheim & Schafer [r+1]
|
||||
*
|
||||
* OUTPUT:
|
||||
* -------
|
||||
* Returns double value of A[freq]
|
||||
*********************/
|
||||
|
||||
static double ComputeA(double freq, int r, const double ad[],
|
||||
const double x[], const double y[])
|
||||
{
|
||||
int i;
|
||||
double xc, c, denom, numer;
|
||||
|
||||
denom = numer = 0;
|
||||
xc = cos(Pi2 * freq);
|
||||
for (i = 0; i <= r; i++) {
|
||||
c = xc - x[i];
|
||||
if (fabs(c) < 1.0e-7) {
|
||||
numer = y[i];
|
||||
denom = 1;
|
||||
break;
|
||||
}
|
||||
c = ad[i] / c;
|
||||
denom += c;
|
||||
numer += c * y[i];
|
||||
}
|
||||
return numer / denom;
|
||||
}
|
||||
|
||||
|
||||
/************************
|
||||
* CalcError
|
||||
*===========
|
||||
* Calculates the Error function from the desired frequency response
|
||||
* on the dense grid (D[]), the weight function on the dense grid (W[]),
|
||||
* and the present response calculation (A[])
|
||||
*
|
||||
*
|
||||
* INPUT:
|
||||
* ------
|
||||
* int r - 1/2 the number of filter coefficients
|
||||
* double ad[] - [r+1]
|
||||
* double x[] - [r+1]
|
||||
* double y[] - [r+1]
|
||||
* int gridsize - Number of elements in the dense frequency grid
|
||||
* double Grid[] - Frequencies on the dense grid [gridsize]
|
||||
* double D[] - Desired response on the dense grid [gridsize]
|
||||
* double W[] - Weight function on the desnse grid [gridsize]
|
||||
*
|
||||
* OUTPUT:
|
||||
* -------
|
||||
* double E[] - Error function on dense grid [gridsize]
|
||||
************************/
|
||||
|
||||
static void CalcError(int r, const double ad[],
|
||||
const double x[], const double y[],
|
||||
int gridsize, const double Grid[],
|
||||
const double D[], const double W[], double E[])
|
||||
{
|
||||
int i;
|
||||
double A;
|
||||
|
||||
for (i = 0; i < gridsize; i++) {
|
||||
A = ComputeA(Grid[i], r, ad, x, y);
|
||||
E[i] = W[i] * (D[i] - A);
|
||||
}
|
||||
}
|
||||
|
||||
/************************
|
||||
* Search
|
||||
*========
|
||||
* Searches for the maxima/minima of the error curve. If more than
|
||||
* r+1 extrema are found, it uses the following heuristic (thanks
|
||||
* Chris Hanson):
|
||||
* 1) Adjacent non-alternating extrema deleted first.
|
||||
* 2) If there are more than one excess extrema, delete the
|
||||
* one with the smallest error. This will create a non-alternation
|
||||
* condition that is fixed by 1).
|
||||
* 3) If there is exactly one excess extremum, delete the smaller
|
||||
* of the first/last extremum
|
||||
*
|
||||
*
|
||||
* INPUT:
|
||||
* ------
|
||||
* int r - 1/2 the number of filter coefficients
|
||||
* int Ext[] - Indexes to Grid[] of extremal frequencies [r+1]
|
||||
* int gridsize - Number of elements in the dense frequency grid
|
||||
* double E[] - Array of error values. [gridsize]
|
||||
* OUTPUT:
|
||||
* -------
|
||||
* int Ext[] - New indexes to extremal frequencies [r+1]
|
||||
************************/
|
||||
|
||||
static void Search(int r, int Ext[], int gridsize, const double E[])
|
||||
{
|
||||
int i, j, k, l, extra; /* Counters */
|
||||
int up, alt;
|
||||
int *foundExt; /* Array of found extremals */
|
||||
|
||||
/* Allocate enough space for found extremals. */
|
||||
foundExt = (int *) Util_malloc((2 * r) * sizeof(int));
|
||||
k = 0;
|
||||
|
||||
/* Check for extremum at 0. */
|
||||
if (((E[0] > 0.0) && (E[0] > E[1])) ||
|
||||
((E[0] < 0.0) && (E[0] < E[1])))
|
||||
foundExt[k++] = 0;
|
||||
|
||||
/* Check for extrema inside dense grid */
|
||||
for (i = 1; i < gridsize - 1; i++) {
|
||||
if (((E[i] >= E[i - 1]) && (E[i] > E[i + 1]) && (E[i] > 0.0)) ||
|
||||
((E[i] <= E[i - 1]) && (E[i] < E[i + 1]) && (E[i] < 0.0)))
|
||||
foundExt[k++] = i;
|
||||
}
|
||||
|
||||
/* Check for extremum at 0.5 */
|
||||
j = gridsize - 1;
|
||||
if (((E[j] > 0.0) && (E[j] > E[j - 1])) ||
|
||||
((E[j] < 0.0) && (E[j] < E[j - 1])))
|
||||
foundExt[k++] = j;
|
||||
|
||||
/* Remove extra extremals */
|
||||
extra = k - (r + 1);
|
||||
|
||||
while (extra > 0) {
|
||||
if (E[foundExt[0]] > 0.0)
|
||||
up = 1; /* first one is a maxima */
|
||||
else
|
||||
up = 0; /* first one is a minima */
|
||||
|
||||
l = 0;
|
||||
alt = 1;
|
||||
for (j = 1; j < k; j++) {
|
||||
if (fabs(E[foundExt[j]]) < fabs(E[foundExt[l]]))
|
||||
l = j; /* new smallest error. */
|
||||
if ((up) && (E[foundExt[j]] < 0.0))
|
||||
up = 0; /* switch to a minima */
|
||||
else if ((!up) && (E[foundExt[j]] > 0.0))
|
||||
up = 1; /* switch to a maxima */
|
||||
else {
|
||||
alt = 0;
|
||||
break; /* Ooops, found two non-alternating */
|
||||
} /* extrema. Delete smallest of them */
|
||||
} /* if the loop finishes, all extrema are alternating */
|
||||
|
||||
/* If there's only one extremal and all are alternating,
|
||||
* delete the smallest of the first/last extremals. */
|
||||
if ((alt) && (extra == 1)) {
|
||||
if (fabs(E[foundExt[k - 1]]) < fabs(E[foundExt[0]]))
|
||||
l = foundExt[k - 1]; /* Delete last extremal */
|
||||
else
|
||||
l = foundExt[0]; /* Delete first extremal */
|
||||
}
|
||||
|
||||
/* Loop that does the deletion */
|
||||
for (j = l; j < k; j++) {
|
||||
foundExt[j] = foundExt[j+1];
|
||||
}
|
||||
k--;
|
||||
extra--;
|
||||
}
|
||||
|
||||
/* Copy found extremals to Ext[] */
|
||||
for (i = 0; i <= r; i++) {
|
||||
Ext[i] = foundExt[i];
|
||||
}
|
||||
|
||||
free(foundExt);
|
||||
}
|
||||
|
||||
|
||||
/*********************
|
||||
* FreqSample
|
||||
*============
|
||||
* Simple frequency sampling algorithm to determine the impulse
|
||||
* response h[] from A's found in ComputeA
|
||||
*
|
||||
*
|
||||
* INPUT:
|
||||
* ------
|
||||
* int N - Number of filter coefficients
|
||||
* double A[] - Sample points of desired response [N/2]
|
||||
* int symm - Symmetry of desired filter
|
||||
*
|
||||
* OUTPUT:
|
||||
* -------
|
||||
* double h[] - Impulse Response of final filter [N]
|
||||
*********************/
|
||||
static void FreqSample(int N, const double A[], double h[], int symm)
|
||||
{
|
||||
int n, k;
|
||||
double x, val, M;
|
||||
|
||||
M = (N - 1.0) / 2.0;
|
||||
if (symm == POSITIVE) {
|
||||
if (N % 2) {
|
||||
for (n = 0; n < N; n++) {
|
||||
val = A[0];
|
||||
x = Pi2 * (n - M) / N;
|
||||
for (k = 1; k <= M; k++)
|
||||
val += 2.0 * A[k] * cos(x * k);
|
||||
h[n] = val / N;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (n = 0; n < N; n++) {
|
||||
val = A[0];
|
||||
x = Pi2 * (n - M)/N;
|
||||
for (k = 1; k <= (N / 2 - 1); k++)
|
||||
val += 2.0 * A[k] * cos(x * k);
|
||||
h[n] = val / N;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (N % 2) {
|
||||
for (n = 0; n < N; n++) {
|
||||
val = 0;
|
||||
x = Pi2 * (n - M) / N;
|
||||
for (k = 1; k <= M; k++)
|
||||
val += 2.0 * A[k] * sin(x * k);
|
||||
h[n] = val / N;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (n = 0; n < N; n++) {
|
||||
val = A[N / 2] * sin(Pi * (n - M));
|
||||
x = Pi2 * (n - M) / N;
|
||||
for (k = 1; k <= (N / 2 - 1); k++)
|
||||
val += 2.0 * A[k] * sin(x * k);
|
||||
h[n] = val / N;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************
|
||||
* isDone
|
||||
*========
|
||||
* Checks to see if the error function is small enough to consider
|
||||
* the result to have converged.
|
||||
*
|
||||
* INPUT:
|
||||
* ------
|
||||
* int r - 1/2 the number of filter coeffiecients
|
||||
* int Ext[] - Indexes to extremal frequencies [r+1]
|
||||
* double E[] - Error function on the dense grid [gridsize]
|
||||
*
|
||||
* OUTPUT:
|
||||
* -------
|
||||
* Returns 1 if the result converged
|
||||
* Returns 0 if the result has not converged
|
||||
********************/
|
||||
|
||||
static int isDone(int r, const int Ext[], const double E[])
|
||||
{
|
||||
int i;
|
||||
double min, max, current;
|
||||
|
||||
min = max = fabs(E[Ext[0]]);
|
||||
for (i = 1; i <= r; i++) {
|
||||
current = fabs(E[Ext[i]]);
|
||||
if (current < min)
|
||||
min = current;
|
||||
if (current > max)
|
||||
max = current;
|
||||
}
|
||||
if (((max - min) / max) < 0.0001)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/********************
|
||||
* REMEZ_CreateFilter
|
||||
*=======
|
||||
* Calculates the optimal (in the Chebyshev/minimax sense)
|
||||
* FIR filter impulse response given a set of band edges,
|
||||
* the desired reponse on those bands, and the weight given to
|
||||
* the error in those bands.
|
||||
*
|
||||
* INPUT:
|
||||
* ------
|
||||
* int numtaps - Number of filter coefficients
|
||||
* int numband - Number of bands in filter specification
|
||||
* double bands[] - User-specified band edges [2 * numband]
|
||||
* double des[] - User-specified band responses [numband]
|
||||
* double weight[] - User-specified error weights [numband]
|
||||
* int type - Type of filter
|
||||
*
|
||||
* OUTPUT:
|
||||
* -------
|
||||
* double h[] - Impulse response of final filter [numtaps]
|
||||
********************/
|
||||
|
||||
void REMEZ_CreateFilter(double h[], int numtaps, int numband, double bands[],
|
||||
const double des[], const double weight[], int type)
|
||||
{
|
||||
double *Grid, *W, *D, *E;
|
||||
int i, iter, gridsize, r, *Ext;
|
||||
double *taps, c;
|
||||
double *x, *y, *ad;
|
||||
int symmetry;
|
||||
|
||||
if (type == REMEZ_BANDPASS)
|
||||
symmetry = POSITIVE;
|
||||
else
|
||||
symmetry = NEGATIVE;
|
||||
|
||||
r = numtaps / 2; /* number of extrema */
|
||||
if ((numtaps % 2) && (symmetry == POSITIVE))
|
||||
r++;
|
||||
|
||||
/* Predict dense grid size in advance for memory allocation
|
||||
* .5 is so we round up, not truncate */
|
||||
gridsize = 0;
|
||||
for (i = 0; i < numband; i++) {
|
||||
gridsize += (int) (2 * r * GRIDDENSITY *
|
||||
(bands[2 * i + 1] - bands[2 * i]) + .5);
|
||||
}
|
||||
if (symmetry == NEGATIVE) {
|
||||
gridsize--;
|
||||
}
|
||||
|
||||
/* Dynamically allocate memory for arrays with proper sizes */
|
||||
Grid = (double *) Util_malloc(gridsize * sizeof(double));
|
||||
D = (double *) Util_malloc(gridsize * sizeof(double));
|
||||
W = (double *) Util_malloc(gridsize * sizeof(double));
|
||||
E = (double *) Util_malloc(gridsize * sizeof(double));
|
||||
Ext = (int *) Util_malloc((r + 1) * sizeof(int));
|
||||
taps = (double *) Util_malloc((r + 1) * sizeof(double));
|
||||
x = (double *) Util_malloc((r + 1) * sizeof(double));
|
||||
y = (double *) Util_malloc((r + 1) * sizeof(double));
|
||||
ad = (double *) Util_malloc((r + 1) * sizeof(double));
|
||||
|
||||
/* Create dense frequency grid */
|
||||
CreateDenseGrid(r, numtaps, numband, bands, des, weight,
|
||||
&gridsize, Grid, D, W, symmetry);
|
||||
InitialGuess(r, Ext, gridsize);
|
||||
|
||||
/* For Differentiator: (fix grid) */
|
||||
if (type == REMEZ_DIFFERENTIATOR) {
|
||||
for (i = 0; i < gridsize; i++) {
|
||||
/* D[i] = D[i] * Grid[i]; */
|
||||
if (D[i] > 0.0001)
|
||||
W[i] = W[i] / Grid[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* For odd or Negative symmetry filters, alter the
|
||||
* D[] and W[] according to Parks McClellan */
|
||||
if (symmetry == POSITIVE) {
|
||||
if (numtaps % 2 == 0) {
|
||||
for (i = 0; i < gridsize; i++) {
|
||||
c = cos(Pi * Grid[i]);
|
||||
D[i] /= c;
|
||||
W[i] *= c;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (numtaps % 2) {
|
||||
for (i = 0; i < gridsize; i++) {
|
||||
c = sin(Pi2 * Grid[i]);
|
||||
D[i] /= c;
|
||||
W[i] *= c;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < gridsize; i++) {
|
||||
c = sin(Pi * Grid[i]);
|
||||
D[i] /= c;
|
||||
W[i] *= c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform the Remez Exchange algorithm */
|
||||
for (iter = 0; iter < MAXITERATIONS; iter++) {
|
||||
CalcParms(r, Ext, Grid, D, W, ad, x, y);
|
||||
CalcError(r, ad, x, y, gridsize, Grid, D, W, E);
|
||||
Search(r, Ext, gridsize, E);
|
||||
if (isDone(r, Ext, E))
|
||||
break;
|
||||
}
|
||||
#ifndef ASAP
|
||||
if (iter == MAXITERATIONS) {
|
||||
Log_print("remez(): reached maximum iteration count. Results may be bad.");
|
||||
}
|
||||
#endif
|
||||
|
||||
CalcParms(r, Ext, Grid, D, W, ad, x, y);
|
||||
|
||||
/* Find the 'taps' of the filter for use with Frequency
|
||||
* Sampling. If odd or Negative symmetry, fix the taps
|
||||
* according to Parks McClellan */
|
||||
for (i = 0; i <= numtaps / 2; i++) {
|
||||
if (symmetry == POSITIVE) {
|
||||
if (numtaps % 2)
|
||||
c = 1;
|
||||
else
|
||||
c = cos(Pi * (double) i / numtaps);
|
||||
}
|
||||
else {
|
||||
if (numtaps % 2)
|
||||
c = sin(Pi2 * (double) i / numtaps);
|
||||
else
|
||||
c = sin(Pi * (double) i / numtaps);
|
||||
}
|
||||
taps[i] = ComputeA((double) i / numtaps, r, ad, x, y) * c;
|
||||
}
|
||||
|
||||
/* Frequency sampling design with calculated taps */
|
||||
FreqSample(numtaps, taps, h, symmetry);
|
||||
|
||||
/* Delete allocated memory */
|
||||
free(Grid);
|
||||
free(W);
|
||||
free(D);
|
||||
free(E);
|
||||
free(Ext);
|
||||
free(taps);
|
||||
free(x);
|
||||
free(y);
|
||||
free(ad);
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/**************************************************************************
|
||||
* Parks-McClellan algorithm for FIR filter design (C version)
|
||||
*-------------------------------------------------
|
||||
* Copyright (c) 1995,1998 Jake Janovetz (janovetz@uiuc.edu)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
*************************************************************************/
|
||||
#ifndef REMEZ_H_
|
||||
#define REMEZ_H_
|
||||
|
||||
#define REMEZ_BANDPASS 1
|
||||
#define REMEZ_DIFFERENTIATOR 2
|
||||
#define REMEZ_HILBERT 3
|
||||
|
||||
/* Function prototype for REMEZ_CreateFilter() - the only function that should need be
|
||||
* called from external code */
|
||||
void REMEZ_CreateFilter(double h[], int numtaps,
|
||||
int numband, double bands[], const double des[], const double weight[],
|
||||
int type);
|
||||
|
||||
#endif /* REMEZ_H_ */
|
||||
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* rtime.c - Emulate ICD R-Time 8 cartridge
|
||||
*
|
||||
* Copyright (C) 2000 Jason Duerstock
|
||||
* Copyright (C) 2000-2005 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h> /* for NULL */
|
||||
#include <string.h> /* for strcmp() */
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "atari.h"
|
||||
#include "log.h"
|
||||
#include "rtime.h"
|
||||
|
||||
int RTIME_enabled = 1;
|
||||
|
||||
static int rtime_state = 0;
|
||||
/* 0 = waiting for register # */
|
||||
/* 1 = got register #, waiting for hi nybble */
|
||||
/* 2 = got hi nybble, waiting for lo nybble */
|
||||
static int rtime_tmp = 0;
|
||||
static int rtime_tmp2 = 0;
|
||||
|
||||
static UBYTE regset[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
|
||||
int RTIME_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
for (i = j = 1; i < *argc; i++) {
|
||||
if (strcmp(argv[i], "-rtime") == 0)
|
||||
RTIME_enabled = TRUE;
|
||||
else if (strcmp(argv[i], "-nortime") == 0)
|
||||
RTIME_enabled = FALSE;
|
||||
else {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
Log_print("\t-rtime Enable R-Time 8 emulation");
|
||||
Log_print("\t-nortime Disable R-Time 8 emulation");
|
||||
}
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
}
|
||||
*argc = j;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if defined(WIN32) || (defined(HAVE_TIME) && defined(HAVE_LOCALTIME))
|
||||
|
||||
static int hex2bcd(int h)
|
||||
{
|
||||
return ((h / 10) << 4) | (h % 10);
|
||||
}
|
||||
|
||||
static int gettime(int p)
|
||||
{
|
||||
#ifdef WIN32
|
||||
SYSTEMTIME st;
|
||||
GetLocalTime(&st);
|
||||
switch (p) {
|
||||
case 0:
|
||||
return hex2bcd(st.wSecond);
|
||||
case 1:
|
||||
return hex2bcd(st.wMinute);
|
||||
case 2:
|
||||
return hex2bcd(st.wHour);
|
||||
case 3:
|
||||
return hex2bcd(st.wDay);
|
||||
case 4:
|
||||
return hex2bcd(st.wMonth);
|
||||
case 5:
|
||||
return hex2bcd(st.wYear % 100);
|
||||
case 6:
|
||||
return hex2bcd(((st.wDayOfWeek + 2) % 7) + 1);
|
||||
}
|
||||
#else /* WIN32 */
|
||||
time_t tt;
|
||||
struct tm *lt;
|
||||
|
||||
tt = time(NULL);
|
||||
lt = localtime(&tt);
|
||||
|
||||
switch (p) {
|
||||
case 0:
|
||||
return hex2bcd(lt->tm_sec);
|
||||
case 1:
|
||||
return hex2bcd(lt->tm_min);
|
||||
case 2:
|
||||
return hex2bcd(lt->tm_hour);
|
||||
case 3:
|
||||
return hex2bcd(lt->tm_mday);
|
||||
case 4:
|
||||
return hex2bcd(lt->tm_mon + 1);
|
||||
case 5:
|
||||
return hex2bcd(lt->tm_year % 100);
|
||||
case 6:
|
||||
return hex2bcd(((lt->tm_wday + 2) % 7) + 1);
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define HAVE_GETTIME
|
||||
|
||||
#endif /* defined(WIN32) || (defined(HAVE_TIME) && defined(HAVE_LOCALTIME)) */
|
||||
|
||||
UBYTE RTIME_GetByte(void)
|
||||
{
|
||||
switch (rtime_state) {
|
||||
case 0:
|
||||
/* Log_print("pretending rtime not busy, returning 0"); */
|
||||
return 0;
|
||||
case 1:
|
||||
rtime_state = 2;
|
||||
return (
|
||||
#ifdef HAVE_GETTIME
|
||||
rtime_tmp <= 6 ?
|
||||
gettime(rtime_tmp) :
|
||||
#endif
|
||||
regset[rtime_tmp]) >> 4;
|
||||
case 2:
|
||||
rtime_state = 0;
|
||||
return (
|
||||
#ifdef HAVE_GETTIME
|
||||
rtime_tmp <= 6 ?
|
||||
gettime(rtime_tmp) :
|
||||
#endif
|
||||
regset[rtime_tmp]) & 0x0f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RTIME_PutByte(UBYTE byte)
|
||||
{
|
||||
switch (rtime_state) {
|
||||
case 0:
|
||||
rtime_tmp = byte & 0x0f;
|
||||
rtime_state = 1;
|
||||
break;
|
||||
case 1:
|
||||
rtime_tmp2 = byte << 4;
|
||||
rtime_state = 2;
|
||||
break;
|
||||
case 2:
|
||||
regset[rtime_tmp] = rtime_tmp2 | (byte & 0x0f);
|
||||
rtime_state = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#ifndef RTIME_H_
|
||||
#define RTIME_H_
|
||||
/* Emulate ICD R-Time 8 cartridge
|
||||
Copyright 2000 Jason Duerstock <jason@cluephone.com>
|
||||
|
||||
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 Street, Fifth Floor, Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "atari.h"
|
||||
|
||||
extern int RTIME_enabled;
|
||||
|
||||
int RTIME_Initialise(int *argc, char *argv[]);
|
||||
UBYTE RTIME_GetByte(void);
|
||||
void RTIME_PutByte(UBYTE byte);
|
||||
#endif /* RTIME_H_ */
|
||||
@@ -1,587 +0,0 @@
|
||||
/*
|
||||
* screen.c - Atari screen handling
|
||||
*
|
||||
* Copyright (c) 2001 Robert Golias and Piotr Fusik
|
||||
* Copyright (C) 2001-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HAVE_LIBPNG
|
||||
#include <png.h>
|
||||
#endif
|
||||
|
||||
#include "antic.h"
|
||||
#include "atari.h"
|
||||
#include "colours.h"
|
||||
#include "log.h"
|
||||
#include "screen.h"
|
||||
#include "sio.h"
|
||||
#include "util.h"
|
||||
|
||||
#define ATARI_VISIBLE_WIDTH 336
|
||||
#define ATARI_LEFT_MARGIN 24
|
||||
|
||||
ULONG *Screen_atari = NULL;
|
||||
#ifdef DIRTYRECT
|
||||
UBYTE *Screen_dirty = NULL;
|
||||
#endif
|
||||
#ifdef BITPL_SCR
|
||||
ULONG *Screen_atari_b = NULL;
|
||||
ULONG *Screen_atari1 = NULL;
|
||||
ULONG *Screen_atari2 = NULL;
|
||||
#endif
|
||||
|
||||
/* The area that can been seen is Screen_visible_x1 <= x < Screen_visible_x2,
|
||||
Screen_visible_y1 <= y < Screen_visible_y2.
|
||||
Full Atari screen is 336x240. Screen_WIDTH is 384 only because
|
||||
the code in antic.c sometimes draws more than 336 bytes in a line.
|
||||
Currently Screen_visible variables are used only to place
|
||||
disk led and snailmeter in the corners of the screen.
|
||||
*/
|
||||
int Screen_visible_x1 = 24; /* 0 .. Screen_WIDTH */
|
||||
int Screen_visible_y1 = 0; /* 0 .. Screen_HEIGHT */
|
||||
int Screen_visible_x2 = 360; /* 0 .. Screen_WIDTH */
|
||||
int Screen_visible_y2 = Screen_HEIGHT; /* 0 .. Screen_HEIGHT */
|
||||
|
||||
int Screen_show_atari_speed = FALSE;
|
||||
int Screen_show_disk_led = TRUE;
|
||||
int Screen_show_sector_counter = FALSE;
|
||||
|
||||
#ifdef HAVE_LIBPNG
|
||||
#define DEFAULT_SCREENSHOT_FILENAME_FORMAT "atari%03d.png"
|
||||
#else
|
||||
#define DEFAULT_SCREENSHOT_FILENAME_FORMAT "atari%03d.pcx"
|
||||
#endif
|
||||
|
||||
static char screenshot_filename_format[FILENAME_MAX] = DEFAULT_SCREENSHOT_FILENAME_FORMAT;
|
||||
static int screenshot_no_max = 1000;
|
||||
|
||||
/* converts "foo%bar##.pcx" to "foo%%bar%02d.pcx" */
|
||||
static void Screen_SetScreenshotFilenamePattern(const char *p)
|
||||
{
|
||||
char *f = screenshot_filename_format;
|
||||
char no_width = '0';
|
||||
screenshot_no_max = 1;
|
||||
/* 9 because sprintf'ed "no" can be 9 digits */
|
||||
while (f < screenshot_filename_format + FILENAME_MAX - 9) {
|
||||
/* replace a sequence of hashes with e.g. "%05d" */
|
||||
if (*p == '#') {
|
||||
if (no_width > '0') /* already seen a sequence of hashes */
|
||||
break; /* invalid */
|
||||
/* count hashes */
|
||||
do {
|
||||
screenshot_no_max *= 10;
|
||||
p++;
|
||||
no_width++;
|
||||
/* now no_width is the number of hashes seen so far
|
||||
and p points after the counted hashes */
|
||||
} while (no_width < '9' && *p == '#'); /* no more than 9 hashes */
|
||||
*f++ = '%';
|
||||
*f++ = '0';
|
||||
*f++ = no_width;
|
||||
*f++ = 'd';
|
||||
continue;
|
||||
}
|
||||
if (*p == '%')
|
||||
*f++ = '%'; /* double the percents */
|
||||
*f++ = *p;
|
||||
if (*p == '\0')
|
||||
return; /* ok */
|
||||
p++;
|
||||
}
|
||||
Log_print("Invalid filename pattern for screenshots, using default.");
|
||||
strcpy(screenshot_filename_format, DEFAULT_SCREENSHOT_FILENAME_FORMAT);
|
||||
screenshot_no_max = 1000;
|
||||
}
|
||||
|
||||
int Screen_Initialise(int *argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int help_only = FALSE;
|
||||
|
||||
for (i = j = 1; i < *argc; i++) {
|
||||
int i_a = (i + 1 < *argc); /* is argument available? */
|
||||
int a_m = FALSE; /* error, argument missing! */
|
||||
|
||||
if (strcmp(argv[i], "-screenshots") == 0) {
|
||||
if (i_a)
|
||||
Screen_SetScreenshotFilenamePattern(argv[++i]);
|
||||
else a_m = TRUE;
|
||||
}
|
||||
if (strcmp(argv[i], "-showspeed") == 0) {
|
||||
Screen_show_atari_speed = TRUE;
|
||||
}
|
||||
else {
|
||||
if (strcmp(argv[i], "-help") == 0) {
|
||||
help_only = TRUE;
|
||||
Log_print("\t-screenshots <p> Set filename pattern for screenshots");
|
||||
Log_print("\t-showspeed Show percentage of actual speed");
|
||||
}
|
||||
argv[j++] = argv[i];
|
||||
}
|
||||
|
||||
if (a_m) {
|
||||
Log_print("Missing argument for '%s'", argv[i]);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
*argc = j;
|
||||
|
||||
/* don't bother mallocing Screen_atari with just "-help" */
|
||||
if (help_only)
|
||||
return TRUE;
|
||||
|
||||
if (Screen_atari == NULL) { /* platform-specific code can initialize it in theory */
|
||||
Screen_atari = (ULONG *) Util_malloc(Screen_HEIGHT * Screen_WIDTH);
|
||||
#ifdef DIRTYRECT
|
||||
Screen_dirty = (UBYTE *) Util_malloc(Screen_HEIGHT * Screen_WIDTH / 8);
|
||||
Screen_EntireDirty();
|
||||
#endif
|
||||
#ifdef BITPL_SCR
|
||||
Screen_atari_b = (ULONG *) Util_malloc(Screen_HEIGHT * Screen_WIDTH);
|
||||
Screen_atari1 = Screen_atari;
|
||||
Screen_atari2 = Screen_atari_b;
|
||||
#endif
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define SMALLFONT_WIDTH 5
|
||||
#define SMALLFONT_HEIGHT 7
|
||||
#define SMALLFONT_PERCENT 10
|
||||
#define SMALLFONT_____ 0x00
|
||||
#define SMALLFONT___X_ 0x02
|
||||
#define SMALLFONT__X__ 0x04
|
||||
#define SMALLFONT__XX_ 0x06
|
||||
#define SMALLFONT_X___ 0x08
|
||||
#define SMALLFONT_X_X_ 0x0A
|
||||
#define SMALLFONT_XX__ 0x0C
|
||||
#define SMALLFONT_XXX_ 0x0E
|
||||
|
||||
static void SmallFont_DrawChar(UBYTE *screen, int ch, UBYTE color1, UBYTE color2)
|
||||
{
|
||||
static const UBYTE font[12][SMALLFONT_HEIGHT] = {
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_____
|
||||
},
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_XX__,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_____
|
||||
},
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT_XX__,
|
||||
SMALLFONT___X_,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_X___,
|
||||
SMALLFONT_XXX_,
|
||||
SMALLFONT_____
|
||||
},
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT_XX__,
|
||||
SMALLFONT___X_,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT___X_,
|
||||
SMALLFONT_XX__,
|
||||
SMALLFONT_____
|
||||
},
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT___X_,
|
||||
SMALLFONT__XX_,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT_XXX_,
|
||||
SMALLFONT___X_,
|
||||
SMALLFONT_____
|
||||
},
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT_XXX_,
|
||||
SMALLFONT_X___,
|
||||
SMALLFONT_XXX_,
|
||||
SMALLFONT___X_,
|
||||
SMALLFONT_XX__,
|
||||
SMALLFONT_____
|
||||
},
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_X___,
|
||||
SMALLFONT_XX__,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_____
|
||||
},
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT_XXX_,
|
||||
SMALLFONT___X_,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_____
|
||||
},
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_____
|
||||
},
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT__XX_,
|
||||
SMALLFONT___X_,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_____
|
||||
},
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT___X_,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_X___,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT_____
|
||||
},
|
||||
{
|
||||
SMALLFONT_____,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT_X___,
|
||||
SMALLFONT_X_X_,
|
||||
SMALLFONT__X__,
|
||||
SMALLFONT_____
|
||||
}
|
||||
};
|
||||
int y;
|
||||
for (y = 0; y < SMALLFONT_HEIGHT; y++) {
|
||||
int src;
|
||||
int mask;
|
||||
src = font[ch][y];
|
||||
for (mask = 1 << (SMALLFONT_WIDTH - 1); mask != 0; mask >>= 1) {
|
||||
ANTIC_VideoPutByte(screen, (UBYTE) ((src & mask) != 0 ? color1 : color2));
|
||||
screen++;
|
||||
}
|
||||
screen += Screen_WIDTH - SMALLFONT_WIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
static void SmallFont_DrawInt(UBYTE *screen, int n, UBYTE color1, UBYTE color2)
|
||||
{
|
||||
do {
|
||||
SmallFont_DrawChar(screen, n % 10, color1, color2);
|
||||
screen -= SMALLFONT_WIDTH;
|
||||
n /= 10;
|
||||
} while (n > 0);
|
||||
}
|
||||
|
||||
void Screen_DrawAtariSpeed(double cur_time)
|
||||
{
|
||||
if (Screen_show_atari_speed) {
|
||||
static int percent_display = 100;
|
||||
static int last_updated = 0;
|
||||
static double last_time = 0;
|
||||
if ((cur_time - last_time) >= 0.5) {
|
||||
percent_display = (int) (100 * (Atari800_nframes - last_updated) / (cur_time - last_time) / (Atari800_tv_mode == Atari800_TV_PAL ? 50 : 60));
|
||||
last_updated = Atari800_nframes;
|
||||
last_time = cur_time;
|
||||
}
|
||||
/* if (percent_display < 99 || percent_display > 101) */
|
||||
{
|
||||
/* space for 5 digits - up to 99999% Atari speed */
|
||||
UBYTE *screen = (UBYTE *) Screen_atari + Screen_visible_x1 + 5 * SMALLFONT_WIDTH
|
||||
+ (Screen_visible_y2 - SMALLFONT_HEIGHT) * Screen_WIDTH;
|
||||
SmallFont_DrawChar(screen, SMALLFONT_PERCENT, 0x0c, 0x00);
|
||||
SmallFont_DrawInt(screen - SMALLFONT_WIDTH, percent_display, 0x0c, 0x00);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_DrawDiskLED(void)
|
||||
{
|
||||
if (SIO_last_op_time > 0) {
|
||||
UBYTE *screen;
|
||||
if (SIO_last_drive != 0x60)
|
||||
SIO_last_op_time--;
|
||||
screen = (UBYTE *) Screen_atari + Screen_visible_x2 - SMALLFONT_WIDTH
|
||||
+ (Screen_visible_y2 - SMALLFONT_HEIGHT) * Screen_WIDTH;
|
||||
if (SIO_last_drive == 0x60 || SIO_last_drive == 0x61) {
|
||||
if (Screen_show_disk_led)
|
||||
SmallFont_DrawChar(screen, 11, 0x00, (UBYTE) (SIO_last_op == SIO_LAST_READ ? 0xac : 0x2b));
|
||||
}
|
||||
else {
|
||||
if (Screen_show_disk_led)
|
||||
SmallFont_DrawChar(screen, SIO_last_drive, 0x00, (UBYTE) (SIO_last_op == SIO_LAST_READ ? 0xac : 0x2b));
|
||||
|
||||
if (Screen_show_sector_counter)
|
||||
SmallFont_DrawInt(screen - SMALLFONT_WIDTH, SIO_last_sector, 0x00, 0x88);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Screen_FindScreenshotFilename(char *buffer)
|
||||
{
|
||||
static int no = -1;
|
||||
static int overwrite = FALSE;
|
||||
|
||||
for (;;) {
|
||||
if (++no >= screenshot_no_max) {
|
||||
no = 0;
|
||||
overwrite = TRUE;
|
||||
}
|
||||
sprintf(buffer, screenshot_filename_format, no);
|
||||
if (overwrite)
|
||||
break;
|
||||
if (!Util_fileexists(buffer))
|
||||
break; /* file does not exist - we can create it */
|
||||
}
|
||||
}
|
||||
|
||||
static void fputw(int x, FILE *fp)
|
||||
{
|
||||
fputc(x & 0xff, fp);
|
||||
fputc(x >> 8, fp);
|
||||
}
|
||||
|
||||
static void Screen_SavePCX(FILE *fp, UBYTE *ptr1, UBYTE *ptr2)
|
||||
{
|
||||
int i;
|
||||
int x;
|
||||
int y;
|
||||
UBYTE plane = 16; /* 16 = Red, 8 = Green, 0 = Blue */
|
||||
UBYTE last;
|
||||
UBYTE count;
|
||||
|
||||
fputc(0xa, fp); /* pcx signature */
|
||||
fputc(0x5, fp); /* version 5 */
|
||||
fputc(0x1, fp); /* RLE encoding */
|
||||
fputc(0x8, fp); /* bits per pixel */
|
||||
fputw(0, fp); /* XMin */
|
||||
fputw(0, fp); /* YMin */
|
||||
fputw(ATARI_VISIBLE_WIDTH - 1, fp); /* XMax */
|
||||
fputw(Screen_HEIGHT - 1, fp); /* YMax */
|
||||
fputw(0, fp); /* HRes */
|
||||
fputw(0, fp); /* VRes */
|
||||
for (i = 0; i < 48; i++)
|
||||
fputc(0, fp); /* EGA color palette */
|
||||
fputc(0, fp); /* reserved */
|
||||
fputc(ptr2 != NULL ? 3 : 1, fp); /* number of bit planes */
|
||||
fputw(ATARI_VISIBLE_WIDTH, fp); /* number of bytes per scan line per color plane */
|
||||
fputw(1, fp); /* palette info */
|
||||
fputw(ATARI_VISIBLE_WIDTH, fp); /* screen resolution */
|
||||
fputw(Screen_HEIGHT, fp);
|
||||
for (i = 0; i < 54; i++)
|
||||
fputc(0, fp); /* unused */
|
||||
|
||||
for (y = 0; y < Screen_HEIGHT; ) {
|
||||
x = 0;
|
||||
do {
|
||||
last = ptr2 != NULL ? (((Colours_table[*ptr1] >> plane) & 0xff) + ((Colours_table[*ptr2] >> plane) & 0xff)) >> 1 : *ptr1;
|
||||
count = 0xc0;
|
||||
do {
|
||||
ptr1++;
|
||||
if (ptr2 != NULL)
|
||||
ptr2++;
|
||||
count++;
|
||||
x++;
|
||||
} while (last == (ptr2 != NULL ? (((Colours_table[*ptr1] >> plane) & 0xff) + ((Colours_table[*ptr2] >> plane) & 0xff)) >> 1 : *ptr1)
|
||||
&& count < 0xff && x < ATARI_VISIBLE_WIDTH);
|
||||
if (count > 0xc1 || last >= 0xc0)
|
||||
fputc(count, fp);
|
||||
fputc(last, fp);
|
||||
} while (x < ATARI_VISIBLE_WIDTH);
|
||||
|
||||
if (ptr2 != NULL && plane) {
|
||||
ptr1 -= ATARI_VISIBLE_WIDTH;
|
||||
ptr2 -= ATARI_VISIBLE_WIDTH;
|
||||
plane -= 8;
|
||||
}
|
||||
else {
|
||||
ptr1 += Screen_WIDTH - ATARI_VISIBLE_WIDTH;
|
||||
if (ptr2 != NULL) {
|
||||
ptr2 += Screen_WIDTH - ATARI_VISIBLE_WIDTH;
|
||||
plane = 16;
|
||||
}
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr2 == NULL) {
|
||||
/* write palette */
|
||||
fputc(0xc, fp);
|
||||
for (i = 0; i < 256; i++) {
|
||||
fputc(Colours_GetR(i), fp);
|
||||
fputc(Colours_GetG(i), fp);
|
||||
fputc(Colours_GetB(i), fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int striendswith(const char *s1, const char *s2)
|
||||
{
|
||||
int pos;
|
||||
pos = strlen(s1) - strlen(s2);
|
||||
if (pos < 0)
|
||||
return 0;
|
||||
return Util_stricmp(s1 + pos, s2) == 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBPNG
|
||||
static void Screen_SavePNG(FILE *fp, UBYTE *ptr1, UBYTE *ptr2)
|
||||
{
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_bytep rows[Screen_HEIGHT];
|
||||
|
||||
png_ptr = png_create_write_struct(
|
||||
PNG_LIBPNG_VER_STRING,
|
||||
NULL, NULL, NULL
|
||||
);
|
||||
if (png_ptr == NULL)
|
||||
return;
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == NULL)
|
||||
return;
|
||||
png_init_io(png_ptr, fp);
|
||||
png_set_IHDR(
|
||||
png_ptr, info_ptr, ATARI_VISIBLE_WIDTH, Screen_HEIGHT,
|
||||
8, ptr2 == NULL ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT
|
||||
);
|
||||
if (ptr2 == NULL) {
|
||||
int i;
|
||||
png_color palette[256];
|
||||
for (i = 0; i < 256; i++) {
|
||||
palette[i].red = Colours_GetR(i);
|
||||
palette[i].green = Colours_GetG(i);
|
||||
palette[i].blue = Colours_GetB(i);
|
||||
}
|
||||
png_set_PLTE(png_ptr, info_ptr, palette, 256);
|
||||
for (i = 0; i < Screen_HEIGHT; i++) {
|
||||
rows[i] = ptr1;
|
||||
ptr1 += Screen_WIDTH;
|
||||
}
|
||||
}
|
||||
else {
|
||||
png_bytep ptr3;
|
||||
int x;
|
||||
int y;
|
||||
ptr3 = (png_bytep) Util_malloc(3 * ATARI_VISIBLE_WIDTH * Screen_HEIGHT);
|
||||
for (y = 0; y < Screen_HEIGHT; y++) {
|
||||
rows[y] = ptr3;
|
||||
for (x = 0; x < ATARI_VISIBLE_WIDTH; x++) {
|
||||
*ptr3++ = (png_byte) ((Colours_GetR(*ptr1) + Colours_GetR(*ptr2)) >> 1);
|
||||
*ptr3++ = (png_byte) ((Colours_GetG(*ptr1) + Colours_GetG(*ptr2)) >> 1);
|
||||
*ptr3++ = (png_byte) ((Colours_GetB(*ptr1) + Colours_GetB(*ptr2)) >> 1);
|
||||
ptr1++;
|
||||
ptr2++;
|
||||
}
|
||||
ptr1 += Screen_WIDTH - ATARI_VISIBLE_WIDTH;
|
||||
ptr2 += Screen_WIDTH - ATARI_VISIBLE_WIDTH;
|
||||
}
|
||||
}
|
||||
png_set_rows(png_ptr, info_ptr, rows);
|
||||
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
if (ptr2 != NULL)
|
||||
free(rows[0]);
|
||||
}
|
||||
#endif /* HAVE_LIBPNG */
|
||||
|
||||
int Screen_SaveScreenshot(const char *filename, int interlaced)
|
||||
{
|
||||
int is_png;
|
||||
FILE *fp;
|
||||
ULONG *main_screen_atari;
|
||||
UBYTE *ptr1;
|
||||
UBYTE *ptr2;
|
||||
if (striendswith(filename, ".pcx"))
|
||||
is_png = 0;
|
||||
#ifdef HAVE_LIBPNG
|
||||
else if (striendswith(filename, ".png"))
|
||||
is_png = 1;
|
||||
#endif
|
||||
else
|
||||
return FALSE;
|
||||
fp = fopen(filename, "wb");
|
||||
if (fp == NULL)
|
||||
return FALSE;
|
||||
main_screen_atari = Screen_atari;
|
||||
ptr1 = (UBYTE *) Screen_atari + ATARI_LEFT_MARGIN;
|
||||
if (interlaced) {
|
||||
Screen_atari = (ULONG *) Util_malloc(Screen_WIDTH * Screen_HEIGHT);
|
||||
ptr2 = (UBYTE *) Screen_atari + ATARI_LEFT_MARGIN;
|
||||
ANTIC_Frame(TRUE); /* draw on Screen_atari */
|
||||
}
|
||||
else {
|
||||
ptr2 = NULL;
|
||||
}
|
||||
#ifdef HAVE_LIBPNG
|
||||
if (is_png)
|
||||
Screen_SavePNG(fp, ptr1, ptr2);
|
||||
else
|
||||
#endif
|
||||
Screen_SavePCX(fp, ptr1, ptr2);
|
||||
fclose(fp);
|
||||
if (interlaced) {
|
||||
free(Screen_atari);
|
||||
Screen_atari = main_screen_atari;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void Screen_SaveNextScreenshot(int interlaced)
|
||||
{
|
||||
char filename[FILENAME_MAX];
|
||||
Screen_FindScreenshotFilename(filename);
|
||||
Screen_SaveScreenshot(filename, interlaced);
|
||||
}
|
||||
|
||||
void Screen_EntireDirty(void)
|
||||
{
|
||||
#ifdef DIRTYRECT
|
||||
memset(Screen_dirty, 1, Screen_WIDTH * Screen_HEIGHT / 8);
|
||||
#endif /* DIRTYRECT */
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#ifndef SCREEN_H_
|
||||
#define SCREEN_H_
|
||||
|
||||
#include "atari.h" /* UBYTE */
|
||||
|
||||
#ifdef DIRTYRECT
|
||||
#ifndef CLIENTUPDATE
|
||||
extern UBYTE *Screen_dirty;
|
||||
#endif /* CLIENTUPDATE */
|
||||
#endif /* DIRTYRECT */
|
||||
|
||||
extern ULONG *Screen_atari;
|
||||
|
||||
/* Dimensions of Screen_atari.
|
||||
Screen_atari is Screen_WIDTH * Screen_HEIGHT bytes.
|
||||
Each byte is an Atari color code - use Colours_Get[RGB] functions
|
||||
to get actual RGB codes.
|
||||
You should never display anything outside the middle 336 columns. */
|
||||
#define Screen_WIDTH 384
|
||||
#define Screen_HEIGHT 240
|
||||
|
||||
#ifdef BITPL_SCR
|
||||
extern ULONG *Screen_atari_b;
|
||||
extern ULONG *Screen_atari1;
|
||||
extern ULONG *Screen_atari2;
|
||||
#endif
|
||||
|
||||
extern int Screen_visible_x1;
|
||||
extern int Screen_visible_y1;
|
||||
extern int Screen_visible_x2;
|
||||
extern int Screen_visible_y2;
|
||||
|
||||
extern int Screen_show_atari_speed;
|
||||
extern int Screen_show_disk_led;
|
||||
extern int Screen_show_sector_counter;
|
||||
|
||||
int Screen_Initialise(int *argc, char *argv[]);
|
||||
void Screen_DrawAtariSpeed(double);
|
||||
void Screen_DrawDiskLED(void);
|
||||
void Screen_FindScreenshotFilename(char *buffer);
|
||||
int Screen_SaveScreenshot(const char *filename, int interlaced);
|
||||
void Screen_SaveNextScreenshot(int interlaced);
|
||||
void Screen_EntireDirty(void);
|
||||
|
||||
#endif /* SCREEN_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,63 +0,0 @@
|
||||
#ifndef SIO_H_
|
||||
#define SIO_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h> /* FILENAME_MAX */
|
||||
|
||||
#include "atari.h"
|
||||
|
||||
#define SIO_MAX_DRIVES 8
|
||||
|
||||
typedef enum SIO_tagUnitStatus {
|
||||
SIO_OFF,
|
||||
SIO_NO_DISK,
|
||||
SIO_READ_ONLY,
|
||||
SIO_READ_WRITE
|
||||
} SIO_UnitStatus;
|
||||
|
||||
extern char SIO_status[256];
|
||||
extern SIO_UnitStatus SIO_drive_status[SIO_MAX_DRIVES];
|
||||
extern char SIO_filename[SIO_MAX_DRIVES][FILENAME_MAX];
|
||||
|
||||
#define SIO_LAST_READ 0
|
||||
#define SIO_LAST_WRITE 1
|
||||
extern int SIO_last_op;
|
||||
extern int SIO_last_op_time;
|
||||
extern int SIO_last_drive; /* 1 .. 8 */
|
||||
extern int SIO_last_sector;
|
||||
|
||||
int SIO_Mount(int diskno, const char *filename, int b_open_readonly);
|
||||
void SIO_Dismount(int diskno);
|
||||
void SIO_DisableDrive(int diskno);
|
||||
int SIO_RotateDisks(void);
|
||||
void SIO_Handler(void);
|
||||
|
||||
UBYTE SIO_ChkSum(const UBYTE *buffer, int length);
|
||||
void SIO_TapeMotor(int onoff);
|
||||
void SIO_SwitchCommandFrame(int onoff);
|
||||
void SIO_PutByte(int byte);
|
||||
int SIO_GetByte(void);
|
||||
int SIO_Initialise(int *argc, char *argv[]);
|
||||
void SIO_Exit(void);
|
||||
|
||||
/* Some defines about the serial I/O timing. Currently fixed! */
|
||||
#define SIO_XMTDONE_INTERVAL 15
|
||||
#define SIO_SERIN_INTERVAL 8
|
||||
#define SIO_SEROUT_INTERVAL 8
|
||||
#define SIO_ACK_INTERVAL 36
|
||||
|
||||
/* These functions are also used by the 1450XLD Parallel disk device */
|
||||
extern int SIO_format_sectorcount[SIO_MAX_DRIVES];
|
||||
extern int SIO_format_sectorsize[SIO_MAX_DRIVES];
|
||||
int SIO_ReadStatusBlock(int unit, UBYTE *buffer);
|
||||
int SIO_FormatDisk(int unit, UBYTE *buffer, int sectsize, int sectcount);
|
||||
void SIO_SizeOfSector(UBYTE unit, int sector, int *sz, ULONG *ofs);
|
||||
int SIO_ReadSector(int unit, int sector, UBYTE *buffer);
|
||||
int SIO_DriveStatus(int unit, UBYTE *buffer);
|
||||
int SIO_WriteStatusBlock(int unit, const UBYTE *buffer);
|
||||
int SIO_WriteSector(int unit, int sector, const UBYTE *buffer);
|
||||
void SIO_StateSave(void);
|
||||
void SIO_StateRead(void);
|
||||
|
||||
#endif /* SIO_H_ */
|
||||
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
* sndsave.c - reading and writing sound to files
|
||||
*
|
||||
* Copyright (C) 1995-1998 David Firth
|
||||
* Copyright (C) 1998-2005 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "pokeysnd.h"
|
||||
#include "sndsave.h"
|
||||
|
||||
/* sndoutput is just the file pointer for the current sound file */
|
||||
static FILE *sndoutput = NULL;
|
||||
|
||||
static ULONG byteswritten;
|
||||
|
||||
/* write 32-bit word as little endian */
|
||||
static void write32(long x)
|
||||
{
|
||||
fputc(x & 0xff, sndoutput);
|
||||
fputc((x >> 8) & 0xff, sndoutput);
|
||||
fputc((x >> 16) & 0xff, sndoutput);
|
||||
fputc((x >> 24) & 0xff, sndoutput);
|
||||
}
|
||||
|
||||
/* SndSave_IsSoundFileOpen simply returns true if the sound file is currently open and able to receive writes
|
||||
RETURNS: TRUE is file is open, FALSE if it is not */
|
||||
int SndSave_IsSoundFileOpen(void)
|
||||
{
|
||||
return sndoutput != NULL;
|
||||
}
|
||||
|
||||
|
||||
/* SndSave_CloseSoundFile should be called when the program is exiting, or when all data required has been
|
||||
written to the file. SndSave_CloseSoundFile will also be called automatically when a call is made to
|
||||
SndSave_OpenSoundFile, or an error is made in SndSave_WriteToSoundFile. Note that CloseSoundFile has to back track
|
||||
to the header written out in SndSave_OpenSoundFile and update it with the length of samples written
|
||||
|
||||
RETURNS: TRUE if file closed with no problems, FALSE if failure during close */
|
||||
|
||||
int SndSave_CloseSoundFile(void)
|
||||
{
|
||||
int bSuccess = TRUE;
|
||||
char aligned = 0;
|
||||
|
||||
if (sndoutput != NULL) {
|
||||
/* A RIFF file's chunks must be word-aligned. So let's align. */
|
||||
if (byteswritten & 1) {
|
||||
if (putc(0, sndoutput) == EOF)
|
||||
bSuccess = FALSE;
|
||||
else
|
||||
aligned = 1;
|
||||
}
|
||||
|
||||
if (bSuccess) {
|
||||
/* Sound file is finished, so modify header and close it. */
|
||||
if (fseek(sndoutput, 4, SEEK_SET) != 0) /* Seek past RIFF */
|
||||
bSuccess = FALSE;
|
||||
else {
|
||||
/* RIFF header's size field must equal the size of all chunks
|
||||
* with alignment, so the alignment byte is added.
|
||||
*/
|
||||
write32(byteswritten + 36 + aligned);
|
||||
if (fseek(sndoutput, 40, SEEK_SET) != 0)
|
||||
bSuccess = FALSE;
|
||||
else {
|
||||
/* But in the "data" chunk size field, the alignment byte
|
||||
* should be ignored. */
|
||||
write32(byteswritten);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(sndoutput);
|
||||
sndoutput = NULL;
|
||||
}
|
||||
|
||||
return bSuccess;
|
||||
}
|
||||
|
||||
|
||||
/* SndSave_OpenSoundFile will start a new sound file and write out the header. If an existing sound file is
|
||||
already open it will be closed first, and the new file opened in it's place
|
||||
|
||||
RETURNS: TRUE if file opened with no problems, FALSE if failure during open */
|
||||
|
||||
int SndSave_OpenSoundFile(const char *szFileName)
|
||||
{
|
||||
SndSave_CloseSoundFile();
|
||||
|
||||
sndoutput = fopen(szFileName, "wb");
|
||||
|
||||
if (sndoutput == NULL)
|
||||
return FALSE;
|
||||
/*
|
||||
The RIFF header:
|
||||
|
||||
Offset Length Contents
|
||||
0 4 bytes 'RIFF'
|
||||
4 4 bytes <file length - 8>
|
||||
8 4 bytes 'WAVE'
|
||||
|
||||
The fmt chunk:
|
||||
|
||||
12 4 bytes 'fmt '
|
||||
16 4 bytes 0x00000010 // Length of the fmt data (16 bytes)
|
||||
20 2 bytes 0x0001 // Format tag: 1 = PCM
|
||||
22 2 bytes <channels> // Channels: 1 = mono, 2 = stereo
|
||||
24 4 bytes <sample rate> // Samples per second: e.g., 44100
|
||||
28 4 bytes <bytes/second> // sample rate * block align
|
||||
32 2 bytes <block align> // channels * bits/sample / 8
|
||||
34 2 bytes <bits/sample> // 8 or 16
|
||||
|
||||
The data chunk:
|
||||
|
||||
36 4 bytes 'data'
|
||||
40 4 bytes <length of the data block>
|
||||
44 bytes <sample data>
|
||||
|
||||
All chunks must be word-aligned.
|
||||
|
||||
Good description of WAVE format: http://www.sonicspot.com/guide/wavefiles.html
|
||||
*/
|
||||
|
||||
if (fwrite("RIFF\0\0\0\0WAVEfmt \x10\0\0\0\1\0", 1, 22, sndoutput) != 22) {
|
||||
fclose(sndoutput);
|
||||
sndoutput = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
fputc(POKEYSND_num_pokeys, sndoutput);
|
||||
fputc(0, sndoutput);
|
||||
write32(POKEYSND_playback_freq);
|
||||
|
||||
|
||||
write32(POKEYSND_playback_freq * (POKEYSND_snd_flags & POKEYSND_BIT16 ? POKEYSND_num_pokeys << 1 : POKEYSND_num_pokeys));
|
||||
|
||||
fputc(POKEYSND_snd_flags & POKEYSND_BIT16 ? POKEYSND_num_pokeys << 1 : POKEYSND_num_pokeys, sndoutput);
|
||||
fputc(0, sndoutput);
|
||||
|
||||
fputc(POKEYSND_snd_flags & POKEYSND_BIT16? 16: 8, sndoutput);
|
||||
|
||||
if (fwrite("\0data\0\0\0\0", 1, 9, sndoutput) != 9) {
|
||||
fclose(sndoutput);
|
||||
sndoutput = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
byteswritten = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* SndSave_WriteToSoundFile will dump PCM data to the WAV file. The best way to do this for Atari800 is
|
||||
probably to call it directly after POKEYSND_Process(buffer, size) with the same values (buffer, size)
|
||||
|
||||
RETURNS: the number of bytes written to the file (should be equivalent to the input uiSize parm) */
|
||||
|
||||
int SndSave_WriteToSoundFile(const unsigned char *ucBuffer, unsigned int uiSize)
|
||||
{
|
||||
/* XXX FIXME: doesn't work with big-endian architectures */
|
||||
if (sndoutput && ucBuffer && uiSize) {
|
||||
int result;
|
||||
if (POKEYSND_snd_flags & POKEYSND_BIT16)
|
||||
uiSize <<= 1;
|
||||
result = fwrite(ucBuffer, 1, uiSize, sndoutput);
|
||||
byteswritten += result;
|
||||
if (result != uiSize) {
|
||||
SndSave_CloseSoundFile();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef SNDSAVE_H_
|
||||
#define SNDSAVE_H_
|
||||
|
||||
#include "atari.h"
|
||||
|
||||
int SndSave_IsSoundFileOpen(void);
|
||||
int SndSave_CloseSoundFile(void);
|
||||
int SndSave_OpenSoundFile(const char *szFileName);
|
||||
int SndSave_WriteToSoundFile(const UBYTE *ucBuffer, unsigned int uiSize);
|
||||
|
||||
#endif /* SNDSAVE_H_ */
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#ifndef SOUND_H_
|
||||
#define SOUND_H_
|
||||
|
||||
void Sound_Initialise(int *argc, char *argv[]);
|
||||
void Sound_Exit(void);
|
||||
void Sound_Update(void);
|
||||
void Sound_Pause(void);
|
||||
void Sound_Continue(void);
|
||||
#ifdef SUPPORTS_SOUND_REINIT
|
||||
void Sound_Reinit(void);
|
||||
#endif
|
||||
|
||||
#endif /* SOUND_H_ */
|
||||
@@ -1,662 +0,0 @@
|
||||
/*
|
||||
* statesav.c - saving the emulator's state to a file
|
||||
*
|
||||
* Copyright (C) 1995-1998 David Firth
|
||||
* Copyright (C) 1998-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h> /* getcwd */
|
||||
#endif
|
||||
#ifdef HAVE_DIRECT_H
|
||||
#include <direct.h> /* getcwd on MSVC*/
|
||||
#endif
|
||||
#ifdef HAVE_LIBZ
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
#ifdef DREAMCAST
|
||||
#include <bzlib/bzlib.h>
|
||||
#define MEMCOMPR /* compress in memory before writing */
|
||||
#include "vmu.h"
|
||||
#include "icon.h"
|
||||
#include "version.h"
|
||||
#endif
|
||||
|
||||
#include "atari.h"
|
||||
#include "statesav.h"
|
||||
#include "antic.h"
|
||||
#include "cartridge.h"
|
||||
#include "cpu.h"
|
||||
#include "gtia.h"
|
||||
#include "log.h"
|
||||
#include "pbi.h"
|
||||
#include "pia.h"
|
||||
#include "pokey.h"
|
||||
#include "sio.h"
|
||||
#include "util.h"
|
||||
#ifdef PBI_MIO
|
||||
#include "pbi_mio.h"
|
||||
#endif
|
||||
#ifdef PBI_BB
|
||||
#include "pbi_bb.h"
|
||||
#endif
|
||||
#ifdef PBI_XLD
|
||||
#include "pbi_xld.h"
|
||||
#endif
|
||||
#ifdef XEP80_EMULATION
|
||||
#include "xep80.h"
|
||||
#endif
|
||||
|
||||
#define SAVE_VERSION_NUMBER 6
|
||||
|
||||
#if defined(MEMCOMPR)
|
||||
static gzFile *mem_open(const char *name, const char *mode);
|
||||
static int mem_close(gzFile *stream);
|
||||
static size_t mem_read(void *buf, size_t len, gzFile *stream);
|
||||
static size_t mem_write(const void *buf, size_t len, gzFile *stream);
|
||||
#define GZOPEN(X, Y) mem_open(X, Y)
|
||||
#define GZCLOSE(X) mem_close(X)
|
||||
#define GZREAD(X, Y, Z) mem_read(Y, Z, X)
|
||||
#define GZWRITE(X, Y, Z) mem_write(Y, Z, X)
|
||||
#undef GZERROR
|
||||
#elif defined(HAVE_LIBZ) /* above MEMCOMPR, below HAVE_LIBZ */
|
||||
#define GZOPEN(X, Y) gzopen(X, Y)
|
||||
#define GZCLOSE(X) gzclose(X)
|
||||
#define GZREAD(X, Y, Z) gzread(X, Y, Z)
|
||||
#define GZWRITE(X, Y, Z) gzwrite(X, (const voidp) Y, Z)
|
||||
#define GZERROR(X, Y) gzerror(X, Y)
|
||||
#else
|
||||
#define GZOPEN(X, Y) fopen(X, Y)
|
||||
#define GZCLOSE(X) fclose(X)
|
||||
#define GZREAD(X, Y, Z) fread(Y, Z, 1, X)
|
||||
#define GZWRITE(X, Y, Z) fwrite(Y, Z, 1, X)
|
||||
#undef GZERROR
|
||||
#define gzFile FILE *
|
||||
#define Z_OK 0
|
||||
#endif
|
||||
|
||||
static gzFile StateFile = NULL;
|
||||
static int nFileError = Z_OK;
|
||||
|
||||
static void GetGZErrorText(void)
|
||||
{
|
||||
#ifdef GZERROR
|
||||
const char *error = GZERROR(StateFile, &nFileError);
|
||||
if (nFileError == Z_ERRNO) {
|
||||
#ifdef HAVE_STRERROR
|
||||
Log_print("The following general file I/O error occurred:");
|
||||
Log_print(strerror(errno));
|
||||
#else
|
||||
Log_print("A file I/O error occurred");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
Log_print("ZLIB returned the following error: %s", error);
|
||||
#endif /* GZERROR */
|
||||
Log_print("State file I/O failed.");
|
||||
}
|
||||
|
||||
/* Value is memory location of data, num is number of type to save */
|
||||
void StateSav_SaveUBYTE(const UBYTE *data, int num)
|
||||
{
|
||||
if (!StateFile || nFileError != Z_OK)
|
||||
return;
|
||||
|
||||
/* Assumption is that UBYTE = 8bits and the pointer passed in refers
|
||||
directly to the active bits if in a padded location. If not (unlikely)
|
||||
you'll have to redefine this to save appropriately for cross-platform
|
||||
compatibility */
|
||||
if (GZWRITE(StateFile, data, num) == 0)
|
||||
GetGZErrorText();
|
||||
}
|
||||
|
||||
/* Value is memory location of data, num is number of type to save */
|
||||
void StateSav_ReadUBYTE(UBYTE *data, int num)
|
||||
{
|
||||
if (!StateFile || nFileError != Z_OK)
|
||||
return;
|
||||
|
||||
if (GZREAD(StateFile, data, num) == 0)
|
||||
GetGZErrorText();
|
||||
}
|
||||
|
||||
/* Value is memory location of data, num is number of type to save */
|
||||
void StateSav_SaveUWORD(const UWORD *data, int num)
|
||||
{
|
||||
if (!StateFile || nFileError != Z_OK)
|
||||
return;
|
||||
|
||||
/* UWORDS are saved as 16bits, regardless of the size on this particular
|
||||
platform. Each byte of the UWORD will be pushed out individually in
|
||||
LSB order. The shifts here and in the read routines will work for both
|
||||
LSB and MSB architectures. */
|
||||
while (num > 0) {
|
||||
UWORD temp;
|
||||
UBYTE byte;
|
||||
|
||||
temp = *data++;
|
||||
byte = temp & 0xff;
|
||||
if (GZWRITE(StateFile, &byte, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
|
||||
temp >>= 8;
|
||||
byte = temp & 0xff;
|
||||
if (GZWRITE(StateFile, &byte, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
num--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Value is memory location of data, num is number of type to save */
|
||||
void StateSav_ReadUWORD(UWORD *data, int num)
|
||||
{
|
||||
if (!StateFile || nFileError != Z_OK)
|
||||
return;
|
||||
|
||||
while (num > 0) {
|
||||
UBYTE byte1, byte2;
|
||||
|
||||
if (GZREAD(StateFile, &byte1, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
|
||||
if (GZREAD(StateFile, &byte2, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
|
||||
*data++ = (byte2 << 8) | byte1;
|
||||
num--;
|
||||
}
|
||||
}
|
||||
|
||||
void StateSav_SaveINT(const int *data, int num)
|
||||
{
|
||||
if (!StateFile || nFileError != Z_OK)
|
||||
return;
|
||||
|
||||
/* INTs are always saved as 32bits (4 bytes) in the file. They can be any size
|
||||
on the platform however. The sign bit is clobbered into the fourth byte saved
|
||||
for each int; on read it will be extended out to its proper position for the
|
||||
native INT size */
|
||||
while (num > 0) {
|
||||
UBYTE signbit = 0;
|
||||
unsigned int temp;
|
||||
UBYTE byte;
|
||||
int temp0;
|
||||
|
||||
temp0 = *data++;
|
||||
if (temp0 < 0) {
|
||||
temp0 = -temp0;
|
||||
signbit = 0x80;
|
||||
}
|
||||
temp = (unsigned int) temp0;
|
||||
|
||||
byte = temp & 0xff;
|
||||
if (GZWRITE(StateFile, &byte, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
|
||||
temp >>= 8;
|
||||
byte = temp & 0xff;
|
||||
if (GZWRITE(StateFile, &byte, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
|
||||
temp >>= 8;
|
||||
byte = temp & 0xff;
|
||||
if (GZWRITE(StateFile, &byte, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
|
||||
temp >>= 8;
|
||||
byte = (temp & 0x7f) | signbit;
|
||||
if (GZWRITE(StateFile, &byte, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
|
||||
num--;
|
||||
}
|
||||
}
|
||||
|
||||
void StateSav_ReadINT(int *data, int num)
|
||||
{
|
||||
if (!StateFile || nFileError != Z_OK)
|
||||
return;
|
||||
|
||||
while (num > 0) {
|
||||
UBYTE signbit = 0;
|
||||
int temp;
|
||||
UBYTE byte1, byte2, byte3, byte4;
|
||||
|
||||
if (GZREAD(StateFile, &byte1, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
|
||||
if (GZREAD(StateFile, &byte2, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
|
||||
if (GZREAD(StateFile, &byte3, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
|
||||
if (GZREAD(StateFile, &byte4, 1) == 0) {
|
||||
GetGZErrorText();
|
||||
break;
|
||||
}
|
||||
|
||||
signbit = byte4 & 0x80;
|
||||
byte4 &= 0x7f;
|
||||
|
||||
temp = (byte4 << 24) | (byte3 << 16) | (byte2 << 8) | byte1;
|
||||
if (signbit)
|
||||
temp = -temp;
|
||||
*data++ = temp;
|
||||
|
||||
num--;
|
||||
}
|
||||
}
|
||||
|
||||
void StateSav_SaveFNAME(const char *filename)
|
||||
{
|
||||
UWORD namelen;
|
||||
#ifdef HAVE_GETCWD
|
||||
char dirname[FILENAME_MAX];
|
||||
|
||||
/* Check to see if file is in application tree, if so, just save as
|
||||
relative path....*/
|
||||
getcwd(dirname, FILENAME_MAX);
|
||||
if (strncmp(filename, dirname, strlen(dirname)) == 0)
|
||||
/* XXX: check if '/' or '\\' follows dirname in filename? */
|
||||
filename += strlen(dirname) + 1;
|
||||
#endif
|
||||
|
||||
namelen = strlen(filename);
|
||||
/* Save the length of the filename, followed by the filename */
|
||||
StateSav_SaveUWORD(&namelen, 1);
|
||||
StateSav_SaveUBYTE((const UBYTE *) filename, namelen);
|
||||
}
|
||||
|
||||
void StateSav_ReadFNAME(char *filename)
|
||||
{
|
||||
UWORD namelen = 0;
|
||||
|
||||
StateSav_ReadUWORD(&namelen, 1);
|
||||
if (namelen >= FILENAME_MAX) {
|
||||
Log_print("Filenames of %d characters not supported on this platform", (int) namelen);
|
||||
return;
|
||||
}
|
||||
StateSav_ReadUBYTE((UBYTE *) filename, namelen);
|
||||
filename[namelen] = 0;
|
||||
}
|
||||
|
||||
int StateSav_SaveAtariState(const char *filename, const char *mode, UBYTE SaveVerbose)
|
||||
{
|
||||
UBYTE StateVersion = SAVE_VERSION_NUMBER;
|
||||
|
||||
if (StateFile != NULL) {
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
}
|
||||
nFileError = Z_OK;
|
||||
|
||||
StateFile = GZOPEN(filename, mode);
|
||||
if (StateFile == NULL) {
|
||||
Log_print("Could not open %s for state save.", filename);
|
||||
GetGZErrorText();
|
||||
return FALSE;
|
||||
}
|
||||
if (GZWRITE(StateFile, "ATARI800", 8) == 0) {
|
||||
GetGZErrorText();
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
StateSav_SaveUBYTE(&StateVersion, 1);
|
||||
StateSav_SaveUBYTE(&SaveVerbose, 1);
|
||||
/* The order here is important. Atari800_StateSave must be first because it saves the machine type, and
|
||||
decisions on what to save/not save are made based off that later in the process */
|
||||
Atari800_StateSave();
|
||||
CARTRIDGE_StateSave();
|
||||
SIO_StateSave();
|
||||
ANTIC_StateSave();
|
||||
CPU_StateSave(SaveVerbose);
|
||||
GTIA_StateSave();
|
||||
PIA_StateSave();
|
||||
POKEY_StateSave();
|
||||
#ifdef XEP80_EMULATION
|
||||
XEP80_StateSave();
|
||||
#else
|
||||
{
|
||||
int local_xep80_enabled = FALSE;
|
||||
StateSav_SaveINT(&local_xep80_enabled, 1);
|
||||
}
|
||||
#endif /* XEP80_EMULATION */
|
||||
PBI_StateSave();
|
||||
#ifdef PBI_MIO
|
||||
PBI_MIO_StateSave();
|
||||
#else
|
||||
{
|
||||
int local_mio_enabled = FALSE;
|
||||
StateSav_SaveINT(&local_mio_enabled, 1);
|
||||
}
|
||||
#endif /* PBI_MIO */
|
||||
#ifdef PBI_BB
|
||||
PBI_BB_StateSave();
|
||||
#else
|
||||
{
|
||||
int local_bb_enabled = FALSE;
|
||||
StateSav_SaveINT(&local_bb_enabled, 1);
|
||||
}
|
||||
#endif /* PBI_BB */
|
||||
#ifdef PBI_XLD
|
||||
PBI_XLD_StateSave();
|
||||
#else
|
||||
{
|
||||
int local_xld_enabled = FALSE;
|
||||
StateSav_SaveINT(&local_xld_enabled, 1);
|
||||
}
|
||||
#endif /* PBI_XLD */
|
||||
#ifdef DREAMCAST
|
||||
DCStateSave();
|
||||
#endif
|
||||
|
||||
if (GZCLOSE(StateFile) != 0) {
|
||||
StateFile = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
StateFile = NULL;
|
||||
|
||||
if (nFileError != Z_OK)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int StateSav_ReadAtariState(const char *filename, const char *mode)
|
||||
{
|
||||
char header_string[8];
|
||||
UBYTE StateVersion = 0; /* The version of the save file */
|
||||
UBYTE SaveVerbose = 0; /* Verbose mode means save basic, OS if patched */
|
||||
|
||||
if (StateFile != NULL) {
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
}
|
||||
nFileError = Z_OK;
|
||||
|
||||
StateFile = GZOPEN(filename, mode);
|
||||
if (StateFile == NULL) {
|
||||
Log_print("Could not open %s for state read.", filename);
|
||||
GetGZErrorText();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (GZREAD(StateFile, header_string, 8) == 0) {
|
||||
GetGZErrorText();
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
if (memcmp(header_string, "ATARI800", 8) != 0) {
|
||||
Log_print("This is not an Atari800 state save file.");
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (GZREAD(StateFile, &StateVersion, 1) == 0
|
||||
|| GZREAD(StateFile, &SaveVerbose, 1) == 0) {
|
||||
Log_print("Failed read from Atari state file.");
|
||||
GetGZErrorText();
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (StateVersion != SAVE_VERSION_NUMBER && StateVersion < 3) {
|
||||
Log_print("Cannot read this state file because it is an incompatible version.");
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Atari800_StateRead();
|
||||
if (StateVersion >= 4) {
|
||||
CARTRIDGE_StateRead();
|
||||
SIO_StateRead();
|
||||
}
|
||||
ANTIC_StateRead();
|
||||
CPU_StateRead(SaveVerbose, StateVersion);
|
||||
GTIA_StateRead();
|
||||
PIA_StateRead();
|
||||
POKEY_StateRead();
|
||||
if (StateVersion >= 6) {
|
||||
#ifdef XEP80_EMULATION
|
||||
XEP80_StateRead();
|
||||
#else
|
||||
int local_xep80_enabled;
|
||||
StateSav_ReadINT(&local_xep80_enabled,1);
|
||||
if (local_xep80_enabled) {
|
||||
Log_print("Cannot read this state file because this version does not support XEP80.");
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
#endif /* XEP80_EMULATION */
|
||||
PBI_StateRead();
|
||||
#ifdef PBI_MIO
|
||||
PBI_MIO_StateRead();
|
||||
#else
|
||||
{
|
||||
int local_mio_enabled;
|
||||
StateSav_ReadINT(&local_mio_enabled,1);
|
||||
if (local_mio_enabled) {
|
||||
Log_print("Cannot read this state file because this version does not support MIO.");
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif /* PBI_MIO */
|
||||
#ifdef PBI_BB
|
||||
PBI_BB_StateRead();
|
||||
#else
|
||||
{
|
||||
int local_bb_enabled;
|
||||
StateSav_ReadINT(&local_bb_enabled,1);
|
||||
if (local_bb_enabled) {
|
||||
Log_print("Cannot read this state file because this version does not support the Black Box.");
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif /* PBI_BB */
|
||||
#ifdef PBI_XLD
|
||||
PBI_XLD_StateRead();
|
||||
#else
|
||||
{
|
||||
int local_xld_enabled;
|
||||
StateSav_ReadINT(&local_xld_enabled,1);
|
||||
if (local_xld_enabled) {
|
||||
Log_print("Cannot read this state file because this version does not support the 1400XL/1450XLD.");
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif /* PBI_XLD */
|
||||
}
|
||||
#ifdef DREAMCAST
|
||||
DCStateRead();
|
||||
#endif
|
||||
|
||||
GZCLOSE(StateFile);
|
||||
StateFile = NULL;
|
||||
|
||||
if (nFileError != Z_OK)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* hack to compress in memory before writing
|
||||
* - for DREAMCAST only
|
||||
* - 2 reasons for this:
|
||||
* - use bzip2 instead of zip: better compression ratio (the DC VMUs are small)
|
||||
* - write in DC specific file format to provide icon and description
|
||||
*/
|
||||
#ifdef MEMCOMPR
|
||||
|
||||
static char * plainmembuf;
|
||||
static unsigned int plainmemoff;
|
||||
static char * comprmembuf;
|
||||
#define OM_READ 1
|
||||
#define OM_WRITE 2
|
||||
static int openmode;
|
||||
static unsigned int unclen;
|
||||
static char savename[FILENAME_MAX];
|
||||
#define HDR_LEN 640
|
||||
|
||||
#define ALLOC_LEN 210000
|
||||
|
||||
/* replacement for GZOPEN */
|
||||
static gzFile *mem_open(const char *name, const char *mode)
|
||||
{
|
||||
if (*mode == 'w') {
|
||||
/* open for write (save) */
|
||||
openmode = OM_WRITE;
|
||||
strcpy(savename, name); /* remember name */
|
||||
plainmembuf = Util_malloc(ALLOC_LEN);
|
||||
plainmemoff = 0; /*HDR_LEN;*/
|
||||
return (gzFile *) plainmembuf;
|
||||
}
|
||||
else {
|
||||
/* open for read (read) */
|
||||
FILE *f;
|
||||
size_t len;
|
||||
openmode = OM_READ;
|
||||
unclen = ALLOC_LEN;
|
||||
f = fopen(name, mode);
|
||||
if (f == NULL)
|
||||
return NULL;
|
||||
plainmembuf = Util_malloc(ALLOC_LEN);
|
||||
comprmembuf = Util_malloc(ALLOC_LEN);
|
||||
len = fread(comprmembuf, 1, ALLOC_LEN, f);
|
||||
fclose(f);
|
||||
/* XXX: does DREAMCAST's fread return ((size_t) -1) ? */
|
||||
if (len != 0
|
||||
&& BZ2_bzBuffToBuffDecompress(plainmembuf, &unclen, comprmembuf + HDR_LEN, len - HDR_LEN, 1, 0) == BZ_OK) {
|
||||
#ifdef DEBUG
|
||||
printf("decompress: old len %lu, new len %lu\n",
|
||||
(unsigned long) len - 1024, (unsigned long) unclen);
|
||||
#endif
|
||||
free(comprmembuf);
|
||||
plainmemoff = 0;
|
||||
return (gzFile *) plainmembuf;
|
||||
}
|
||||
free(comprmembuf);
|
||||
free(plainmembuf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* replacement for GZCLOSE */
|
||||
static int mem_close(gzFile *stream)
|
||||
{
|
||||
int status = -1;
|
||||
unsigned int comprlen = ALLOC_LEN - HDR_LEN;
|
||||
if (openmode != OM_WRITE) {
|
||||
/* was opened for read */
|
||||
free(plainmembuf);
|
||||
return 0;
|
||||
}
|
||||
comprmembuf = Util_malloc(ALLOC_LEN);
|
||||
if (BZ2_bzBuffToBuffCompress(comprmembuf + HDR_LEN, &comprlen, plainmembuf, plainmemoff, 9, 0, 0) == BZ_OK) {
|
||||
FILE *f;
|
||||
f = fopen(savename, "wb");
|
||||
if (f != NULL) {
|
||||
char icon[32 + 512];
|
||||
#ifdef DEBUG
|
||||
printf("mem_close: plain len %lu, compr len %lu\n",
|
||||
(unsigned long) plainmemoff, (unsigned long) comprlen);
|
||||
#endif
|
||||
memcpy(icon, palette, 32);
|
||||
memcpy(icon + 32, bitmap, 512);
|
||||
ndc_vmu_create_vmu_header(comprmembuf, "Atari800DC",
|
||||
"Atari800DC " A800DCVERASC " saved state",
|
||||
comprlen, icon);
|
||||
comprlen = (comprlen + HDR_LEN + 511) & ~511;
|
||||
ndc_vmu_do_crc(comprmembuf, comprlen);
|
||||
status = (fwrite(comprmembuf, 1, comprlen, f) == comprlen) ? 0 : -1;
|
||||
status |= fclose(f);
|
||||
#ifdef DEBUG
|
||||
if (status != 0)
|
||||
printf("mem_close: fwrite: error!!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
free(comprmembuf);
|
||||
free(plainmembuf);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* replacement for GZREAD */
|
||||
static size_t mem_read(void *buf, size_t len, gzFile *stream)
|
||||
{
|
||||
if (plainmemoff + len > unclen) return 0; /* shouldn't happen */
|
||||
memcpy(buf, plainmembuf + plainmemoff, len);
|
||||
plainmemoff += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* replacement for GZWRITE */
|
||||
static size_t mem_write(const void *buf, size_t len, gzFile *stream)
|
||||
{
|
||||
if (plainmemoff + len > ALLOC_LEN) return 0; /* shouldn't happen */
|
||||
memcpy(plainmembuf + plainmemoff, buf, len);
|
||||
plainmemoff += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
#endif /* #ifdef MEMCOMPR */
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef STATESAV_H_
|
||||
#define STATESAV_H_
|
||||
|
||||
#include "atari.h"
|
||||
|
||||
int StateSav_SaveAtariState(const char *filename, const char *mode, UBYTE SaveVerbose);
|
||||
int StateSav_ReadAtariState(const char *filename, const char *mode);
|
||||
|
||||
void StateSav_SaveUBYTE(const UBYTE *data, int num);
|
||||
void StateSav_SaveUWORD(const UWORD *data, int num);
|
||||
void StateSav_SaveINT(const int *data, int num);
|
||||
void StateSav_SaveFNAME(const char *filename);
|
||||
|
||||
void StateSav_ReadUBYTE(UBYTE *data, int num);
|
||||
void StateSav_ReadUWORD(UWORD *data, int num);
|
||||
void StateSav_ReadINT(int *data, int num);
|
||||
void StateSav_ReadFNAME(char *filename);
|
||||
|
||||
#endif /* STATESAV_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,195 +0,0 @@
|
||||
/*
|
||||
* ui.h - Atari user interface definitions
|
||||
*
|
||||
* Copyright (C) 1995-1998 David Firth
|
||||
* Copyright (C) 1998-2008 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef UI_H_
|
||||
#define UI_H_
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h> /* FILENAME_MAX */
|
||||
#include "atari.h"
|
||||
|
||||
/* Three legitimate entries to UI module. */
|
||||
int UI_SelectCartType(int k);
|
||||
void UI_Run(void);
|
||||
|
||||
extern int UI_is_active;
|
||||
extern int UI_alt_function;
|
||||
|
||||
#ifdef CRASH_MENU
|
||||
extern int UI_crash_code;
|
||||
extern UWORD UI_crash_address;
|
||||
extern UWORD UI_crash_afterCIM;
|
||||
#endif
|
||||
|
||||
#define UI_MAX_DIRECTORIES 8
|
||||
|
||||
extern char UI_atari_files_dir[UI_MAX_DIRECTORIES][FILENAME_MAX];
|
||||
extern char UI_saved_files_dir[UI_MAX_DIRECTORIES][FILENAME_MAX];
|
||||
extern int UI_n_atari_files_dir;
|
||||
extern int UI_n_saved_files_dir;
|
||||
|
||||
#ifdef SDL
|
||||
void PLATFORM_SetJoystickKey(int joystick, int direction, int value);
|
||||
void PLATFORM_GetJoystickKeyName(int joystick, int direction, char *buffer, int bufsize);
|
||||
int GetRawKey(void);
|
||||
#endif
|
||||
|
||||
/* Menu codes for Alt+letter shortcuts.
|
||||
Store in UI_alt_function and put AKEY_UI in INPUT_key_code. */
|
||||
#define UI_MENU_DISK 0
|
||||
#define UI_MENU_CARTRIDGE 1
|
||||
#define UI_MENU_RUN 2
|
||||
#define UI_MENU_SYSTEM 3
|
||||
#define UI_MENU_SOUND 4
|
||||
#define UI_MENU_SOUND_RECORDING 5
|
||||
#define UI_MENU_DISPLAY 6
|
||||
#define UI_MENU_SETTINGS 7
|
||||
#define UI_MENU_SAVESTATE 8
|
||||
#define UI_MENU_LOADSTATE 9
|
||||
#define UI_MENU_PCX 10
|
||||
#define UI_MENU_PCXI 11
|
||||
#define UI_MENU_BACK 12
|
||||
#define UI_MENU_RESETW 13
|
||||
#define UI_MENU_RESETC 14
|
||||
#define UI_MENU_MONITOR 15
|
||||
#define UI_MENU_ABOUT 16
|
||||
#define UI_MENU_EXIT 17
|
||||
#define UI_MENU_CASSETTE 18
|
||||
|
||||
/* Structure of menu item. Each menu is just an array of items of this structure
|
||||
terminated by UI_MENU_END */
|
||||
typedef struct
|
||||
{
|
||||
UWORD flags; /* Flags, see values below */
|
||||
SWORD retval; /* Value returned by Select when this item is selected */
|
||||
/* < 0 means that item is strictly informative and cannot be selected */
|
||||
char *prefix; /* Text to prepend the item */
|
||||
char *item; /* Main item text */
|
||||
const char *suffix; /* Optional text to show after the item text (e.g. key shortcut) */
|
||||
/* or (if (flags & UI_ITEM_TIP) != 0) "tooltip" */
|
||||
} UI_tMenuItem;
|
||||
|
||||
/* The following are item types, mutually exclusive. */
|
||||
#define UI_ITEM_HIDDEN 0x00 /* Item does not appear in the menu */
|
||||
#define UI_ITEM_ACTION 0x01 /* Item invokes an action */
|
||||
#define UI_ITEM_CHECK 0x02 /* Item represents a boolean value */
|
||||
#define UI_ITEM_FILESEL 0x03 /* Item invokes file/directory selection */
|
||||
#define UI_ITEM_SUBMENU 0x04 /* Item opens a submenu */
|
||||
/* UI_ITEM_CHECK means that the value of UI_ITEM_CHECKED is shown.
|
||||
UI_ITEM_FILESEL and UI_ITEM_SUBMENU are just for optional decorations,
|
||||
so the user knows what happens when he/she selects this item. */
|
||||
#define UI_ITEM_TYPE 0x0f
|
||||
|
||||
/* The following are bit masks and should be combined with one of the above item types. */
|
||||
#define UI_ITEM_CHECKED 0x10 /* The boolean value for UI_ITEM_CHECK is true */
|
||||
#define UI_ITEM_TIP 0x20 /* suffix is shown when the item is selected rather than on its right */
|
||||
|
||||
#if defined(_WIN32_WCE) || defined(DREAMCAST)
|
||||
/* No function keys nor Alt+letter on Windows CE, Sega DC */
|
||||
#define UI_MENU_ACCEL(keystroke) NULL
|
||||
#else
|
||||
#define UI_MENU_ACCEL(keystroke) keystroke
|
||||
#endif
|
||||
|
||||
#define UI_MENU_LABEL(item) { UI_ITEM_ACTION, -1, NULL, item, NULL }
|
||||
#define UI_MENU_ACTION(retval, item) { UI_ITEM_ACTION, retval, NULL, item, NULL }
|
||||
#define UI_MENU_ACTION_PREFIX(retval, prefix, item) { UI_ITEM_ACTION, retval, prefix, item, NULL }
|
||||
#define UI_MENU_ACTION_PREFIX_TIP(retval, prefix, item, tip) { UI_ITEM_ACTION | UI_ITEM_TIP, retval, prefix, item, tip }
|
||||
#define UI_MENU_ACTION_ACCEL(retval, item, keystroke) { UI_ITEM_ACTION, retval, NULL, item, UI_MENU_ACCEL(keystroke) }
|
||||
#define UI_MENU_ACTION_TIP(retval, item, tip) { UI_ITEM_ACTION | UI_ITEM_TIP, retval, NULL, item, tip }
|
||||
#define UI_MENU_CHECK(retval, item) { UI_ITEM_CHECK, retval, NULL, item, NULL }
|
||||
#define UI_MENU_FILESEL(retval, item) { UI_ITEM_FILESEL, retval, NULL, item, NULL }
|
||||
#define UI_MENU_FILESEL_PREFIX(retval, prefix, item) { UI_ITEM_FILESEL, retval, prefix, item, NULL }
|
||||
#define UI_MENU_FILESEL_PREFIX_TIP(retval, prefix, item, tip) { UI_ITEM_FILESEL | UI_ITEM_TIP, retval, prefix, item, tip }
|
||||
#define UI_MENU_FILESEL_ACCEL(retval, item, keystroke) { UI_ITEM_FILESEL, retval, NULL, item, UI_MENU_ACCEL(keystroke) }
|
||||
#define UI_MENU_FILESEL_TIP(retval, item, tip) { UI_ITEM_FILESEL | UI_ITEM_TIP, retval, NULL, item, tip }
|
||||
#define UI_MENU_SUBMENU(retval, item) { UI_ITEM_SUBMENU, retval, NULL, item, NULL }
|
||||
#define UI_MENU_SUBMENU_SUFFIX(retval, item, suffix) { UI_ITEM_SUBMENU, retval, NULL, item, suffix }
|
||||
#define UI_MENU_SUBMENU_ACCEL(retval, item, keystroke) { UI_ITEM_SUBMENU, retval, NULL, item, UI_MENU_ACCEL(keystroke) }
|
||||
#define UI_MENU_END { UI_ITEM_HIDDEN, 0, NULL, NULL, NULL }
|
||||
|
||||
/* UI driver entry prototypes */
|
||||
|
||||
/* Select provides simple selection from menu.
|
||||
title can be used as a caption.
|
||||
If (flags & UI_SELECT_POPUP) != 0 the menu is a popup menu.
|
||||
default_item is initially selected item (not item # but rather retval from menu structure).
|
||||
menu is array of items of type UI_tMenuItem, must be termintated by UI_MENU_END.
|
||||
If seltype is non-null, it is used to return selection type (see UI_USER_* below).
|
||||
UI_USER_DRAG_UP and UI_USER_DRAG_DOWN are returned only if (flags & UI_SELECT_DRAG) != 0.
|
||||
Returned is retval of the selected item or -1 if the user cancelled selection,
|
||||
or -2 if the user pressed "magic key" (Tab). */
|
||||
typedef int (*UI_fnSelect)(const char *title, int flags, int default_item, const UI_tMenuItem *menu, int *seltype);
|
||||
/* SelectInt returns an integer chosen by the user from the range min_value..max_value.
|
||||
default_value is the initial selection and the value returned if the selection is cancelled. */
|
||||
typedef int (*UI_fnSelectInt)(int default_value, int min_value, int max_value);
|
||||
/* EditString provides string input. pString is shown initially and can be modified by the user.
|
||||
It won't exceed nSize characters, including NUL. Note that pString may be modified even
|
||||
when the user pressed Esc. */
|
||||
typedef int (*UI_fnEditString)(const char *title, char *string, int size);
|
||||
/* GetSaveFilename and GetLoadFilename return fully qualified file name via pFilename.
|
||||
pDirectories are "favourite" directories (there are nDirectories of them).
|
||||
Selection starts in the directory of the passed pFilename (i.e. pFilename must be initialized)
|
||||
or (if pFilename[0] == '\0') in the first "favourite" directory. */
|
||||
typedef int (*UI_fnGetSaveFilename)(char *filename, char directories[][FILENAME_MAX], int n_directories);
|
||||
typedef int (*UI_fnGetLoadFilename)(char *filename, char directories[][FILENAME_MAX], int n_directories);
|
||||
/* GetDirectoryPath is a directory browser */
|
||||
typedef int (*UI_fnGetDirectoryPath)(char *directory);
|
||||
/* Message is just some kind of MessageBox */
|
||||
typedef void (*UI_fnMessage)(const char *message, int waitforkey);
|
||||
/* InfoScreen displays a "long" message.
|
||||
Caution: lines in pMessage should be ended with '\0', the message should be terminated with '\n'. */
|
||||
typedef void (*UI_fnInfoScreen)(const char *title, const char *message);
|
||||
/* Init is called to initialize driver every time UI code is executed.
|
||||
Driver must be protected against multiple inits. */
|
||||
typedef void (*UI_fnInit)(void);
|
||||
|
||||
/* Bit masks for flags */
|
||||
#define UI_SELECT_POPUP 0x01
|
||||
#define UI_SELECT_DRAG 0x02
|
||||
|
||||
/* Values returned via seltype */
|
||||
#define UI_USER_SELECT 1
|
||||
#define UI_USER_TOGGLE 2
|
||||
#define UI_USER_DELETE 3
|
||||
#define UI_USER_DRAG_UP 4
|
||||
#define UI_USER_DRAG_DOWN 5
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UI_fnSelect fSelect;
|
||||
UI_fnSelectInt fSelectInt;
|
||||
UI_fnEditString fEditString;
|
||||
UI_fnGetSaveFilename fGetSaveFilename;
|
||||
UI_fnGetLoadFilename fGetLoadFilename;
|
||||
UI_fnGetDirectoryPath fGetDirectoryPath;
|
||||
UI_fnMessage fMessage;
|
||||
UI_fnInfoScreen fInfoScreen;
|
||||
UI_fnInit fInit;
|
||||
} UI_tDriver;
|
||||
|
||||
/* Current UI driver. Port can override it and set pointer to port
|
||||
specific driver */
|
||||
extern UI_tDriver *UI_driver;
|
||||
|
||||
#endif /* UI_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +0,0 @@
|
||||
#ifndef UI_BASIC_H_
|
||||
#define UI_BASIC_H_
|
||||
|
||||
#include "ui.h"
|
||||
|
||||
/* "Basic" UI driver. Always present and guaranteed to work. Override
|
||||
driver may call into this one to implement filtering */
|
||||
extern UI_tDriver UI_BASIC_driver;
|
||||
|
||||
/* for Windows CE and Dreamcast */
|
||||
#ifdef USE_UI_BASIC_ONSCREEN_KEYBOARD
|
||||
int UI_BASIC_OnScreenKeyboard(const char *title, int layout);
|
||||
/* layout must be one of MACHINE_* values (see atari.h)
|
||||
or -1 for base keyboard with no function keys */
|
||||
#endif
|
||||
|
||||
/* used only in the Dreamcast port */
|
||||
extern const unsigned char UI_BASIC_key_to_ascii[256];
|
||||
|
||||
#endif /* UI_BASIC_H_ */
|
||||
@@ -1,419 +0,0 @@
|
||||
/*
|
||||
* util.c - utility functions
|
||||
*
|
||||
* Copyright (c) 2005 Piotr Fusik
|
||||
* Copyright (c) 2005 Atari800 development team (see DOC/CREDITS)
|
||||
*
|
||||
* This file is part of the Atari800 emulator project which emulates
|
||||
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
|
||||
*
|
||||
* Atari800 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.
|
||||
*
|
||||
* Atari800 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 Atari800; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
/* suppress -ansi -pedantic warning for fdopen: */
|
||||
#ifdef __STRICT_ANSI__
|
||||
#undef __STRICT_ANSI__
|
||||
#include <stdio.h>
|
||||
#define __STRICT_ANSI__ 1
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif /* __STRICT_ANSI__ */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "atari.h"
|
||||
#include "util.h"
|
||||
|
||||
int Util_chrieq(char c1, char c2)
|
||||
{
|
||||
switch (c1 ^ c2) {
|
||||
case 0x00:
|
||||
return TRUE;
|
||||
case 0x20:
|
||||
return (c1 >= 'A' && c1 <= 'Z') || (c1 >= 'a' && c1 <= 'z');
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
/*
|
||||
** STRICMP.C - Comapres strings, case-insensitive.
|
||||
**
|
||||
** public domain by Bob Stout
|
||||
**
|
||||
*/
|
||||
|
||||
/* from http://c.snippets.org/code/stricmp.c */
|
||||
int Util_stricmp(const char *str1, const char *str2)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
retval = tolower(*str1++) - tolower(*str2++);
|
||||
|
||||
if (retval)
|
||||
break;
|
||||
|
||||
if (*str1 && *str2)
|
||||
continue;
|
||||
else break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *Util_stpcpy(char *dest, const char *src)
|
||||
{
|
||||
size_t len = strlen(src);
|
||||
memcpy(dest, src, len + 1);
|
||||
return dest + len;
|
||||
}
|
||||
|
||||
#ifndef HAVE_STRNCPY
|
||||
char *Util_strncpy(char *dest, const char *src, size_t size) {
|
||||
while (size-- > 0) {
|
||||
if ((*dest++ = *src++) == '\0')
|
||||
break;
|
||||
}
|
||||
while (size-- > 0)
|
||||
*dest++ = '\0';
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *safe_strncpy(char *buffer, const char *source, int bufsize)
|
||||
{
|
||||
if (buffer == NULL) return NULL;
|
||||
if (bufsize > 0) {
|
||||
strncpy(buffer, source != NULL ? source : "", bufsize);
|
||||
buffer[bufsize-1] = '\0';
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char *Util_strlcpy(char *dest, const char *src, size_t size)
|
||||
{
|
||||
Util_strncpy(dest, src, size);
|
||||
dest[size - 1] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *Util_strupper(char *s)
|
||||
{
|
||||
char *p;
|
||||
for (p = s; *p != '\0'; p++)
|
||||
if (*p >= 'a' && *p <= 'z')
|
||||
*p += 'A' - 'a';
|
||||
return s;
|
||||
}
|
||||
|
||||
char *Util_strlower(char *s)
|
||||
{
|
||||
char *p;
|
||||
for (p = s; *p != '\0'; p++)
|
||||
if (*p >= 'A' && *p <= 'Z')
|
||||
*p += 'a' - 'A';
|
||||
return s;
|
||||
}
|
||||
|
||||
void Util_chomp(char *s)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = strlen(s);
|
||||
if (len >= 2 && s[len - 1] == '\n' && s[len - 2] == '\r')
|
||||
s[len - 2] = '\0';
|
||||
else if (len >= 1 && (s[len - 1] == '\n' || s[len - 1] == '\r'))
|
||||
s[len - 1] = '\0';
|
||||
}
|
||||
|
||||
void Util_trim(char *s)
|
||||
{
|
||||
char *p = s;
|
||||
char *q;
|
||||
/* skip leading whitespace */
|
||||
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
|
||||
p++;
|
||||
/* now p points at the first non-whitespace character */
|
||||
|
||||
if (*p == '\0') {
|
||||
/* only whitespace */
|
||||
*s = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
q = s + strlen(s);
|
||||
/* skip trailing whitespace */
|
||||
/* we have found p < q such that *p is non-whitespace,
|
||||
so this loop terminates with q >= p */
|
||||
do
|
||||
q--;
|
||||
while (*q == ' ' || *q == '\t' || *q == '\r' || *q == '\n');
|
||||
|
||||
/* now q points at the last non-whitespace character */
|
||||
/* cut off trailing whitespace */
|
||||
*++q = '\0';
|
||||
|
||||
/* move to string */
|
||||
memmove(s, p, q + 1 - p);
|
||||
}
|
||||
|
||||
int Util_sscandec(const char *s)
|
||||
{
|
||||
int result;
|
||||
if (*s == '\0')
|
||||
return -1;
|
||||
result = 0;
|
||||
for (;;) {
|
||||
if (*s >= '0' && *s <= '9')
|
||||
result = 10 * result + *s - '0';
|
||||
else if (*s == '\0')
|
||||
return result;
|
||||
else
|
||||
return -1;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
int Util_sscanhex(const char *s)
|
||||
{
|
||||
int result;
|
||||
if (*s == '\0')
|
||||
return -1;
|
||||
result = 0;
|
||||
for (;;) {
|
||||
if (*s >= '0' && *s <= '9')
|
||||
result = 16 * result + *s - '0';
|
||||
else if (*s >= 'A' && *s <= 'F')
|
||||
result = 16 * result + *s - 'A' + 10;
|
||||
else if (*s >= 'a' && *s <= 'f')
|
||||
result = 16 * result + *s - 'a' + 10;
|
||||
else if (*s == '\0')
|
||||
return result;
|
||||
else
|
||||
return -1;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
int Util_sscanbool(const char *s)
|
||||
{
|
||||
if (*s == '0' && s[1] == '\0')
|
||||
return 0;
|
||||
if (*s == '1' && s[1] == '\0')
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *Util_malloc(size_t size)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
if (ptr == NULL) {
|
||||
Atari800_Exit(FALSE);
|
||||
printf("Fatal error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *Util_realloc(void *ptr, size_t size)
|
||||
{
|
||||
ptr = realloc(ptr, size);
|
||||
if (ptr == NULL) {
|
||||
Atari800_Exit(FALSE);
|
||||
printf("Fatal error: out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *Util_strdup(const char *s)
|
||||
{
|
||||
/* don't use strdup(): it is unavailable on WinCE */
|
||||
size_t size = strlen(s) + 1;
|
||||
char *ptr = (char *) Util_malloc(size);
|
||||
memcpy(ptr, s, size); /* faster than strcpy(ptr, s) */
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void Util_splitpath(const char *path, char *dir_part, char *file_part)
|
||||
{
|
||||
const char *p;
|
||||
/* find the last Util_DIR_SEP_CHAR except the last character */
|
||||
for (p = path + strlen(path) - 2; p >= path; p--) {
|
||||
if (*p == Util_DIR_SEP_CHAR
|
||||
#ifdef DIR_SEP_BACKSLASH
|
||||
/* on DOSish systems slash can be also used as a directory separator */
|
||||
|| *p == '/'
|
||||
#endif
|
||||
) {
|
||||
if (dir_part != NULL) {
|
||||
int len = p - path;
|
||||
if (p == path || (p == path + 2 && path[1] == ':'))
|
||||
/* root dir: include Util_DIR_SEP_CHAR in dir_part */
|
||||
len++;
|
||||
memcpy(dir_part, path, len);
|
||||
dir_part[len] = '\0';
|
||||
}
|
||||
if (file_part != NULL)
|
||||
strcpy(file_part, p + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* no Util_DIR_SEP_CHAR: current dir */
|
||||
if (dir_part != NULL)
|
||||
dir_part[0] = '\0';
|
||||
if (file_part != NULL)
|
||||
strcpy(file_part, path);
|
||||
}
|
||||
|
||||
void Util_catpath(char *result, const char *path1, const char *path2)
|
||||
{
|
||||
#ifdef HAVE_SNPRINTF
|
||||
snprintf(result, FILENAME_MAX,
|
||||
#else
|
||||
sprintf(result,
|
||||
#endif
|
||||
path1[0] == '\0' || path2[0] == Util_DIR_SEP_CHAR || path1[strlen(path1) - 1] == Util_DIR_SEP_CHAR
|
||||
#ifdef DIR_SEP_BACKSLASH
|
||||
|| path2[0] == '/' || path1[strlen(path1) - 1] == '/'
|
||||
#endif
|
||||
? "%s%s" : "%s" Util_DIR_SEP_STR "%s", path1, path2);
|
||||
}
|
||||
|
||||
int Util_fileexists(const char *filename)
|
||||
{
|
||||
FILE *fp;
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == NULL)
|
||||
return FALSE;
|
||||
fclose(fp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
int Util_direxists(const char *filename)
|
||||
{
|
||||
DWORD attr;
|
||||
#ifdef UNICODE
|
||||
WCHAR wfilename[FILENAME_MAX];
|
||||
if (MultiByteToWideChar(CP_ACP, 0, filename, -1, wfilename, FILENAME_MAX) <= 0)
|
||||
return FALSE;
|
||||
attr = GetFileAttributes(wfilename);
|
||||
#else
|
||||
attr = GetFileAttributes(filename);
|
||||
#endif /* UNICODE */
|
||||
if (attr == 0xffffffff)
|
||||
return FALSE;
|
||||
#ifdef _WIN32_WCE
|
||||
/* WinCE: Make sure user does not up-dir from the root */
|
||||
if (*filename == 0)
|
||||
return FALSE;
|
||||
#endif
|
||||
return (attr & FILE_ATTRIBUTE_DIRECTORY) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_STAT)
|
||||
|
||||
int Util_direxists(const char *filename)
|
||||
{
|
||||
struct stat filestatus;
|
||||
return stat(filename, &filestatus) == 0 && (filestatus.st_mode & S_IFDIR);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int Util_direxists(const char *filename)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif /* defined(HAVE_STAT) */
|
||||
|
||||
|
||||
int Util_flen(FILE *fp)
|
||||
{
|
||||
fseek(fp, 0, SEEK_END);
|
||||
return (int) ftell(fp);
|
||||
}
|
||||
|
||||
/* Creates a file that does not exist and fills in filename with its name.
|
||||
filename must point to FILENAME_MAX characters buffer which doesn't need
|
||||
to be initialized. */
|
||||
FILE *Util_uniqopen(char *filename, const char *mode)
|
||||
{
|
||||
/* We cannot simply call tmpfile(), because we don't want the file
|
||||
to be deleted when we close it, and we need the filename. */
|
||||
|
||||
#if defined(HAVE_MKSTEMP) && defined(HAVE_FDOPEN)
|
||||
/* this is the only implementation without a race condition */
|
||||
strcpy(filename, "a8XXXXXX");
|
||||
/* mkstemp() modifies the 'X'es and returns an open descriptor */
|
||||
return fdopen(mkstemp(filename), mode);
|
||||
#elif defined(HAVE_TMPNAM)
|
||||
/* tmpnam() is better than mktemp(), because it creates filenames
|
||||
in system's temporary directory. It is also more portable. */
|
||||
return fopen(tmpnam(filename), mode);
|
||||
#elif defined(HAVE_MKTEMP)
|
||||
strcpy(filename, "a8XXXXXX");
|
||||
/* mktemp() modifies the 'X'es and returns filename */
|
||||
return fopen(mktemp(filename), mode);
|
||||
#else
|
||||
/* Roll-your-own */
|
||||
int no;
|
||||
for (no = 0; no < 1000000; no++) {
|
||||
sprintf(filename, "a8%06d", no);
|
||||
if (!Util_fileexists(filename))
|
||||
return fopen(filename, mode);
|
||||
}
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WIN32) && defined(UNICODE)
|
||||
int Util_unlink(const char *filename)
|
||||
{
|
||||
WCHAR wfilename[FILENAME_MAX];
|
||||
#ifdef _WIN32_WCE
|
||||
char cwd[FILENAME_MAX];
|
||||
char fullfilename[FILENAME_MAX];
|
||||
if (filename[0] != '\\' && filename[0] != '/') {
|
||||
getcwd(cwd, FILENAME_MAX);
|
||||
Util_catpath(fullfilename, cwd, filename);
|
||||
if (MultiByteToWideChar(CP_ACP, 0, fullfilename, -1, wfilename, FILENAME_MAX) <= 0)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (MultiByteToWideChar(CP_ACP, 0, filename, -1, wfilename, FILENAME_MAX) <= 0)
|
||||
return -1;
|
||||
return (DeleteFile(wfilename) != 0) ? 0 : -1;
|
||||
}
|
||||
#elif defined(WIN32) && !defined(UNICODE)
|
||||
int Util_unlink(const char *filename)
|
||||
{
|
||||
return (DeleteFile(filename) != 0) ? 0 : -1;
|
||||
}
|
||||
#endif /* defined(WIN32) && defined(UNICODE) */
|
||||
@@ -1,178 +0,0 @@
|
||||
#ifndef UTIL_H_
|
||||
#define UTIL_H_
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* String functions ------------------------------------------------------ */
|
||||
|
||||
/* Returns TRUE if the characters are equal or represent the same letter
|
||||
in different case. */
|
||||
int Util_chrieq(char c1, char c2);
|
||||
|
||||
#ifdef __STRICT_ANSI__
|
||||
/* Returns a positive integer if str1>str2, negative if str1<str2
|
||||
* 0 if str1 == str2, case insensitive */
|
||||
int Util_stricmp(const char *str1, const char *str2);
|
||||
#elif defined(WIN32)
|
||||
#define Util_stricmp _stricmp
|
||||
#elif defined(HAVE_STRCASECMP)
|
||||
#define Util_stricmp strcasecmp
|
||||
#else
|
||||
#define Util_stricmp stricmp
|
||||
#endif
|
||||
|
||||
/* Same as stpcpy() in some C libraries: copies src to dest
|
||||
and returns a pointer to the trailing NUL in dest. */
|
||||
char *Util_stpcpy(char *dest, const char *src);
|
||||
|
||||
/* NestedVM strncpy from newlib has a bug */
|
||||
#ifdef HAVE_STRNCPY
|
||||
#define Util_strncpy strncpy
|
||||
#else
|
||||
char *Util_strncpy(char *dest, const char *src, size_t size);
|
||||
#endif
|
||||
|
||||
/* Same as strlcpy() in some C libraries: copies src to dest
|
||||
and terminates the string. Never writes more than size characters
|
||||
to dest (the result may be truncated). Returns dest. */
|
||||
char *Util_strlcpy(char *dest, const char *src, size_t size);
|
||||
|
||||
/* Modifies the string to uppercase and returns it. */
|
||||
char *Util_strupper(char *s);
|
||||
|
||||
/* Modifies the string to lowercase and returns it. */
|
||||
char *Util_strlower(char *s);
|
||||
|
||||
/* Similar to Perl's chomp(): removes trailing LF, CR or CR/LF. */
|
||||
void Util_chomp(char *s);
|
||||
|
||||
/* Similar to Basic's trim(): removes leading and trailing whitespace. */
|
||||
void Util_trim(char *s);
|
||||
|
||||
/* Converts the string to a non-negative integer and returns it.
|
||||
The string must represent the number and nothing else.
|
||||
-1 indicates an error. */
|
||||
int Util_sscandec(const char *s);
|
||||
|
||||
/* Likewise, but parses hexadecimal numbers. */
|
||||
int Util_sscanhex(const char *s);
|
||||
|
||||
/* Likewise, but allows only 0 and 1. */
|
||||
int Util_sscanbool(const char *s);
|
||||
|
||||
/* safe_strncpy guarantees that the dest. buffer ends with '\0' */
|
||||
char *safe_strncpy(char *, const char *, int);
|
||||
|
||||
/* Memory management ----------------------------------------------------- */
|
||||
|
||||
/* malloc() with out-of-memory checking. Never returns NULL. */
|
||||
void *Util_malloc(size_t size);
|
||||
|
||||
/* realloc() with out-of-memory checking. Never returns NULL. */
|
||||
void *Util_realloc(void *ptr, size_t size);
|
||||
|
||||
/* strdup() with out-of-memory checking. Never returns NULL. */
|
||||
char *Util_strdup(const char *s);
|
||||
|
||||
|
||||
/* Filenames ------------------------------------------------------------- */
|
||||
|
||||
/* I assume here that '\n' is not valid in filenames,
|
||||
at least not as their first character. */
|
||||
#define Util_FILENAME_NOT_SET "\n"
|
||||
#define Util_filenamenotset(filename) ((filename)[0] == '\n')
|
||||
|
||||
#ifdef DIR_SEP_BACKSLASH
|
||||
#define Util_DIR_SEP_CHAR '\\'
|
||||
#define Util_DIR_SEP_STR "\\"
|
||||
#else
|
||||
#define Util_DIR_SEP_CHAR '/'
|
||||
#define Util_DIR_SEP_STR "/"
|
||||
#endif
|
||||
|
||||
/* Splits a filename into directory part and file part. */
|
||||
/* dir_part or file_part may be NULL. */
|
||||
void Util_splitpath(const char *path, char *dir_part, char *file_part);
|
||||
|
||||
/* Concatenates file paths.
|
||||
Places directory separator char between paths, unless path1 is empty
|
||||
or ends with the separator char, or path2 starts with the separator char. */
|
||||
void Util_catpath(char *result, const char *path1, const char *path2);
|
||||
|
||||
|
||||
/* File I/O -------------------------------------------------------------- */
|
||||
|
||||
/* Returns TRUE if the specified file exists. */
|
||||
int Util_fileexists(const char *filename);
|
||||
|
||||
/* Returns TRUE if the specified directory exists. */
|
||||
int Util_direxists(const char *filename);
|
||||
|
||||
/* Rewinds the stream to its beginning. */
|
||||
#ifdef HAVE_REWIND
|
||||
#define Util_rewind(fp) rewind(fp)
|
||||
#else
|
||||
#define Util_rewind(fp) fseek(fp, 0, SEEK_SET)
|
||||
#endif
|
||||
|
||||
/* Returns the length of an open stream.
|
||||
May change the current position. */
|
||||
int Util_flen(FILE *fp);
|
||||
|
||||
/* Deletes a file, returns 0 on success, -1 on failure. */
|
||||
#ifdef WIN32
|
||||
int Util_unlink(const char *filename);
|
||||
#define HAVE_UTIL_UNLINK
|
||||
#elif defined(HAVE_UNLINK)
|
||||
#define Util_unlink unlink
|
||||
#define HAVE_UTIL_UNLINK
|
||||
#endif /* defined(HAVE_UNLINK) */
|
||||
|
||||
/* Creates a file that does not exist and fills in filename with its name. */
|
||||
FILE *Util_uniqopen(char *filename, const char *mode);
|
||||
|
||||
/* Support for temporary files.
|
||||
|
||||
Util_tmpbufdef() defines storage for names of temporary files, if necessary.
|
||||
Example use:
|
||||
Util_tmpbufdef(static, mytmpbuf[4]) // four buffers with "static" storage
|
||||
Util_fopen() opens a *non-temporary* file and marks tmpbuf
|
||||
as *not containing* name of a temporary file.
|
||||
Util_tmpopen() creates a temporary file with "wb+" mode.
|
||||
Util_fclose() closes a file. If it was temporary, it gets deleted.
|
||||
|
||||
There are 3 implementations of the above:
|
||||
- one that uses tmpfile() (preferred)
|
||||
- one that stores names of temporary files and deletes them when they
|
||||
are closed
|
||||
- one that creates unique files but doesn't delete them
|
||||
because Util_unlink is not available
|
||||
*/
|
||||
#ifdef HAVE_TMPFILE
|
||||
#define Util_tmpbufdef(modifier, def)
|
||||
#define Util_fopen(filename, mode, tmpbuf) fopen(filename, mode)
|
||||
#define Util_tmpopen(tmpbuf) tmpfile()
|
||||
#define Util_fclose(fp, tmpbuf) fclose(fp)
|
||||
#elif defined(HAVE_UTIL_UNLINK)
|
||||
#define Util_tmpbufdef(modifier, def) modifier char def [FILENAME_MAX];
|
||||
#define Util_fopen(filename, mode, tmpbuf) (tmpbuf[0] = '\0', fopen(filename, mode))
|
||||
#define Util_tmpopen(tmpbuf) Util_uniqopen(tmpbuf, "wb+")
|
||||
#define Util_fclose(fp, tmpbuf) (fclose(fp), tmpbuf[0] != '\0' && Util_unlink(tmpbuf))
|
||||
#else
|
||||
/* if we can't delete the created file, leave it to the user */
|
||||
#define Util_tmpbufdef(modifier, def)
|
||||
#define Util_fopen(filename, mode, tmpbuf) fopen(filename, mode)
|
||||
#define Util_tmpopen(tmpbuf) Util_uniqopen(NULL, "wb+")
|
||||
#define Util_fclose(fp, tmpbuf) fclose(fp)
|
||||
#endif
|
||||
|
||||
#endif /* UTIL_H_ */
|
||||
@@ -1,470 +0,0 @@
|
||||
/* License note by perry_m:
|
||||
Permission has been granted by the authors Mike Coates and Tom Haukap
|
||||
to distribute this file under the terms of the GNU GPL license of Atari800.
|
||||
The original version written by Mike Coates is from MAME.
|
||||
This extensively modified version with new samples and mixing written
|
||||
by Tom Haukap is from PinMAME.
|
||||
I have also made modifications to this file for use in Atari800 and
|
||||
allow any modifications to be distributed under any of the licenses
|
||||
of Atari800, MAME and PinMAME. */
|
||||
|
||||
/**************************************************************************
|
||||
|
||||
Votrax SC-01 Emulator
|
||||
|
||||
Mike@Dissfulfils.co.uk
|
||||
Tom.Haukap@t-online.de
|
||||
modified for Atari800 by perry_m@fastmail.fm
|
||||
|
||||
**************************************************************************
|
||||
|
||||
Votrax_Start - Start emulation, load samples from Votrax subdirectory
|
||||
Votrax_Stop - End emulation, free memory used for samples
|
||||
Votrax_PutByte - Write data to votrax port
|
||||
Votrax_GetStatus - Return busy status (1 = busy)
|
||||
|
||||
**************************************************************************/
|
||||
|
||||
#ifdef PBI_DEBUG
|
||||
#define VERBOSE 1
|
||||
#endif
|
||||
|
||||
#if VERBOSE
|
||||
#define LOG(x) printf x
|
||||
#else
|
||||
#define LOG(x)
|
||||
#endif
|
||||
|
||||
#include "votrax.h"
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "util.h"
|
||||
|
||||
static struct {
|
||||
int busy;
|
||||
|
||||
int actPhoneme;
|
||||
int actIntonation;
|
||||
|
||||
struct Votrax_interface *intf;
|
||||
|
||||
SWORD* pActPos;
|
||||
int iRemainingSamples;
|
||||
|
||||
SWORD *lpBuffer;
|
||||
SWORD* pBufferPos;
|
||||
|
||||
int iSamplesInBuffer;
|
||||
int iDelay; /* a count of samples to output '0' in a Delay state */
|
||||
|
||||
} votraxsc01_locals;
|
||||
|
||||
#define INT16 SWORD
|
||||
#define UINT16 UWORD
|
||||
#include "vtxsmpls.inc"
|
||||
|
||||
#if VERBOSE
|
||||
static const char *PhonemeNames[65] =
|
||||
{
|
||||
"EH3","EH2","EH1","PA0","DT" ,"A2" ,"A1" ,"ZH",
|
||||
"AH2","I3" ,"I2" ,"I1" ,"M" ,"N" ,"B" ,"V",
|
||||
"CH" ,"SH" ,"Z" ,"AW1","NG" ,"AH1","OO1","OO",
|
||||
"L" ,"K" ,"J" ,"H" ,"G" ,"F" ,"D" ,"S",
|
||||
"A" ,"AY" ,"Y1" ,"UH3","AH" ,"P" ,"O" ,"I",
|
||||
"U" ,"Y" ,"T" ,"R" ,"E" ,"W" ,"AE" ,"AE1",
|
||||
"AW2","UH2","UH1","UH" ,"O2" ,"O1" ,"IU" ,"U1",
|
||||
"THV","TH" ,"ER" ,"EH" ,"E1" ,"AW" ,"PA1","STOP",
|
||||
0
|
||||
};
|
||||
#endif
|
||||
|
||||
/* phoneme types*/
|
||||
#define PT_NS 0
|
||||
#define PT_V 1
|
||||
#define PT_VF 2
|
||||
#define PT_F 3
|
||||
#define PT_N 4
|
||||
#define PT_VS 5
|
||||
#define PT_FS 6
|
||||
|
||||
|
||||
static int sample_rate[4] = {22050, 22050, 22050, 22050};
|
||||
|
||||
/* converts milliseconds to a count of samples */
|
||||
static int time_to_samples(int ms)
|
||||
{
|
||||
return sample_rate[votraxsc01_locals.actIntonation]*ms/1000;
|
||||
}
|
||||
|
||||
static void PrepareVoiceData(int nextPhoneme, int nextIntonation)
|
||||
{
|
||||
int iNextRemainingSamples;
|
||||
SWORD *pNextPos, *lpHelp;
|
||||
|
||||
int iFadeOutSamples;
|
||||
int iFadeOutPos;
|
||||
|
||||
int iFadeInSamples;
|
||||
int iFadeInPos;
|
||||
|
||||
int doMix;
|
||||
/* used only for SecondStart phonemes */
|
||||
int AdditionalSamples;
|
||||
/* dwCount is the length of samples to produce in ms from iLengthms */
|
||||
int dwCount, i;
|
||||
|
||||
SWORD data;
|
||||
|
||||
AdditionalSamples = 0;
|
||||
/* some phonenemes have a SecondStart */
|
||||
if ( PhonemeData[votraxsc01_locals.actPhoneme].iType>=PT_VS && votraxsc01_locals.actPhoneme!=nextPhoneme ) {
|
||||
AdditionalSamples = PhonemeData[votraxsc01_locals.actPhoneme].iSecondStart;
|
||||
}
|
||||
|
||||
if ( PhonemeData[nextPhoneme].iType>=PT_VS ) {
|
||||
/* 'stop phonemes' will stop playing until the next phoneme is sent*/
|
||||
votraxsc01_locals.iRemainingSamples = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* length of samples to produce*/
|
||||
dwCount = time_to_samples(PhonemeData[nextPhoneme].iLengthms);
|
||||
|
||||
votraxsc01_locals.iSamplesInBuffer = dwCount+AdditionalSamples;
|
||||
|
||||
if ( AdditionalSamples )
|
||||
memcpy(votraxsc01_locals.lpBuffer, PhonemeData[votraxsc01_locals.actPhoneme].lpStart[votraxsc01_locals.actIntonation], AdditionalSamples*sizeof(SWORD));
|
||||
|
||||
lpHelp = votraxsc01_locals.lpBuffer + AdditionalSamples;
|
||||
|
||||
iNextRemainingSamples = 0;
|
||||
pNextPos = NULL;
|
||||
|
||||
iFadeOutSamples = 0;
|
||||
iFadeOutPos = 0;
|
||||
|
||||
iFadeInSamples = 0;
|
||||
iFadeInPos = 0;
|
||||
|
||||
doMix = 0;
|
||||
|
||||
/* set up processing*/
|
||||
if ( PhonemeData[votraxsc01_locals.actPhoneme].sameAs!=PhonemeData[nextPhoneme].sameAs ) {
|
||||
/* do something, if they are the same all FadeIn/Out values are 0, */
|
||||
/* the buffer is simply filled with the samples of the new phoneme */
|
||||
|
||||
switch ( PhonemeData[votraxsc01_locals.actPhoneme].iType ) {
|
||||
case PT_NS:
|
||||
/* "fade" out NS:*/
|
||||
iFadeOutSamples = time_to_samples(30);
|
||||
iFadeOutPos = 0;
|
||||
|
||||
/* fade in new phoneme*/
|
||||
iFadeInPos = -time_to_samples(30);
|
||||
iFadeInSamples = time_to_samples(30);
|
||||
break;
|
||||
|
||||
case PT_V:
|
||||
case PT_VF:
|
||||
switch ( PhonemeData[nextPhoneme].iType ){
|
||||
case PT_F:
|
||||
case PT_VF:
|
||||
/* V-->F, V-->VF: fade out 30 ms fade in from 30 ms to 60 ms without mixing*/
|
||||
iFadeOutPos = 0;
|
||||
iFadeOutSamples = time_to_samples(30);
|
||||
|
||||
iFadeInPos = -time_to_samples(30);
|
||||
iFadeInSamples = time_to_samples(30);
|
||||
break;
|
||||
|
||||
case PT_N:
|
||||
/* V-->N: fade out 40 ms fade from 0 ms to 40 ms without mixing*/
|
||||
iFadeOutPos = 0;
|
||||
iFadeOutSamples = time_to_samples(40);
|
||||
|
||||
iFadeInPos = -time_to_samples(10);
|
||||
iFadeInSamples = time_to_samples(10);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* fade out 20 ms, no fade in from 10 ms to 30 ms*/
|
||||
iFadeOutPos = 0;
|
||||
iFadeOutSamples = time_to_samples(20);
|
||||
|
||||
iFadeInPos = -time_to_samples(0);
|
||||
iFadeInSamples = time_to_samples(20);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case PT_N:
|
||||
switch ( PhonemeData[nextPhoneme].iType ){
|
||||
case PT_V:
|
||||
case PT_VF:
|
||||
/* N-->V, N-->VF: fade out 30 ms fade in from 10 ms to 50 ms without mixing*/
|
||||
iFadeOutPos = 0;
|
||||
iFadeOutSamples = time_to_samples(30);
|
||||
|
||||
iFadeInPos = -time_to_samples(10);
|
||||
iFadeInSamples = time_to_samples(40);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case PT_VS:
|
||||
case PT_FS:
|
||||
iFadeOutPos = 0;
|
||||
iFadeOutSamples = PhonemeData[votraxsc01_locals.actPhoneme].iLength[votraxsc01_locals.actIntonation] - PhonemeData[votraxsc01_locals.actPhoneme].iSecondStart;
|
||||
votraxsc01_locals.pActPos = PhonemeData[votraxsc01_locals.actPhoneme].lpStart[votraxsc01_locals.actIntonation] + PhonemeData[votraxsc01_locals.actPhoneme].iSecondStart;
|
||||
votraxsc01_locals.iRemainingSamples = iFadeOutSamples;
|
||||
doMix = 1;
|
||||
|
||||
iFadeInPos = -time_to_samples(0);
|
||||
iFadeInSamples = time_to_samples(0);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
/* fade out 30 ms, no fade in*/
|
||||
iFadeOutPos = 0;
|
||||
iFadeOutSamples = time_to_samples(20);
|
||||
|
||||
iFadeInPos = -time_to_samples(20);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !votraxsc01_locals.iDelay ) {
|
||||
/* this is true if after a stop and a phoneme was sent a second phoneme is sent*/
|
||||
/* during the delay time of the chip. Ignore the first phoneme data*/
|
||||
iFadeOutPos = 0;
|
||||
iFadeOutSamples = 0;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
/* the next one is of the same type as the previous one; continue to use the samples of the last phoneme*/
|
||||
iNextRemainingSamples = votraxsc01_locals.iRemainingSamples;
|
||||
pNextPos = votraxsc01_locals.pActPos;
|
||||
}
|
||||
|
||||
for (i=0; i<dwCount; i++)
|
||||
{
|
||||
data = 0x00;
|
||||
|
||||
/* fade out*/
|
||||
if ( iFadeOutPos<iFadeOutSamples )
|
||||
{
|
||||
double dFadeOut = 1.0;
|
||||
|
||||
if ( !doMix )
|
||||
dFadeOut = 1.0-sin((1.0*iFadeOutPos/iFadeOutSamples)*3.1415/2);
|
||||
|
||||
if ( !votraxsc01_locals.iRemainingSamples ) {
|
||||
votraxsc01_locals.iRemainingSamples = PhonemeData[votraxsc01_locals.actPhoneme].iLength[votraxsc01_locals.actIntonation];
|
||||
votraxsc01_locals.pActPos = PhonemeData[votraxsc01_locals.actPhoneme].lpStart[votraxsc01_locals.actIntonation];
|
||||
}
|
||||
|
||||
data = (SWORD) (*votraxsc01_locals.pActPos++ * dFadeOut);
|
||||
|
||||
votraxsc01_locals.iRemainingSamples--;
|
||||
iFadeOutPos++;
|
||||
}
|
||||
|
||||
/* fade in or copy*/
|
||||
if ( iFadeInPos>=0 )
|
||||
{
|
||||
double dFadeIn = 1.0;
|
||||
|
||||
if ( iFadeInPos<iFadeInSamples ) {
|
||||
dFadeIn = sin((1.0*iFadeInPos/iFadeInSamples)*3.1415/2);
|
||||
iFadeInPos++;
|
||||
}
|
||||
|
||||
if ( !iNextRemainingSamples ) {
|
||||
iNextRemainingSamples = PhonemeData[nextPhoneme].iLength[nextIntonation];
|
||||
pNextPos = PhonemeData[nextPhoneme].lpStart[nextIntonation];
|
||||
}
|
||||
|
||||
data += (SWORD) (*pNextPos++ * dFadeIn);
|
||||
|
||||
iNextRemainingSamples--;
|
||||
}
|
||||
iFadeInPos++;
|
||||
|
||||
*lpHelp++ = data;
|
||||
}
|
||||
|
||||
votraxsc01_locals.pBufferPos = votraxsc01_locals.lpBuffer;
|
||||
|
||||
votraxsc01_locals.pActPos = pNextPos;
|
||||
votraxsc01_locals.iRemainingSamples = iNextRemainingSamples;
|
||||
}
|
||||
|
||||
void Votrax_PutByte(UBYTE data)
|
||||
{
|
||||
int Phoneme, Intonation;
|
||||
|
||||
Phoneme = data & 0x3F;
|
||||
Intonation = (data >> 6)&0x03;
|
||||
|
||||
#ifdef VERBOSE
|
||||
if (!votraxsc01_locals.intf) {
|
||||
LOG(("Error: votraxsc01_locals.intf not set"));
|
||||
return;
|
||||
}
|
||||
#endif /* VERBOSE */
|
||||
LOG(("Votrax SC-01: %s at intonation %d\n", PhonemeNames[Phoneme], Intonation));
|
||||
PrepareVoiceData(Phoneme, Intonation);
|
||||
|
||||
if ( votraxsc01_locals.actPhoneme==0x3f )
|
||||
votraxsc01_locals.iDelay = time_to_samples(20);
|
||||
|
||||
if ( !votraxsc01_locals.busy )
|
||||
{
|
||||
votraxsc01_locals.busy = 1;
|
||||
if ( votraxsc01_locals.intf->BusyCallback )
|
||||
(*votraxsc01_locals.intf->BusyCallback)(votraxsc01_locals.busy);
|
||||
}
|
||||
|
||||
votraxsc01_locals.actPhoneme = Phoneme;
|
||||
votraxsc01_locals.actIntonation = Intonation;
|
||||
}
|
||||
|
||||
UBYTE Votrax_GetStatus(void)
|
||||
{
|
||||
return votraxsc01_locals.busy;
|
||||
}
|
||||
|
||||
void Votrax_Update(int num, SWORD *buffer, int length)
|
||||
{
|
||||
int samplesToCopy;
|
||||
|
||||
/* if it is a different intonation */
|
||||
if ( num!=votraxsc01_locals.actIntonation ) {
|
||||
/* clear buffer */
|
||||
memset(buffer, 0x00, length*sizeof(SWORD));
|
||||
return;
|
||||
}
|
||||
|
||||
while ( length ) {
|
||||
/* Case 1: if in a delay state, output 0's*/
|
||||
if ( votraxsc01_locals.iDelay ) {
|
||||
samplesToCopy = (length<=votraxsc01_locals.iDelay)?length:votraxsc01_locals.iDelay;
|
||||
|
||||
memset(buffer, 0x00, samplesToCopy*sizeof(SWORD));
|
||||
buffer += samplesToCopy;
|
||||
|
||||
votraxsc01_locals.iDelay -= samplesToCopy;
|
||||
length -= samplesToCopy; /* missing in the original */
|
||||
}
|
||||
/* Case 2: there are no samples left in the buffer */
|
||||
else if ( votraxsc01_locals.iSamplesInBuffer==0 ) {
|
||||
if ( votraxsc01_locals.busy ) {
|
||||
/* busy -> idle */
|
||||
votraxsc01_locals.busy = 0;
|
||||
if ( votraxsc01_locals.intf->BusyCallback )
|
||||
(*votraxsc01_locals.intf->BusyCallback)(votraxsc01_locals.busy);
|
||||
}
|
||||
|
||||
if ( votraxsc01_locals.iRemainingSamples==0 ) {
|
||||
if ( PhonemeData[votraxsc01_locals.actPhoneme].iType>=PT_VS ) {
|
||||
votraxsc01_locals.pActPos = PhonemeData[0x3f].lpStart[0];
|
||||
votraxsc01_locals.iRemainingSamples = PhonemeData[0x3f].iLength[0];
|
||||
}
|
||||
else {
|
||||
votraxsc01_locals.pActPos = PhonemeData[votraxsc01_locals.actPhoneme].lpStart[votraxsc01_locals.actIntonation];
|
||||
votraxsc01_locals.iRemainingSamples = PhonemeData[votraxsc01_locals.actPhoneme].iLength[votraxsc01_locals.actIntonation];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* if there aren't enough remaining, reduce the amount */
|
||||
samplesToCopy = (length<=votraxsc01_locals.iRemainingSamples)?length:votraxsc01_locals.iRemainingSamples;
|
||||
|
||||
memcpy(buffer, votraxsc01_locals.pActPos, samplesToCopy*sizeof(SWORD));
|
||||
buffer += samplesToCopy;
|
||||
|
||||
votraxsc01_locals.pActPos += samplesToCopy;
|
||||
votraxsc01_locals.iRemainingSamples -= samplesToCopy;
|
||||
|
||||
length -= samplesToCopy;
|
||||
}
|
||||
/* Case 3: output the samples in the buffer */
|
||||
else {
|
||||
samplesToCopy = (length<=votraxsc01_locals.iSamplesInBuffer)?length:votraxsc01_locals.iSamplesInBuffer;
|
||||
|
||||
memcpy(buffer, votraxsc01_locals.pBufferPos, samplesToCopy*sizeof(SWORD));
|
||||
buffer += samplesToCopy;
|
||||
|
||||
votraxsc01_locals.pBufferPos += samplesToCopy;
|
||||
votraxsc01_locals.iSamplesInBuffer -= samplesToCopy;
|
||||
|
||||
length -= samplesToCopy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Votrax_Start(void *sound_interface)
|
||||
{
|
||||
int i, buffer_size;
|
||||
/* clear local variables */
|
||||
memset(&votraxsc01_locals, 0x00, sizeof votraxsc01_locals);
|
||||
|
||||
/* copy interface */
|
||||
votraxsc01_locals.intf = (struct Votrax_interface *)sound_interface;
|
||||
|
||||
votraxsc01_locals.actPhoneme = 0x3f;
|
||||
|
||||
/* find the largest possible size of iSamplesInBuffer */
|
||||
buffer_size = 0;
|
||||
for (i = 0; i <= 0x3f; i++) {
|
||||
int dwCount;
|
||||
int size;
|
||||
int AdditionalSamples;
|
||||
AdditionalSamples = PhonemeData[i].iSecondStart;
|
||||
dwCount = time_to_samples(PhonemeData[i].iLengthms);
|
||||
size = dwCount + AdditionalSamples;
|
||||
if (size > buffer_size) buffer_size = size;
|
||||
}
|
||||
votraxsc01_locals.lpBuffer = (SWORD*) Util_malloc(buffer_size*sizeof(SWORD));
|
||||
PrepareVoiceData(votraxsc01_locals.actPhoneme, votraxsc01_locals.actIntonation);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Votrax_Stop(void)
|
||||
{
|
||||
if ( votraxsc01_locals.lpBuffer ) {
|
||||
free(votraxsc01_locals.lpBuffer);
|
||||
votraxsc01_locals.lpBuffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int Votrax_Samples(int currentP, int nextP, int cursamples)
|
||||
{
|
||||
int AdditionalSamples = 0;
|
||||
int dwCount;
|
||||
int delay = 0;
|
||||
/* some phonemes have a SecondStart */
|
||||
if ( PhonemeData[currentP].iType>=PT_VS && currentP!=nextP) {
|
||||
AdditionalSamples = PhonemeData[currentP].iSecondStart;
|
||||
}
|
||||
|
||||
if ( PhonemeData[nextP].iType>=PT_VS ) {
|
||||
/* 'stop phonemes' will stop playing until the next phoneme is sent*/
|
||||
/* votraxsc01_locals.iRemainingSamples = 0; */
|
||||
return cursamples;
|
||||
}
|
||||
if (currentP == 0x3f) delay = time_to_samples(20);
|
||||
|
||||
/* length of samples to produce*/
|
||||
dwCount = time_to_samples(PhonemeData[nextP].iLengthms);
|
||||
return dwCount + AdditionalSamples + delay ;
|
||||
}
|
||||
|
||||
/*
|
||||
vim:ts=4:sw=4:
|
||||
*/
|
||||
@@ -1,23 +0,0 @@
|
||||
#ifndef VOTRAX_H_
|
||||
#define VOTRAX_H_
|
||||
|
||||
#include "atari.h"
|
||||
|
||||
typedef void (*Votrax_BusyCallBack)(int);
|
||||
|
||||
struct Votrax_interface
|
||||
{
|
||||
int num; /* total number of chips */
|
||||
Votrax_BusyCallBack BusyCallback; /* callback function when busy signal changes */
|
||||
};
|
||||
|
||||
int Votrax_Start(void *sound_interface);
|
||||
void Votrax_Stop(void);
|
||||
|
||||
void Votrax_PutByte(UBYTE data);
|
||||
UBYTE Votrax_GetStatus(void);
|
||||
|
||||
void Votrax_Update(int num, SWORD *buffer, int length);
|
||||
int Votrax_Samples(int currentP, int nextP, int cursamples);
|
||||
|
||||
#endif /* VOTRAX_H_ */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user