This commit was generated by cvs2svn to compensate for changes in r6,

which included commits to RCS files with non-trunk default branches.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@7 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
bwmott 2001-12-27 19:54:36 +00:00
parent 1dbf9ae846
commit b87826ae62
118 changed files with 39946 additions and 0 deletions

82
stella/Announce.txt Normal file
View File

@ -0,0 +1,82 @@
===============================================================================
SSSS tt lll lll
SS SS tt ll ll
SS tttttt eeee ll ll aaaa
SSSS tt ee ee ll ll aa
SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
SS SS tt ee ll ll aa aa
SSSS ttt eeeee llll llll aaaaa
===============================================================================
Release 1.1 for DOS, Linux, and Unix
===============================================================================
The Atari 2600 Video Computer System (VCS), introduced in 1977, was the most
popular home video game system of the early 1980's. Now you can enjoy all of
your favorite Atari 2600 games on your PC thanks to Stella!
Stella is a multi-platform Atari 2600 VCS emulator written in C++. Stella
allows you to play most of the games written for the Atari 2600 including
Supercharger games.
This is the 1.1 release of Stella for DOS, Linux, and Unix. Distributions
for other operating systems will appear as they become available. The three
distributions currently available are:
* Binary distribution for Linux (stella-1.1-linux-x86.tar.gz)
* Binary distribution for DOS (st11.zip)
* Source code distribution for Unix and DOS (stella-1.1-src.tar.gz)
A few 2600 ROM images, BIN files, are included with these distributions.
BEYOND THESE FILES NONE OF THE DISTRIBUTIONS CONTAIN ANY 2600 ROM IMAGES.
PLEASE DON'T WRITE ASKING FOR ROMS BECAUSE THEY ARE COPYRIGHTED! If you
own any of the Atari 2600 Action Packs by Activision you can use the ROM
images from them with Stella.
New in this Release
===================
* DOS and Linux versions support real Atari 2600 paddles using a
special PC game port adaptor
* Linux version uses the new 1.2.x joystick driver API
* Added support for the "-display" option to the X Window version
* Added support for private colormaps to the X Window version
* Fixed a few bugs in the Supercharger emulation
- A major bug in the ROM loading routine was fixed
- Multi-loading in "Escape from the Mindmaster" works correctly
- All Supercharger games load and execute at this point
* Added a small hack to the TIA code to fix a display problem in "Escape
from the Mindmaster"
* Improved TIA emulation to support the RESPx multi-sprite trick
Distribution Site
=================
The Stella distributions can be obtained from the Stella home page at:
http://stella.atari.org
If for some reason you are unable to connect to this page please try
again later or try http://www4.ncsu.edu/~bwmott/2600/.
Contacts
========
If you have any questions regarding Stella send mail to:
Bradford W. Mott (bwmott@acm.org)
Have Fun!

177
stella/Changes.txt Normal file
View File

@ -0,0 +1,177 @@
===============================================================================
SSSS tt lll lll
SS SS tt ll ll
SS tttttt eeee ll ll aaaa
SSSS tt ee ee ll ll aa
SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
SS SS tt ee ll ll aa aa
SSSS ttt eeeee llll llll aaaaa
===============================================================================
Release History
===============================================================================
1.0 to 1.1: (February 26, 1999)
* DOS and Linux versions support real Atari 2600 paddles using a
special PC game port adaptor
* Linux version uses the new 1.2.x joystick driver API
* Added support for the "-display" option to the X Window version
* Added support for private colormaps to the X Window version
* Fixed a few bugs in the Supercharger emulation
- A major bug in the ROM loading routine was fixed
- Multi-loading in "Escape from the Mindmaster" works correctly
- All Supercharger games load and execute at this point
* Added a small hack to the TIA code to fix a display problem in "Escape
from the Mindmaster"
* Improved TIA emulation to support the RESPx multi-sprite trick
1.0b1 to 1.0: (October 7, 1998)
* DOS version supports 320x200 and 320x240 graphics modes
* Several portability issues have been resolved
* Preliminary support for Chris Wilkson's Megacart bank-switching scheme
* BSDI target included in makefile
* Improved Users Manual in several "popular" formats
0.7 to 1.0b1: (July 25, 1998)
* Supports the following controllers:
Joysticks, Paddles, Booster-Grip, Keyboard and Driving
* Supports the following bank switching methods:
2K, 3F, 4K, AR, E0, E7, F4SC, F6, F8, F8SC, FASC, FE
* Properties are associated with games using their MD5 checksum
calculated on the entire ROM image
* Uses the new 'stella.pro' file format for game properties
* Includes Erik's latest stella.pro properties file
* New frame rate throttle code for X windows GUI
* Based on the new and improved M6502 CPU emulation
* Improvements to TIA emulation
- Support HMOVE blanks
- Improved Cosmic Ark star field effect
- Some support for the RESPx multiple sprite trick
- Support NTSC and PAL palettes
* Improvements to PIA emulation (timing)
* Improved Supercharger emulation
0.6 to 0.7: (June 7, 1997)
* Improved emulation speed of TIA and 6507
* Added Starpath Supercharger support
* Added Tigervision bank-switching support (3F bank-switching)
* Added pause game feature for Unix and DOS
* VCS files combined into a single builtin property file
* Added TIA HMOVE "feature" to support Cosmic Ark stars
* Improved TIA VSYNC code so that it works more like the real
thing (0.6 VSYNC code caused the graphics of some games to
be off such as Alien and Battle Zone)
* Added two 6507 emulators: one is designed to act more like
the real thing, while the other is designed to be as fast as
possible (required for Supercharger support)
* Changed TIA peeking so lower nibble of byte read is the same
as the TIA address being accessed (Warlords now works)
0.5 to 0.6: (January 18, 1997)
* Fixed collision detection problem (Freeway works)
* Changed PIA timing code to fix screen jitters
* Added new bank-switching methods: F4SC (Fatal Run), E7 (Burgertime)
* Fixed some code in the TIA emulation that caused SEGFAULTS
* Improved frame rate throttling code to work better on fast machines
* Improved TIA emulation (missle graphics are fully emulated now)
* Included Bob Colbert's "Okie Dokie" game
* Uses version 1.1 of the TIA Sound library by Ron Fries
0.4 to 0.5: (November 17, 1996)
* Added sound support
* Added new bank-switching methods: F8SC (Defender II), FASC (CBS RAM+)
* Changed TIA so peeking $E and $F return $F not $0 for Haunted House
* Changed PIA timing code to fix screen jitters in Frogger
* Addressing scheme rewritten
* Optimized 6507 memory accesses
* Randomized memory in PIA upon startup
* Removed auto-disabling of objects at the start of a frame
so you can't walk through walls in Adventure
* Changed the X windows terminal update method to make it faster and
easier to understand
0.3 to 0.4 (August 28, 1996):
* TIA code has been optimized some
* Some games can be played with just a ROM image
* New search method for ROM images (no more STELLA_PATH)
* Delta screen update supported
* Better error handling added to the "core"
0.2 to 0.3 (July 12, 1996):
* Keyboard joystick support is much better (Daniel Marks)
* Paddles are now supported via the mouse (Bradford Mott)
* Many portability issues have been resolved (Keith Wilkins)
* Fixed a problem with the 6507 ADC and SBC instructions that caused
some games (Enduro) not to work correctly (Bradford Mott)
* Power Macintosh port (Aaron Giles)
* Windows 95 & NT port (Jeff Miller)

37
stella/Copyright.txt Normal file
View File

@ -0,0 +1,37 @@
===============================================================================
SSSS tt lll lll
SS SS tt ll ll
SS tttttt eeee ll ll aaaa
SSSS tt ee ee ll ll aa
SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
SS SS tt ee ll ll aa aa
SSSS ttt eeeee llll llll aaaaa
===============================================================================
License Information and Copyright Notice
===============================================================================
Copyright (C) 1995-2002 Bradford W. Mott <bwmott@acm.org>
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 any later version.
You should have received a copy of the GNU General Public License version 2
along with this program (License.txt); if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES
THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

339
stella/License.txt Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111 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
Appendix: 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) 19yy <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., 59 Temple Place, Suite 330, Boston, MA 02111 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) 19yy 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.

13
stella/Readme.txt Normal file
View File

@ -0,0 +1,13 @@
This is release 1.1 of Stella. You'll find the Stella Users Manual in
the docs subdirectory. If you'd like to verify that you have the latest
release of Stella visit the web site at:
http://stella.atari.org
If you find any problems please let me know.
Bradford W. Mott
February 26, 1999
bwmott@acm.org

39
stella/Todo.txt Normal file
View File

@ -0,0 +1,39 @@
===============================================================================
SSSS tt lll lll
SS SS tt ll ll
SS tttttt eeee ll ll aaaa
SSSS tt ee ee ll ll aa
SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
SS SS tt ee ll ll aa aa
SSSS ttt eeeee llll llll aaaaa
===============================================================================
To Do List - October 2, 1998
===============================================================================
If you would like to contribute to Stella's development then find something
on the list below and send email to Bradford Mott at bwmott@acm.org.
* Provide suggestions for improving Stella
* Provide suggestions for improving the Stella Users Manual
* Port Stella to other operating systems:
- Atari ST/TT/Falcon
- Mac (680x0)
- Others...
* Port the OSS stella-sound program, for Linux, to other versions of Unix
* Add a built-in game menu to the DOS version of Stella
* Find out if the Pro Audio Spectrum sound card is supported by the
DOS version of Stella (if not then add support for this card)
* Add support for real Atari controllers to the DOS version of Stella
(this will involve hardware as well as software)
* Add a debugger to Stella for game developers

File diff suppressed because it is too large Load Diff

3194
stella/src/build/M6502Hi.ins Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

319
stella/src/build/makefile Normal file
View File

@ -0,0 +1,319 @@
##============================================================================
##
## SSSS tt lll lll
## SS SS tt ll ll
## SS tttttt eeee ll ll aaaa
## SSSS tt ee ee ll ll aa
## SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
## SS SS tt ee ll ll aa aa
## SSSS ttt eeeee llll llll aaaaa
##
## Copyright (c) 1995-1999 by Bradford W. Mott
##
## See the file "license" for information on usage and redistribution of
## this file, and for a DISCLAIMER OF ALL WARRANTIES.
##
## $Id: makefile,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
##============================================================================
##============================================================================
##
## The following options are used during compiling. You may need to
## define some of these on the CXXFLAGS line if you're running on an
## "unsupported" system
##
## -DBSPF_BOOL if your C++ compiler doesn't support the bool type
##
## -DSHOW_TIMING if your want some timing information displayed when
## you exit the program
##
## -DDEBUG if you want a 6507 trace written to stdout
##
## -DLINUX_JOYSTICK to include linux joystick driver support
## (requires you to install the joystick kernel module)
##
##============================================================================
CXX = g++
LD = g++
LDFLAGS =
LDLIBS =
SRC = ..
CORE = $(SRC)/emucore
UI = $(SRC)/ui
INCLUDES = -I. -I$(CORE) -I$(CORE)/m6502/src -I$(CORE)/m6502/src/bspf/src
CXXFLAGS = -O -Wall $(INCLUDES) $(SYS_INCLUDES)
default:
@echo ""
@echo "To build Stella type: 'make <version>'"
@echo ""
@echo "where <version> is one of:"
@echo ""
@echo " dos DOS version using DJGPP"
@echo " unix-x Generic Unix X windows version"
@echo " linux-x Linux X windows version"
@echo " linux-x-joy Linux X windows version with joystick"
@echo " bsdi-x BSD/OS 4.0 X Windows version"
@echo " solaris-x Solaris X windows version"
@echo ""
@echo "Hopefully new versions will be added soon!"
@echo ""
dos:
make stella.exe \
LD="gxx" \
CXX="gcc" \
INCLUDES="$(INCLUDES) -I$(UI)/dos -I$(UI)/sound" \
OPTIONS="-DBSPF_DOS" \
LDFLAGS="" \
LDLIBS="" \
OBJS="mainDOS.o PCJoys.o SndDOS.o sbdrv.o TIASound.o"
unix-x:
make xstella \
INCLUDES="$(INCLUDES) -I$(UI)/x11 -I$(UI)/sound" \
SYS_INCLUDES="" \
OPTIONS="-DBSPF_UNIX" \
LDFLAGS="-L/usr/X11R6/lib" \
LDLIBS="-lX11 -lXext" \
OBJS="mainX11.o SndUnix.o"
linux-x:
make xstella \
INCLUDES="$(INCLUDES) -I$(UI)/x11 -I$(UI)/sound" \
SYS_INCLUDES="" \
OPTIONS="-DBSPF_UNIX" \
LDFLAGS="-L/usr/X11R6/lib" \
LDLIBS="-lX11 -lXext" \
OBJS="mainX11.o SndUnix.o"
linux-x-joy:
make xstella \
INCLUDES="$(INCLUDES) -I$(UI)/x11 -I$(UI)/sound" \
SYS_INCLUDES="" \
OPTIONS="-DBSPF_UNIX -DLINUX_JOYSTICK" \
LDFLAGS="-L/usr/X11R6/lib" \
LDLIBS="-lX11 -lXext" \
OBJS="mainX11.o SndUnix.o"
bsdi-x:
make xstella \
INCLUDES="$(INCLUDES) -I$(UI)/x11 -I$(UI)/sound" \
SYS_INCLUDES="-I/usr/X11R6/include" \
OPTIONS="-DBSPF_UNIX" \
LDFLAGS="-L/usr/X11R6/lib" \
LDLIBS="-lX11 -lXext" \
OBJS="mainX11.o SndUnix.o"
solaris-x:
make xstella \
INCLUDES="$(INCLUDES) -I$(UI)/x11 -I$(UI)/sound" \
SYS_INCLUDES="-I/usr/openwin/include" \
OPTIONS="-DBSPF_UNIX" \
LDFLAGS="-L/usr/openwin/lib" \
LDLIBS="-lX11 -lXext" \
OBJS="mainX11.o SndUnix.o"
###############################################################################
## List of "core" object files
###############################################################################
M6502_OBJS = D6502.o Device.o M6502.o M6502Low.o M6502Hi.o NullDev.o System.o
CORE_OBJS = Booster.o Cart.o Cart2K.o Cart3F.o Cart4K.o CartAR.o CartE0.o \
CartE7.o CartF4SC.o CartF6.o CartF6SC.o CartF8.o CartF8SC.o \
CartFASC.o CartFE.o CartMC.o Console.o \
Control.o DefProps.o Driving.o \
Event.o Joystick.o Keyboard.o M6532.o MD5.o MediaSrc.o Paddles.o \
Props.o PropsSet.o Random.o Sound.o Switches.o TIA.o \
$(M6502_OBJS)
stella.exe: $(CORE_OBJS) $(OBJS)
$(LD) -o a.exe *.o $(LDFLAGS) $(LDLIBS)
exe2coff a.exe
strip a
copy /B \djgpp\bin\pmodstub.exe + a stella.exe
del a
del a.exe
xstella: $(CORE_OBJS) $(OBJS)
$(LD) -o xstella $(CORE_OBJS) $(OBJS) $(LDFLAGS) $(LDLIBS)
M6502Low.ins: $(CORE)/m6502/src/M6502Low.m4 $(CORE)/m6502/src/M6502.m4
m4 $(CORE)/m6502/src/M6502Low.m4 $(CORE)/m6502/src/M6502.m4 > M6502Low.ins
M6502Hi.ins: $(CORE)/m6502/src/M6502Hi.m4 $(CORE)/m6502/src/M6502.m4
m4 $(CORE)/m6502/src/M6502Hi.m4 $(CORE)/m6502/src/M6502.m4 > M6502Hi.ins
DefProps.def: $(CORE)/stella.pro
sed 's/"/\\\"/g;s/^/"/g;s/$$/",/g' $(CORE)/stella.pro > DefProps.def
DefProps.o: DefProps.def
M6502Low.o: M6502Low.ins
M6502Hi.o: M6502Hi.ins
cleandos:
del *.o
del stella.exe
del DefProps.def
del M6502Low.ins
del M6502Hi.ins
clean:
rm -f *.o stella xstella stella.exe core
cleanall: clean
rm -f DefProps.def M6502Low.ins M6502Hi.ins
Driving.o: $(CORE)/Driving.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Driving.cxx
Event.o: $(CORE)/Event.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Event.cxx
Control.o: $(CORE)/Control.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Control.cxx
Joystick.o: $(CORE)/Joystick.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Joystick.cxx
Keyboard.o: $(CORE)/Keyboard.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Keyboard.cxx
Paddles.o: $(CORE)/Paddles.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Paddles.cxx
Booster.o: $(CORE)/Booster.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Booster.cxx
Cart.o: $(CORE)/Cart.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Cart.cxx
Cart2K.o: $(CORE)/Cart2K.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Cart2K.cxx
Cart3F.o: $(CORE)/Cart3F.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Cart3F.cxx
Cart4K.o: $(CORE)/Cart4K.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Cart4K.cxx
CartAR.o: $(CORE)/CartAR.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/CartAR.cxx
CartE0.o: $(CORE)/CartE0.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/CartE0.cxx
CartE7.o: $(CORE)/CartE7.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/CartE7.cxx
CartF4SC.o: $(CORE)/CartF4SC.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/CartF4SC.cxx
CartF6.o: $(CORE)/CartF6.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/CartF6.cxx
CartF6SC.o: $(CORE)/CartF6SC.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/CartF6SC.cxx
CartF8.o: $(CORE)/CartF8.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/CartF8.cxx
CartF8SC.o: $(CORE)/CartF8SC.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/CartF8SC.cxx
CartFASC.o: $(CORE)/CartFASC.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/CartFASC.cxx
CartFE.o: $(CORE)/CartFE.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/CartFE.cxx
CartMC.o: $(CORE)/CartMC.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/CartMC.cxx
DefProps.o: $(CORE)/DefProps.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/DefProps.cxx
M6532.o: $(CORE)/M6532.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/M6532.cxx
TIA.o: $(CORE)/TIA.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/TIA.cxx
Console.o: $(CORE)/Console.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Console.cxx
MD5.o: $(CORE)/MD5.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/MD5.cxx
MediaSrc.o: $(CORE)/MediaSrc.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/MediaSrc.cxx
PropsSet.o: $(CORE)/PropsSet.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/PropsSet.cxx
Props.o: $(CORE)/Props.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Props.cxx
Random.o: $(CORE)/Random.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Random.cxx
Switches.o: $(CORE)/Switches.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Switches.cxx
Sound.o: $(CORE)/Sound.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/Sound.cxx
Terminal.o: $(UI)/x11/Terminal.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/x11/Terminal.cxx
mainDOS.o: $(UI)/dos/mainDOS.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/dos/mainDOS.cxx
PCJoys.o: $(UI)/dos/PCJoys.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/dos/PCJoys.cxx
SndDOS.o: $(UI)/dos/SndDOS.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/dos/SndDOS.cxx
sbdrv.o: $(UI)/dos/sbdrv.c
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/dos/sbdrv.c
TIASound.o: $(UI)/sound/TIASound.c
$(CXX) -c -DWIN32 $(CXXFLAGS) $(OPTIONS) $(UI)/sound/TIASound.c
TermX11.o: $(UI)/x11/TermX11.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/x11/TermX11.cxx
mainX11.o: $(UI)/x11/mainX11.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/x11/mainX11.cxx
SndUnix.o: $(UI)/sound/SndUnix.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(UI)/sound/SndUnix.cxx
D6502.o: $(CORE)/m6502/src/D6502.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/m6502/src/D6502.cxx
Device.o: $(CORE)/m6502/src/Device.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/m6502/src/Device.cxx
M6502.o: $(CORE)/m6502/src/M6502.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/m6502/src/M6502.cxx
M6502Low.o: $(CORE)/m6502/src/M6502Low.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/m6502/src/M6502Low.cxx
M6502Hi.o: $(CORE)/m6502/src/M6502Hi.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/m6502/src/M6502Hi.cxx
NullDev.o: $(CORE)/m6502/src/NullDev.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/m6502/src/NullDev.cxx
System.o: $(CORE)/m6502/src/System.cxx
$(CXX) -c $(CXXFLAGS) $(OPTIONS) $(CORE)/m6502/src/System.cxx

View File

@ -0,0 +1,105 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Booster.cxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
//============================================================================
#include "Event.hxx"
#include "Booster.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BoosterGrip::BoosterGrip(Jack jack, const Event& event)
: Controller(jack, event)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BoosterGrip::~BoosterGrip()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool BoosterGrip::read(DigitalPin pin)
{
switch(pin)
{
case One:
return (myJack == Left) ? (myEvent.get(Event::JoystickZeroUp) == 0) :
(myEvent.get(Event::JoystickOneUp) == 0);
case Two:
return (myJack == Left) ? (myEvent.get(Event::JoystickZeroDown) == 0) :
(myEvent.get(Event::JoystickOneDown) == 0);
case Three:
return (myJack == Left) ? (myEvent.get(Event::JoystickZeroLeft) == 0) :
(myEvent.get(Event::JoystickOneLeft) == 0);
case Four:
return (myJack == Left) ? (myEvent.get(Event::JoystickZeroRight) == 0) :
(myEvent.get(Event::JoystickOneRight) == 0);
case Six:
return (myJack == Left) ? (myEvent.get(Event::JoystickZeroFire) == 0) :
(myEvent.get(Event::JoystickOneFire) == 0);
default:
return true;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 BoosterGrip::read(AnalogPin pin)
{
// The CBS Booster-grip has two more buttons on it. These buttons are
// connected to the inputs usually used by paddles.
switch(pin)
{
case Five:
if(myJack == Left)
{
return (myEvent.get(Event::BoosterGripZeroBooster) != 0) ?
minimumResistance : maximumResistance;
}
else
{
return (myEvent.get(Event::BoosterGripOneBooster) != 0) ?
minimumResistance : maximumResistance;
}
case Nine:
if(myJack == Left)
{
return (myEvent.get(Event::BoosterGripZeroTrigger) != 0) ?
minimumResistance : maximumResistance;
}
else
{
return (myEvent.get(Event::BoosterGripOneTrigger) != 0) ?
minimumResistance : maximumResistance;
}
default:
return maximumResistance;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void BoosterGrip::write(DigitalPin, bool)
{
// Writing doesn't do anything to the booster grip...
}

View File

@ -0,0 +1,78 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Booster.hxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
//============================================================================
#ifndef BOOSTERGRIP_HXX
#define BOOSTERGRIP_HXX
#include "bspf.hxx"
#include "Control.hxx"
/**
The standard Atari 2600 joystick controller fitted with the
CBS Booster grip. The Booster grip has two more fire buttons
on it (a booster and a trigger).
@author Bradford W. Mott
@version $Id: Booster.hxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
*/
class BoosterGrip : public Controller
{
public:
/**
Create a new booster grip joystick plugged into the specified jack
@param jack The jack the controller is plugged into
@param event The event object to use for events
*/
BoosterGrip(Jack jack, const Event& event);
/**
Destructor
*/
virtual ~BoosterGrip();
public:
/**
Read the value of the specified digital pin for this controller.
@param pin The pin of the controller jack to read
@return The state of the pin
*/
virtual bool read(DigitalPin pin);
/**
Read the resistance at the specified analog pin for this controller.
The returned value is the resistance measured in ohms.
@param pin The pin of the controller jack to read
@return The resistance at the specified pin
*/
virtual Int32 read(AnalogPin pin);
/**
Write the given value to the specified digital pin for this
controller. Writing is only allowed to the pins associated
with the PIA. Therefore you cannot write to pin six.
@param pin The pin of the controller jack to write to
@param value The value to write to the pin
*/
virtual void write(DigitalPin pin, bool value);
};
#endif

215
stella/src/emucore/Cart.cxx Normal file
View File

@ -0,0 +1,215 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Cart.cxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
//============================================================================
#include <assert.h>
#include <string.h>
#include "Cart.hxx"
#include "Cart2K.hxx"
#include "Cart3F.hxx"
#include "Cart4K.hxx"
#include "CartAR.hxx"
#include "CartE0.hxx"
#include "CartE7.hxx"
#include "CartF4SC.hxx"
#include "CartF6.hxx"
#include "CartF6SC.hxx"
#include "CartF8.hxx"
#include "CartF8SC.hxx"
#include "CartFASC.hxx"
#include "CartFE.hxx"
#include "CartMC.hxx"
#include "MD5.hxx"
#include "Props.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge* Cartridge::create(const uInt8* image, uInt32 size,
const Properties& properties)
{
Cartridge* cartridge = 0;
// Get the type of the cartridge we're creating
string type = properties.get("Cartridge.Type");
// See if we should try to auto-detect the cartridge type
if(type == "Auto-detect")
{
type = autodetectType(image, size);
}
// We should know the cart's type by now so let's create it
if(type == "2K")
cartridge = new Cartridge2K(image);
else if(type == "3F")
cartridge = new Cartridge3F(image, size);
else if(type == "4K")
cartridge = new Cartridge4K(image);
else if(type == "AR")
cartridge = new CartridgeAR(image, size);
else if(type == "E0")
cartridge = new CartridgeE0(image);
else if(type == "E7")
cartridge = new CartridgeE7(image);
else if(type == "F4SC")
cartridge = new CartridgeF4SC(image);
else if(type == "F6")
cartridge = new CartridgeF6(image);
else if(type == "F6SC")
cartridge = new CartridgeF6SC(image);
else if(type == "F8")
cartridge = new CartridgeF8(image);
else if(type == "F8SC")
cartridge = new CartridgeF8SC(image);
else if(type == "FASC")
cartridge = new CartridgeFASC(image);
else if(type == "FE")
cartridge = new CartridgeFE(image);
else if(type == "MC")
cartridge = new CartridgeMC(image, size);
else
{
// TODO: At some point this should be handled in a better way...
assert(false);
}
return cartridge;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge::Cartridge()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge::~Cartridge()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string Cartridge::autodetectType(const uInt8* image, uInt32 size)
{
// The following is a simple table mapping games to type's using MD5 values
struct MD5ToType
{
const char* md5;
const char* type;
};
static MD5ToType table[] = {
{"5336f86f6b982cc925532f2e80aa1e17", "E0"}, // Death Star
{"b311ab95e85bc0162308390728a7361d", "E0"}, // Gyruss
{"c29f8db680990cb45ef7fef6ab57a2c2", "E0"}, // Super Cobra
{"085322bae40d904f53bdcc56df0593fc", "E0"}, // Tutankamn
{"c7f13ef38f61ee2367ada94fdcc6d206", "E0"}, // Popeye
{"6339d28c9a7f92054e70029eb0375837", "E0"}, // Star Wars, Arcade
{"27c6a2ca16ad7d814626ceea62fa8fb4", "E0"}, // Frogger II
{"3347a6dd59049b15a38394aa2dafa585", "E0"}, // Montezuma's Revenge
{"6dda84fb8e442ecf34241ac0d1d91d69", "F6SC"}, // Dig Dug
{"57fa2d09c9e361de7bd2aa3a9575a760", "F8SC"}, // Stargate
{"3a771876e4b61d42e3a3892ad885d889", "F8SC"}, // Defender ][
{"efefc02bbc5258815457f7a5b8d8750a", "FASC"}, // Tunnel runner
{"7e51a58de2c0db7d33715f518893b0db", "FASC"}, // Mountain King
{"9947f1ebabb56fd075a96c6d37351efa", "FASC"}, // Omega Race
{"0443cfa9872cdb49069186413275fa21", "E7"}, // Burger Timer
{"76f53abbbf39a0063f24036d6ee0968a", "E7"}, // Bump-N-Jump
{"3b76242691730b2dd22ec0ceab351bc6", "E7"}, // He-Man
{"ac7c2260378975614192ca2bc3d20e0b", "FE"}, // Decathlon
{"4f618c2429138e0280969193ed6c107e", "FE"}, // Robot Tank
{(char*)0, (char*)0}
};
// Get the MD5 message-digest for the ROM image
string md5 = MD5(image, size);
// Take a closer look at the ROM image and try to figure out its type
const char* type = 0;
// First we'll see if it's type is listed in the table above
for(MD5ToType* entry = table; (entry->md5 != 0); ++entry)
{
if(entry->md5 == md5)
{
type = entry->type;
break;
}
}
// If we didn't find the type in the table then guess it based on size
if(type == 0)
{
if((size % 8448) == 0)
{
type = "AR";
}
else if((size == 2048) || (memcmp(image, image + 2048, 2048) == 0))
{
type = "2K";
}
else if((size == 4096) || (memcmp(image, image + 4096, 4096) == 0))
{
type = "4K";
}
else if((size == 8192) || (memcmp(image, image + 8192, 8192) == 0))
{
type = "F8";
}
else if(size == 12288)
{
type = "FASC";
}
else if(size == 32768)
{
type = "F4SC";
}
else if(size == 131072)
{
type = "MC";
}
else
{
// Assume this is a 16K super-cart then check to see if it is
type = "F6SC";
uInt8 first = image[0];
for(uInt32 i = 0; i < 256; ++i)
{
if(image[i] != first)
{
// It's not a super cart (probably)
type = "F6";
break;
}
}
}
}
return type;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge::Cartridge(const Cartridge&)
{
assert(false);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge& Cartridge::operator = (const Cartridge&)
{
assert(false);
return *this;
}

View File

@ -0,0 +1,80 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Cart.hxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
//============================================================================
#ifndef CARTRIDGE_HXX
#define CARTRIDGE_HXX
class Cartridge;
class Properties;
class System;
#include "bspf.hxx"
#include "Device.hxx"
/**
A cartridge is a device which contains the machine code for a
game and handles any bankswitching performed by the cartridge.
@author Bradford W. Mott
@version $Id: Cart.hxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
*/
class Cartridge : public Device
{
public:
/**
Create a new cartridge object allocated on the heap. The
type of cartridge created depends on the properties object.
@param image A pointer to the ROM image
@param size The size of the ROM image
@param properties The properties associated with the game
@return Pointer to the new cartridge object allocated on the heap
*/
static Cartridge* create(const uInt8* image, uInt32 size,
const Properties& properties);
public:
/**
Create a new cartridge
*/
Cartridge();
/**
Destructor
*/
virtual ~Cartridge();
private:
/**
Try to auto-detect the bankswitching type of the cartridge
@param image A pointer to the ROM image
@param size The size of the ROM image
@return The "best guess" for the cartridge type
*/
static string autodetectType(const uInt8* image, uInt32 size);
private:
// Copy constructor isn't supported by cartridges so make it private
Cartridge(const Cartridge&);
// Assignment operator isn't supported by cartridges so make it private
Cartridge& operator = (const Cartridge&);
};
#endif

View File

@ -0,0 +1,82 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Cart2K.cxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
//============================================================================
#include <assert.h>
#include "Cart2K.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge2K::Cartridge2K(const uInt8* image)
{
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < 2048; ++addr)
{
myImage[addr] = image[addr];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge2K::~Cartridge2K()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* Cartridge2K::name() const
{
return "Cartridge2K";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge2K::reset()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge2K::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert((0x1000 & mask) == 0);
System::PageAccess access;
access.directPokeBase = 0;
access.device = this;
// Map ROM image into the system
for(uInt32 address = 0x1000; address < 0x2000; address += (1 << shift))
{
access.directPeekBase = &myImage[address & 0x07FF];
mySystem->setPageAccess(address >> mySystem->pageShift(), access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Cartridge2K::peek(uInt16 address)
{
return myImage[address & 0x07FF];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge2K::poke(uInt16, uInt8)
{
// This is ROM so poking has no effect :-)
}

View File

@ -0,0 +1,93 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Cart2K.hxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
//============================================================================
#ifndef CARTRIDGE2K_HXX
#define CARTRIDGE2K_HXX
class Cartridge2K;
class System;
#include "bspf.hxx"
#include "Cart.hxx"
/**
This is the standard Atari 2K cartridge. These cartridges
are not bankswitched, however, the data repeats twice in the
2600's 4K cartridge addressing space.
@author Bradford W. Mott
@version $Id: Cart2K.hxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
*/
class Cartridge2K : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
Cartridge2K(const uInt8* image);
/**
Destructor
*/
virtual ~Cartridge2K();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset cartridge to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
// The 2k ROM image for the cartridge
uInt8 myImage[2048];
};
#endif

View File

@ -0,0 +1,148 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Cart3F.cxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
//============================================================================
#include <assert.h>
#include "Cart3F.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge3F::Cartridge3F(const uInt8* image, uInt32 size)
: mySize(size)
{
// Allocate array for the ROM image
myImage = new uInt8[mySize];
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < mySize; ++addr)
{
myImage[addr] = image[addr];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge3F::~Cartridge3F()
{
delete[] myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* Cartridge3F::name() const
{
return "Cartridge3F";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge3F::reset()
{
// We'll map bank 0 into the first segment upon reset
bank(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge3F::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert((0x1800 & mask) == 0);
// Set the page accessing methods for the hot spots (for 100% emulation
// I would need to chain any accesses below 0x40 to the TIA but for
// now I'll just forget about them)
System::PageAccess access;
for(uInt32 i = 0x00; i < 0x40; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
// Setup the second segment to always point to the last ROM slice
for(uInt32 j = 0x1800; j < 0x2000; j += (1 << shift))
{
access.device = this;
access.directPeekBase = &myImage[(mySize - 2048) + (j & 0x07FF)];
access.directPokeBase = 0;
mySystem->setPageAccess(j >> shift, access);
}
// Install pages for bank 0 into the first segment
bank(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Cartridge3F::peek(uInt16 address)
{
address = address & 0x0FFF;
if(address < 0x0800)
{
return myImage[(address & 0x07FF) + myCurrentBank * 2048];
}
else
{
return myImage[(address & 0x07FF) + mySize - 2048];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge3F::poke(uInt16 address, uInt8 value)
{
address = address & 0x0FFF;
// Switch banks if necessary
if(address <= 0x003F)
{
bank(value);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge3F::bank(uInt16 bank)
{
// Make sure the bank they're asking for is reasonable
if((uInt32)bank * 2048 < mySize)
{
myCurrentBank = bank;
}
else
{
// Oops, the bank they're asking for isn't valid so let's wrap it
// around to a valid bank number
myCurrentBank = bank % (mySize / 2048);
}
uInt32 offset = myCurrentBank * 2048;
uInt16 shift = mySystem->pageShift();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
// Map ROM image into the system
for(uInt32 address = 0x1000; address < 0x1800; address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x07FF)];
mySystem->setPageAccess(address >> shift, access);
}
}

View File

@ -0,0 +1,112 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Cart3F.hxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
//============================================================================
#ifndef CARTRIDGE3F_HXX
#define CARTRIDGE3F_HXX
class Cartridge3F;
#include "bspf.hxx"
#include "Cart.hxx"
/**
This is the cartridge class for Tigervision's bankswitched
games. In this bankswitching scheme the 2600's 4K cartridge
address space is broken into two 2K segments. The last 2K
segment always points to the last 2K of the ROM image. The
desired bank number of the first 2K segment is selected by
storing its value into $3F. Actually, any write to location
$00 to $3F will change banks. Although, the Tigervision games
only used 8K this bankswitching scheme supports up to 512K.
@author Bradford W. Mott
@version $Id: Cart3F.hxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
*/
class Cartridge3F : public Cartridge
{
public:
/**
Create a new cartridge using the specified image and size
@param image Pointer to the ROM image
@param size The size of the ROM image
*/
Cartridge3F(const uInt8* image, uInt32 size);
/**
Destructor
*/
virtual ~Cartridge3F();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
/**
Map the specified bank into the first segment
@param bank The bank that should be mapped
*/
void bank(uInt16 bank);
private:
// Indicates which bank is currently active for the first segment
uInt16 myCurrentBank;
// Pointer to a dynamically allocated ROM image of the cartridge
uInt8* myImage;
// Size of the ROM image
uInt32 mySize;
};
#endif

View File

@ -0,0 +1,82 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Cart4K.cxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
//============================================================================
#include <assert.h>
#include "Cart4K.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge4K::Cartridge4K(const uInt8* image)
{
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < 4096; ++addr)
{
myImage[addr] = image[addr];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cartridge4K::~Cartridge4K()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* Cartridge4K::name() const
{
return "Cartridge4K";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge4K::reset()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge4K::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert((0x1000 & mask) == 0);
System::PageAccess access;
access.directPokeBase = 0;
access.device = this;
// Map ROM image into the system
for(uInt32 address = 0x1000; address < 0x2000; address += (1 << shift))
{
access.directPeekBase = &myImage[address & 0x0FFF];
mySystem->setPageAccess(address >> mySystem->pageShift(), access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Cartridge4K::peek(uInt16 address)
{
return myImage[address & 0x0FFF];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Cartridge4K::poke(uInt16, uInt8)
{
// This is ROM so poking has no effect :-)
}

View File

@ -0,0 +1,92 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Cart4K.hxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
//============================================================================
#ifndef CARTRIDGE4K_HXX
#define CARTRIDGE4K_HXX
class Cartridge4K;
class System;
#include "bspf.hxx"
#include "Cart.hxx"
/**
This is the standard Atari 4K cartridge. These cartridges are
not bankswitched.
@author Bradford W. Mott
@version $Id: Cart4K.hxx,v 1.1.1.1 2001-12-27 19:54:18 bwmott Exp $
*/
class Cartridge4K : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
Cartridge4K(const uInt8* image);
/**
Destructor
*/
virtual ~Cartridge4K();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset cartridge to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
// The 4K ROM image for the cartridge
uInt8 myImage[4096];
};
#endif

View File

@ -0,0 +1,420 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1999 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartAR.cxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
//============================================================================
#include <assert.h>
#include <string.h>
#include "CartAR.hxx"
#include "M6502Hi.hxx"
#include "Random.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeAR::CartridgeAR(const uInt8* image, uInt32 size)
: my6502(0)
{
uInt32 i;
// Create a load image buffer and copy the given image
myLoadImages = new uInt8[size];
myNumberOfLoadImages = size / 8448;
memcpy(myLoadImages, image, size);
// Initialize RAM with random values
Random random;
for(i = 0; i < 6 * 1024; ++i)
{
myImage[i] = random.next();
}
// Initialize ROM with an invalid 6502 opcode
for(i = 6 * 1024; i < 8 * 1024; ++i)
{
myImage[i] = 0xFF;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeAR::~CartridgeAR()
{
delete[] myLoadImages;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartridgeAR::name() const
{
return "CartridgeAR";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeAR::reset()
{
// Try to load the first load into RAM upon reset
loadIntoRAM(0);
myPower = true;
myPowerRomCycle = 0;
myWriteEnabled = false;
myLastAccess = 0;
myNumberOfDistinctAccesses = 0;
myWritePending = false;
// Set bank configuration upon reset so ROM is selected
myImageOffset[0] = 0 * 2048;
myImageOffset[1] = 3 * 2048;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeAR::systemCyclesReset()
{
// Get the current system cycle
uInt32 cycles = mySystem->cycles();
// Adjust cycle values
myPowerRomCycle -= cycles;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeAR::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
my6502 = &(M6502High&)mySystem->m6502();
// Make sure the system we're being installed in has a page size that'll work
assert((0x1000 & mask) == 0);
System::PageAccess access;
for(uInt32 i = 0x1000; i < 0x2000; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
bankConfiguration(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeAR::peek(uInt16 addr)
{
// Check to see if the Supercharger ROM is being accessed?
if(myImageOffset[1] == 3 * 2048)
{
Int32 cycles = mySystem->cycles();
// Is the tape rewind routine being accessed?
if((addr & 0x1FFF) == 0x180A)
{
// See if the ROM has been powered up long enough
if(!myPower || (myPower && ((myPowerRomCycle + 7) > cycles)))
{
cerr << "ERROR: Supercharger ROM has not been powered up!\n";
}
else
{
cerr << "ERROR: Supercharger code doesn't handle rewinding tape!\n";
}
}
// Is the multiload routine being accessed?
else if((addr & 0x1FFF) == 0x1800)
{
// See if the ROM has been powered up long enough
if(!myPower || (myPower && ((myPowerRomCycle + 7) > cycles)))
{
cerr << "ERROR: Supercharger ROM has not been powered up!\n";
}
else
{
// Get the load they're trying to access
uInt8 load = mySystem->peek(0x00FA);
// Load the specified load into RAM
loadIntoRAM(load);
return myImage[(addr & 0x07FF) + myImageOffset[1]];
}
}
}
// Are the "value" registers being accessed?
if(!(addr & 0x0F00) && (!myWriteEnabled || !myWritePending))
{
myLastAccess = addr;
myNumberOfDistinctAccesses = my6502->distinctAccesses();
myWritePending = true;
}
// Is the bank configuration hotspot being accessed?
else if((addr & 0x1FFF) == 0x1FF8)
{
// Yes, so handle bank configuration
myWritePending = false;
bankConfiguration(myLastAccess);
}
// Handle poke if writing enabled
else if(myWriteEnabled && myWritePending)
{
if(my6502->distinctAccesses() >= myNumberOfDistinctAccesses + 5)
{
if(my6502->distinctAccesses() == myNumberOfDistinctAccesses + 5)
{
if((addr & 0x0800) == 0)
myImage[(addr & 0x07FF) + myImageOffset[0]] = myLastAccess;
else if(myImageOffset[1] != 3 * 2048) // Can't poke to ROM :-)
myImage[(addr & 0x07FF) + myImageOffset[1]] = myLastAccess;
}
myWritePending = false;
}
}
return myImage[(addr & 0x07FF) + myImageOffset[(addr & 0x0800) ? 1 : 0]];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeAR::poke(uInt16 addr, uInt8)
{
// Are the "value" registers being accessed?
if(!(addr & 0x0F00) && (!myWriteEnabled || !myWritePending))
{
myLastAccess = addr;
myNumberOfDistinctAccesses = my6502->distinctAccesses();
myWritePending = true;
}
// Is the bank configuration hotspot being accessed?
else if((addr & 0x1FFF) == 0x1FF8)
{
// Yes, so handle bank configuration
myWritePending = false;
bankConfiguration(myLastAccess);
}
// Handle poke if writing enabled
else if(myWriteEnabled && myWritePending)
{
if(my6502->distinctAccesses() >= myNumberOfDistinctAccesses + 5)
{
if(my6502->distinctAccesses() == myNumberOfDistinctAccesses + 5)
{
if((addr & 0x0800) == 0)
myImage[(addr & 0x07FF) + myImageOffset[0]] = myLastAccess;
else if(myImageOffset[1] != 3 * 2048) // Can't poke to ROM :-)
myImage[(addr & 0x07FF) + myImageOffset[1]] = myLastAccess;
}
myWritePending = false;
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeAR::bankConfiguration(uInt8 configuration)
{
// D7-D5 of this byte: Write Pulse Delay (n/a for emulator)
//
// D4-D0: RAM/ROM configuration:
// $F000-F7FF $F800-FFFF Address range that banks map into
// 000wp 2 ROM
// 001wp 0 ROM
// 010wp 2 0 as used in Commie Mutants and many others
// 011wp 0 2 as used in Suicide Mission
// 100wp 2 ROM
// 101wp 1 ROM
// 110wp 2 1 as used in Killer Satellites
// 111wp 1 2 as we use for 2k/4k ROM cloning
//
// w = Write Enable (1 = enabled; accesses to $F000-$F0FF cause writes
// to happen. 0 = disabled, and the cart acts like ROM.)
// p = ROM Power (0 = enabled, 1 = off.) Only power the ROM if you're
// wanting to access the ROM for multiloads. Otherwise set to 1.
// Handle ROM power configuration
myPower = !(configuration & 0x01);
if(myPower)
{
myPowerRomCycle = mySystem->cycles();
}
myWriteEnabled = configuration & 0x02;
switch((configuration >> 2) & 0x07)
{
case 0:
{
myImageOffset[0] = 2 * 2048;
myImageOffset[1] = 3 * 2048;
break;
}
case 1:
{
myImageOffset[0] = 0 * 2048;
myImageOffset[1] = 3 * 2048;
break;
}
case 2:
{
myImageOffset[0] = 2 * 2048;
myImageOffset[1] = 0 * 2048;
break;
}
case 3:
{
myImageOffset[0] = 0 * 2048;
myImageOffset[1] = 2 * 2048;
break;
}
case 4:
{
myImageOffset[0] = 2 * 2048;
myImageOffset[1] = 3 * 2048;
break;
}
case 5:
{
myImageOffset[0] = 1 * 2048;
myImageOffset[1] = 3 * 2048;
break;
}
case 6:
{
myImageOffset[0] = 2 * 2048;
myImageOffset[1] = 1 * 2048;
break;
}
case 7:
{
myImageOffset[0] = 1 * 2048;
myImageOffset[1] = 2 * 2048;
break;
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeAR::setupROM()
{
static uInt8 dummyROMCode[] = {
0xa9, 0x0, 0xa2, 0x0, 0x95, 0x80, 0xe8, 0xe0,
0x80, 0xd0, 0xf9, 0x4c, 0x2b, 0xfa, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xa9, 0x0, 0xa2, 0x0, 0x95, 0x80, 0xe8, 0xe0,
0x1e, 0xd0, 0xf9, 0xa2, 0x0, 0xbd, 0x45, 0xfa,
0x95, 0xfa, 0xe8, 0xe0, 0x6, 0xd0, 0xf6, 0xa2,
0xff, 0xa0, 0x0, 0xa9, 0x0, 0x85, 0x80, 0xcd,
0x0, 0xf0, 0x4c, 0xfa, 0x0, 0xad, 0xf8, 0xff,
0x4c, 0x0, 0x0
};
int size = sizeof(dummyROMCode);
// Copy the "dummy" ROM code into the ROM area
for(int i = 0; i < size; ++i)
{
myImage[0x1A00 + i] = dummyROMCode[i];
}
// Put a JMP $FA20 at multiload entry point ($F800)
myImage[0x1800] = 0x4C;
myImage[0x1801] = 0x20;
myImage[0x1802] = 0xFA;
// Update ROM code to have the correct reset address and bank configuration
myImage[0x1A00 + size - 2] = myHeader[0];
myImage[0x1A00 + size - 1] = myHeader[1];
myImage[0x1A00 + size - 11] = myHeader[2];
myImage[0x1A00 + size - 15] = myHeader[2];
// Finally set 6502 vectors to point to this "dummy" code at 0xFA00
myImage[3 * 2048 + 2044] = 0x00;
myImage[3 * 2048 + 2045] = 0xFA;
myImage[3 * 2048 + 2046] = 0x00;
myImage[3 * 2048 + 2047] = 0xFA;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeAR::checksum(uInt8* s, uInt16 length)
{
uInt8 sum = 0;
for(uInt32 i = 0; i < length; ++i)
{
sum += s[i];
}
return sum;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeAR::loadIntoRAM(uInt8 load)
{
uInt16 image;
// Scan through all of the loads to see if we find the one we're looking for
for(image = 0; image < myNumberOfLoadImages; ++image)
{
// Is this the correct load?
if(myLoadImages[(image * 8448) + 8192 + 5] == load)
{
// Copy the load's header
memcpy(myHeader, myLoadImages + (image * 8448) + 8192, 256);
// Verify the load's header
if(checksum(myHeader, 8) != 0x55)
{
cerr << "WARNING: The Supercharger header checksum is invalid...\n";
}
// Load all of the pages from the load
bool invalidPageChecksumSeen = false;
for(uInt32 j = 0; j < myHeader[3]; ++j)
{
uInt32 bank = myHeader[16 + j] & 0x03;
uInt32 page = (myHeader[16 + j] >> 2) & 0x07;
uInt8* src = myLoadImages + (image * 8448) + (j * 256);
uInt8 sum = checksum(src, 256) + myHeader[16 + j] + myHeader[64 + j];
if(!invalidPageChecksumSeen && (sum != 0x55))
{
cerr << "WARNING: Some Supercharger page checksums are invalid...\n";
invalidPageChecksumSeen = true;
}
// Copy page to Supercharger RAM
memcpy(myImage + (bank * 2048) + (page * 256), src, 256);
}
// Make sure the "dummy" ROM is installed
setupROM();
return;
}
}
// TODO: Should probably switch to an internal ROM routine to display
// this message to the user...
cerr << "ERROR: Supercharger load is missing from ROM image...\n";
}

View File

@ -0,0 +1,150 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1999 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartAR.hxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
//============================================================================
#ifndef CARTRIDGEAR_HXX
#define CARTRIDGEAR_HXX
class CartridgeAR;
class M6502High;
#include "bspf.hxx"
#include "Cart.hxx"
/**
This is the cartridge class for Arcadia (aka Starpath) Supercharger
games. Christopher Salomon provided most of the technical details
used in creating this class.
The Supercharger has four 2K banks. There are three banks of RAM
and one bank of ROM. All 6K of the RAM can be read and written.
@author Bradford W. Mott
@version $Id: CartAR.hxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
*/
class CartridgeAR : public Cartridge
{
public:
/**
Create a new cartridge using the specified image and size
@param image Pointer to the ROM image
@param size The size of the ROM image
*/
CartridgeAR(const uInt8* image, uInt32 size);
/**
Destructor
*/
virtual ~CartridgeAR();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
virtual void systemCyclesReset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
// Handle a change to the bank configuration
void bankConfiguration(uInt8 configuration);
// Compute the sum of the array of bytes
uInt8 checksum(uInt8* s, uInt16 length);
// Load the specified load into SC RAM
void loadIntoRAM(uInt8 load);
// Sets up a "dummy" bootstrap ROM in the ROM bank of the cartridge
void setupROM();
private:
// Pointer to the 6502 processor in the system
M6502High* my6502;
// Indicates the offest within the image for the corresponding bank
uInt32 myImageOffset[2];
// The 6K of RAM and 2K of ROM contained in the Supercharger
uInt8 myImage[8192];
// The 256 byte header for the current 8448 byte load
uInt8 myHeader[256];
// All of the 8448 byte loads associated with the game
uInt8* myLoadImages;
// Indicates how many 8448 loads there are
uInt8 myNumberOfLoadImages;
// Indicates if the RAM is write enabled
bool myWriteEnabled;
// Indicates if the ROM's power is on or off
bool myPower;
// Indicates when the power was last turned on
Int32 myPowerRomCycle;
// Indicates the "value" address which was accessed
uInt16 myLastAccess;
// Indicates the number of distinct accesses when "value" was set
uInt32 myNumberOfDistinctAccesses;
// Indicates if a write is pending or not
bool myWritePending;
};
#endif

View File

@ -0,0 +1,191 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartE0.cxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
//============================================================================
#include <assert.h>
#include "CartE0.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeE0::CartridgeE0(const uInt8* image)
{
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < 8192; ++addr)
{
myImage[addr] = image[addr];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeE0::~CartridgeE0()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartridgeE0::name() const
{
return "CartridgeE0";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE0::reset()
{
// Setup segments to some default slices
segmentZero(4);
segmentOne(5);
segmentTwo(6);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE0::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert(((0x1000 & mask) == 0) && ((0x1400 & mask) == 0) &&
((0x1800 & mask) == 0) && ((0x1C00 & mask) == 0));
// Set the page acessing methods for the first part of the last segment
System::PageAccess access;
access.directPokeBase = 0;
access.device = this;
for(uInt32 i = 0x1C00; i < (0x1FE0U & ~mask); i += (1 << shift))
{
access.directPeekBase = &myImage[7168 + (i & 0x03FF)];
mySystem->setPageAccess(i >> shift, access);
}
myCurrentSlice[3] = 7;
// Set the page accessing methods for the hot spots in the last segment
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
for(uInt32 j = (0x1FE0 & ~mask); j < 0x2000; j += (1 << shift))
{
mySystem->setPageAccess(j >> shift, access);
}
// Install some default slices for the other segments
segmentZero(4);
segmentOne(5);
segmentTwo(6);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeE0::peek(uInt16 address)
{
address = address & 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FE0) && (address <= 0x0FE7))
{
segmentZero(address & 0x0007);
}
else if((address >= 0x0FE8) && (address <= 0x0FEF))
{
segmentOne(address & 0x0007);
}
else if((address >= 0x0FF0) && (address <= 0x0FF7))
{
segmentTwo(address & 0x0007);
}
return myImage[(myCurrentSlice[address >> 10] << 10) + (address & 0x03FF)];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE0::poke(uInt16 address, uInt8)
{
address = address & 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FE0) && (address <= 0x0FE7))
{
segmentZero(address & 0x0007);
}
else if((address >= 0x0FE8) && (address <= 0x0FEF))
{
segmentOne(address & 0x0007);
}
else if((address >= 0x0FF0) && (address <= 0x0FF7))
{
segmentTwo(address & 0x0007);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE0::segmentZero(uInt16 slice)
{
// Remember the new slice
myCurrentSlice[0] = slice;
uInt16 offset = slice << 10;
uInt16 shift = mySystem->pageShift();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
for(uInt32 address = 0x1000; address < 0x1400; address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x03FF)];
mySystem->setPageAccess(address >> shift, access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE0::segmentOne(uInt16 slice)
{
// Remember the new slice
myCurrentSlice[1] = slice;
uInt16 offset = slice << 10;
uInt16 shift = mySystem->pageShift();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
for(uInt32 address = 0x1400; address < 0x1800; address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x03FF)];
mySystem->setPageAccess(address >> shift, access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE0::segmentTwo(uInt16 slice)
{
// Remember the new slice
myCurrentSlice[2] = slice;
uInt16 offset = slice << 10;
uInt16 shift = mySystem->pageShift();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
for(uInt32 address = 0x1800; address < 0x1C00; address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x03FF)];
mySystem->setPageAccess(address >> shift, access);
}
}

View File

@ -0,0 +1,121 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartE0.hxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
//============================================================================
#ifndef CARTRIDGEE0_HXX
#define CARTRIDGEE0_HXX
class CartridgeF8;
#include "bspf.hxx"
#include "Cart.hxx"
/**
This is the cartridge class for Parker Brothers' 8K games. In
this bankswitching scheme the 2600's 4K cartridge address space
is broken into four 1K segments. The desired 1K slice of the
ROM is selected by accessing 1FE0 to 1FE7 for the first 1K.
1FE8 to 1FEF selects the slice for the second 1K, and 1FF0 to
1FF8 selects the slice for the third 1K. The last 1K segment
always points to the last 1K of the ROM image.
@author Bradford W. Mott
@version $Id: CartE0.hxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
*/
class CartridgeE0 : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
CartridgeE0(const uInt8* image);
/**
Destructor
*/
virtual ~CartridgeE0();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
/**
Install the specified slice for segment zero
@param slice The slice to map into the segment
*/
void segmentZero(uInt16 slice);
/**
Install the specified slice for segment one
@param slice The slice to map into the segment
*/
void segmentOne(uInt16 slice);
/**
Install the specified slice for segment two
@param slice The slice to map into the segment
*/
void segmentTwo(uInt16 slice);
private:
// Indicates the slice mapped into each of the four segments
uInt16 myCurrentSlice[4];
// The 8K ROM image of the cartridge
uInt8 myImage[8192];
};
#endif

View File

@ -0,0 +1,214 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartE7.cxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
//============================================================================
#include <assert.h>
#include "CartE7.hxx"
#include "Random.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeE7::CartridgeE7(const uInt8* image)
{
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < 16384; ++addr)
{
myImage[addr] = image[addr];
}
// Initialize RAM with random values
Random random;
for(uInt32 i = 0; i < 2048; ++i)
{
myRAM[i] = random.next();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeE7::~CartridgeE7()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartridgeE7::name() const
{
return "CartridgeE7";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE7::reset()
{
// Install some default banks for the RAM and first segment
bankRAM(0);
bank(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE7::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert(((0x1400 & mask) == 0) && ((0x1800 & mask) == 0) &&
((0x1900 & mask) == 0) && ((0x1A00 & mask) == 0));
// Set the page accessing methods for the hot spots
System::PageAccess access;
for(uInt32 i = (0x1FE0 & ~mask); i < 0x2000; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
// Setup the second segment to always point to the last ROM slice
for(uInt32 j = 0x1A00; j < (0x1FE0U & ~mask); j += (1 << shift))
{
access.device = this;
access.directPeekBase = &myImage[7 * 2048 + (j & 0x07FF)];
access.directPokeBase = 0;
mySystem->setPageAccess(j >> shift, access);
}
myCurrentSlice[1] = 7;
// Install some default banks for the RAM and first segment
bankRAM(0);
bank(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeE7::peek(uInt16 address)
{
address = address & 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FE0) && (address <= 0x0FE7))
{
bank(address & 0x0007);
}
else if((address >= 0x0FE8) && (address <= 0x0FEB))
{
bankRAM(address & 0x0003);
}
// NOTE: The following does not handle reading from RAM, however,
// this function should never be called for RAM because of the
// way page accessing has been setup
return myImage[(myCurrentSlice[address >> 11] << 11) + (address & 0x07FF)];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE7::poke(uInt16 address, uInt8)
{
address = address & 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FE0) && (address <= 0x0FE7))
{
bank(address & 0x0007);
}
else if((address >= 0x0FE8) && (address <= 0x0FEB))
{
bankRAM(address & 0x0003);
}
// NOTE: This does not handle writing to RAM, however, this
// function should never be called for RAM because of the
// way page accessing has been setup
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE7::bank(uInt16 slice)
{
// Remember what bank we're in
myCurrentSlice[0] = slice;
uInt16 offset = slice << 11;
uInt16 shift = mySystem->pageShift();
// Setup the page access methods for the current bank
if(slice != 7)
{
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
// Map ROM image into first segment
for(uInt32 address = 0x1000; address < 0x1800; address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x07FF)];
mySystem->setPageAccess(address >> shift, access);
}
}
else
{
System::PageAccess access;
access.device = this;
// Set the page accessing method for the 1K slice of RAM writing pages
access.directPeekBase = 0;
access.directPokeBase = 0;
for(uInt32 j = 0x1000; j < 0x1400; j += (1 << shift))
{
access.directPokeBase = &myRAM[j & 0x03FF];
mySystem->setPageAccess(j >> shift, access);
}
// Set the page accessing method for the 1K slice of RAM reading pages
access.directPeekBase = 0;
access.directPokeBase = 0;
for(uInt32 k = 0x1400; k < 0x1800; k += (1 << shift))
{
access.directPeekBase = &myRAM[k & 0x03FF];
mySystem->setPageAccess(k >> shift, access);
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeE7::bankRAM(uInt16 bank)
{
// Remember what bank we're in
myCurrentRAM = bank;
uInt16 offset = bank << 8;
uInt16 shift = mySystem->pageShift();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
// Set the page accessing method for the 256 bytes of RAM writing pages
access.directPeekBase = 0;
access.directPokeBase = 0;
for(uInt32 j = 0x1800; j < 0x1900; j += (1 << shift))
{
access.directPokeBase = &myRAM[1024 + offset + (j & 0x00FF)];
mySystem->setPageAccess(j >> shift, access);
}
// Set the page accessing method for the 256 bytes of RAM reading pages
access.directPeekBase = 0;
access.directPokeBase = 0;
for(uInt32 k = 0x1900; k < 0x1A00; k += (1 << shift))
{
access.directPeekBase = &myRAM[1024 + offset + (k & 0x00FF)];
mySystem->setPageAccess(k >> shift, access);
}
}

View File

@ -0,0 +1,137 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartE7.hxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
//============================================================================
#ifndef CARTRIDGEE7_HXX
#define CARTRIDGEE7_HXX
class CartridgeE7;
#include "bspf.hxx"
#include "Cart.hxx"
/**
This is the cartridge class for M-Network bankswitched games.
In this bankswitching scheme the 2600's 4K cartridge address
space is broken into two 2K segments.
Kevin Horton describes E7 as follows:
Only M-Network used this scheme. This has to be the
most complex method used in any cart! :-) It allows
for the capability of 2K of RAM; although it doesn't
have to be used (in fact, only one cart used it).
There are now 8 2K banks, instead of 4. The last 2K
in the cart always points to the last 2K of the ROM
image, while the first 2K is selectable. You access
1FE0 to 1FE6 to select which 2K bank. Note that you
cannot select the last 2K of the ROM image into the
lower 2K of the cart! Accessing 1FE7 selects 1K of
RAM at 1000-17FF instead of ROM! The 2K of RAM is
broken up into two 1K sections. One 1K section is
mapped in at 1000-17FF if 1FE7 has been accessed.
1000-13FF is the write port, while 1400-17FF is the
read port. The second 1K of RAM appears at 1800-19FF.
1800-18FF is the write port while 1900-19FF is the
read port. You select which 256 byte block appears
here by accessing 1FF8 to 1FFB.
@author Bradford W. Mott
@version $Id: CartE7.hxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
*/
class CartridgeE7 : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
CartridgeE7(const uInt8* image);
/**
Destructor
*/
virtual ~CartridgeE7();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
/**
Map the specfied bank into the first segment
@param bank The bank that should be installed in the system
*/
void bank(uInt16 bank);
/**
Install pages for the specified 256 byte bank of RAM
@param bank The bank that should be installed in the system
*/
void bankRAM(uInt16 bank);
private:
// Indicates which slice is in the segment
uInt16 myCurrentSlice[2];
// Indicates which 256 byte bank of RAM is being used
uInt16 myCurrentRAM;
// The 16K ROM image of the cartridge
uInt8 myImage[16384];
// The 2048 bytes of RAM
uInt8 myRAM[2048];
};
#endif

View File

@ -0,0 +1,154 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartF4SC.cxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
//============================================================================
#include <assert.h>
#include "CartF4SC.hxx"
#include "Random.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF4SC::CartridgeF4SC(const uInt8* image)
{
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < 32768; ++addr)
{
myImage[addr] = image[addr];
}
// Initialize RAM with random values
Random random;
for(uInt32 i = 0; i < 128; ++i)
{
myRAM[i] = random.next();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF4SC::~CartridgeF4SC()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartridgeF4SC::name() const
{
return "CartridgeF4SC";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF4SC::reset()
{
// Upon reset we switch to bank 7
bank(7);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF4SC::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0));
// Set the page accessing methods for the hot spots
System::PageAccess access;
for(uInt32 i = (0x1FF4 & ~mask); i < 0x2000; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
// Set the page accessing method for the RAM writing pages
for(uInt32 j = 0x1000; j < 0x1080; j += (1 << shift))
{
access.device = this;
access.directPeekBase = 0;
access.directPokeBase = &myRAM[j & 0x007F];
mySystem->setPageAccess(j >> shift, access);
}
// Set the page accessing method for the RAM reading pages
for(uInt32 k = 0x1080; k < 0x1100; k += (1 << shift))
{
access.device = this;
access.directPeekBase = &myRAM[k & 0x007F];
access.directPokeBase = 0;
mySystem->setPageAccess(k >> shift, access);
}
// Install pages for bank 7
bank(7);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeF4SC::peek(uInt16 address)
{
address = address & 0x0FFF;
// Switch banks if necessary
if((address >= 0x0FF4) && (address <= 0x0FFB))
{
bank(address - 0x0FF4);
}
// NOTE: This does not handle accessing RAM, however, this function
// should never be called for RAM because of the way page accessing
// has been setup
return myImage[myCurrentBank * 4096 + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF4SC::poke(uInt16 address, uInt8)
{
// Switch banks if necessary
if((address >= 0x0FF4) && (address <= 0x0FFB))
{
bank(address - 0x0FF4);
}
// NOTE: This does not handle accessing RAM, however, this function
// should never be called for RAM because of the way page accessing
// has been setup
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF4SC::bank(uInt16 bank)
{
// Remember what bank we're in
myCurrentBank = bank;
uInt16 offset = myCurrentBank * 4096;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
// Map ROM image into the system
for(uInt32 address = 0x1100; address < (0x1FF4U & ~mask);
address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
mySystem->setPageAccess(address >> shift, access);
}
}

View File

@ -0,0 +1,105 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartF4SC.hxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
//============================================================================
#ifndef CARTRIDGEF4SC_HXX
#define CARTRIDGEF4SC_HXX
class CartridgeF4SC;
#include "bspf.hxx"
#include "Cart.hxx"
/**
Cartridge class used for Atari's 32K bankswitched games with
128 bytes of RAM. There are eight 4K banks.
@author Bradford W. Mott
@version $Id: CartF4SC.hxx,v 1.1.1.1 2001-12-27 19:54:19 bwmott Exp $
*/
class CartridgeF4SC : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
CartridgeF4SC(const uInt8* image);
/**
Destructor
*/
virtual ~CartridgeF4SC();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
/**
Install pages for the specified bank in the system
@param bank The bank that should be installed in the system
*/
void bank(uInt16 bank);
private:
// Indicates which bank is currently active
uInt16 myCurrentBank;
// The 16K ROM image of the cartridge
uInt8 myImage[32768];
// The 128 bytes of RAM
uInt8 myRAM[128];
};
#endif

View File

@ -0,0 +1,165 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartF6.cxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#include <assert.h>
#include "CartF6.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF6::CartridgeF6(const uInt8* image)
{
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < 16384; ++addr)
{
myImage[addr] = image[addr];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF6::~CartridgeF6()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartridgeF6::name() const
{
return "CartridgeF6";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF6::reset()
{
// Upon reset we switch to bank 0
bank(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF6::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert((0x1000 & mask) == 0);
// Set the page accessing methods for the hot spots
System::PageAccess access;
for(uInt32 i = (0x1FF6 & ~mask); i < 0x2000; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
// Upon install we'll setup bank 0
bank(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeF6::peek(uInt16 address)
{
address = address & 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF6:
// Set the current bank to the first 4k bank
bank(0);
break;
case 0x0FF7:
// Set the current bank to the second 4k bank
bank(1);
break;
case 0x0FF8:
// Set the current bank to the third 4k bank
bank(2);
break;
case 0x0FF9:
// Set the current bank to the forth 4k bank
bank(3);
break;
default:
break;
}
return myImage[myCurrentBank * 4096 + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF6::poke(uInt16 address, uInt8)
{
address = address & 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF6:
// Set the current bank to the first 4k bank
bank(0);
break;
case 0x0FF7:
// Set the current bank to the second 4k bank
bank(1);
break;
case 0x0FF8:
// Set the current bank to the third 4k bank
bank(2);
break;
case 0x0FF9:
// Set the current bank to the forth 4k bank
bank(3);
break;
default:
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF6::bank(uInt16 bank)
{
// Remember what bank we're in
myCurrentBank = bank;
uInt16 offset = myCurrentBank * 4096;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
// Map ROM image into the system
for(uInt32 address = 0x1000; address < (0x1FF6U & ~mask);
address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
mySystem->setPageAccess(address >> shift, access);
}
}

View File

@ -0,0 +1,102 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartF6.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#ifndef CARTRIDGEF6_HXX
#define CARTRIDGEF6_HXX
class CartridgeF6;
#include "bspf.hxx"
#include "Cart.hxx"
/**
Cartridge class used for Atari's 16K bankswitched games. There
are four 4K banks.
@author Bradford W. Mott
@version $Id: CartF6.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
*/
class CartridgeF6 : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
CartridgeF6(const uInt8* image);
/**
Destructor
*/
virtual ~CartridgeF6();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
/**
Install pages for the specified bank in the system
@param bank The bank that should be installed in the system
*/
void bank(uInt16 bank);
private:
// Indicates which bank is currently active
uInt16 myCurrentBank;
// The 16K ROM image of the cartridge
uInt8 myImage[16384];
};
#endif

View File

@ -0,0 +1,198 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartF6SC.cxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#include <assert.h>
#include "CartF6SC.hxx"
#include "Random.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF6SC::CartridgeF6SC(const uInt8* image)
{
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < 16384; ++addr)
{
myImage[addr] = image[addr];
}
// Initialize RAM with random values
Random random;
for(uInt32 i = 0; i < 128; ++i)
{
myRAM[i] = random.next();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF6SC::~CartridgeF6SC()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartridgeF6SC::name() const
{
return "CartridgeF6SC";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF6SC::reset()
{
// Upon reset we switch to bank 0
bank(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF6SC::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0));
// Set the page accessing methods for the hot spots
System::PageAccess access;
for(uInt32 i = (0x1FF6 & ~mask); i < 0x2000; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
// Set the page accessing method for the RAM writing pages
for(uInt32 j = 0x1000; j < 0x1080; j += (1 << shift))
{
access.device = this;
access.directPeekBase = 0;
access.directPokeBase = &myRAM[j & 0x007F];
mySystem->setPageAccess(j >> shift, access);
}
// Set the page accessing method for the RAM reading pages
for(uInt32 k = 0x1080; k < 0x1100; k += (1 << shift))
{
access.device = this;
access.directPeekBase = &myRAM[k & 0x007F];
access.directPokeBase = 0;
mySystem->setPageAccess(k >> shift, access);
}
// Install pages for bank 0
bank(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeF6SC::peek(uInt16 address)
{
address = address & 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF6:
// Set the current bank to the first 4k bank
bank(0);
break;
case 0x0FF7:
// Set the current bank to the second 4k bank
bank(1);
break;
case 0x0FF8:
// Set the current bank to the third 4k bank
bank(2);
break;
case 0x0FF9:
// Set the current bank to the forth 4k bank
bank(3);
break;
default:
break;
}
// NOTE: This does not handle accessing RAM, however, this function
// should never be called for RAM because of the way page accessing
// has been setup
return myImage[myCurrentBank * 4096 + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF6SC::poke(uInt16 address, uInt8)
{
address = address & 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF6:
// Set the current bank to the first 4k bank
bank(0);
break;
case 0x0FF7:
// Set the current bank to the second 4k bank
bank(1);
break;
case 0x0FF8:
// Set the current bank to the third 4k bank
bank(2);
break;
case 0x0FF9:
// Set the current bank to the forth 4k bank
bank(3);
break;
default:
break;
}
// NOTE: This does not handle accessing RAM, however, this function
// should never be called for RAM because of the way page accessing
// has been setup
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF6SC::bank(uInt16 bank)
{
// Remember what bank we're in
myCurrentBank = bank;
uInt16 offset = myCurrentBank * 4096;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
// Map ROM image into the system
for(uInt32 address = 0x1100; address < (0x1FF6U & ~mask);
address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
mySystem->setPageAccess(address >> shift, access);
}
}

View File

@ -0,0 +1,105 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartF6SC.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#ifndef CARTRIDGEF6SC_HXX
#define CARTRIDGEF6SC_HXX
class CartridgeF6SC;
#include "bspf.hxx"
#include "Cart.hxx"
/**
Cartridge class used for Atari's 16K bankswitched games with
128 bytes of RAM. There are four 4K banks.
@author Bradford W. Mott
@version $Id: CartF6SC.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
*/
class CartridgeF6SC : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
CartridgeF6SC(const uInt8* image);
/**
Destructor
*/
virtual ~CartridgeF6SC();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
/**
Install pages for the specified bank in the system
@param bank The bank that should be installed in the system
*/
void bank(uInt16 bank);
private:
// Indicates which bank is currently active
uInt16 myCurrentBank;
// The 16K ROM image of the cartridge
uInt8 myImage[16384];
// The 128 bytes of RAM
uInt8 myRAM[128];
};
#endif

View File

@ -0,0 +1,145 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartF8.cxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#include <assert.h>
#include "CartF8.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF8::CartridgeF8(const uInt8* image)
{
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < 8192; ++addr)
{
myImage[addr] = image[addr];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF8::~CartridgeF8()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartridgeF8::name() const
{
return "CartridgeF8";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8::reset()
{
// Upon reset we switch to bank 1
bank(1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert((0x1000 & mask) == 0);
// Set the page accessing methods for the hot spots
System::PageAccess access;
for(uInt32 i = (0x1FF8 & ~mask); i < 0x2000; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
// Install pages for bank 1
bank(1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeF8::peek(uInt16 address)
{
address = address & 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF8:
// Set the current bank to the lower 4k bank
bank(0);
break;
case 0x0FF9:
// Set the current bank to the upper 4k bank
bank(1);
break;
default:
break;
}
return myImage[myCurrentBank * 4096 + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8::poke(uInt16 address, uInt8)
{
address = address & 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF8:
// Set the current bank to the lower 4k bank
bank(0);
break;
case 0x0FF9:
// Set the current bank to the upper 4k bank
bank(1);
break;
default:
break;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8::bank(uInt16 bank)
{
// Remember what bank we're in
myCurrentBank = bank;
uInt16 offset = myCurrentBank * 4096;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
// Map ROM image into the system
for(uInt32 address = 0x1000; address < (0x1FF8U & ~mask);
address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
mySystem->setPageAccess(address >> shift, access);
}
}

View File

@ -0,0 +1,102 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartF8.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#ifndef CARTRIDGEF8_HXX
#define CARTRIDGEF8_HXX
class CartridgeF8;
#include "bspf.hxx"
#include "Cart.hxx"
/**
Cartridge class used for Atari's 8K bankswitched games. There
are two 4K banks.
@author Bradford W. Mott
@version $Id: CartF8.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
*/
class CartridgeF8 : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
CartridgeF8(const uInt8* image);
/**
Destructor
*/
virtual ~CartridgeF8();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
/**
Install pages for the specified bank in the system
@param bank The bank that should be installed in the system
*/
void bank(uInt16 bank);
private:
// Indicates which bank is currently active
uInt16 myCurrentBank;
// The 8K ROM image of the cartridge
uInt8 myImage[8192];
};
#endif

View File

@ -0,0 +1,178 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartF8SC.cxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#include <assert.h>
#include "CartF8SC.hxx"
#include "Random.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF8SC::CartridgeF8SC(const uInt8* image)
{
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < 8192; ++addr)
{
myImage[addr] = image[addr];
}
// Initialize RAM with random values
Random random;
for(uInt32 i = 0; i < 128; ++i)
{
myRAM[i] = random.next();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeF8SC::~CartridgeF8SC()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartridgeF8SC::name() const
{
return "CartridgeF8SC";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8SC::reset()
{
// Upon reset we switch to bank 1
bank(1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8SC::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert(((0x1080 & mask) == 0) && ((0x1100 & mask) == 0));
// Set the page accessing methods for the hot spots
System::PageAccess access;
for(uInt32 i = (0x1FF8 & ~mask); i < 0x2000; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
// Set the page accessing method for the RAM writing pages
for(uInt32 j = 0x1000; j < 0x1080; j += (1 << shift))
{
access.device = this;
access.directPeekBase = 0;
access.directPokeBase = &myRAM[j & 0x007F];
mySystem->setPageAccess(j >> shift, access);
}
// Set the page accessing method for the RAM reading pages
for(uInt32 k = 0x1080; k < 0x1100; k += (1 << shift))
{
access.device = this;
access.directPeekBase = &myRAM[k & 0x007F];
access.directPokeBase = 0;
mySystem->setPageAccess(k >> shift, access);
}
// Install pages for bank 1
bank(1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeF8SC::peek(uInt16 address)
{
address = address & 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF8:
// Set the current bank to the lower 4k bank
bank(0);
break;
case 0x0FF9:
// Set the current bank to the upper 4k bank
bank(1);
break;
default:
break;
}
// NOTE: This does not handle accessing RAM, however, this function
// should never be called for RAM because of the way page accessing
// has been setup
return myImage[myCurrentBank * 4096 + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8SC::poke(uInt16 address, uInt8)
{
address = address & 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF8:
// Set the current bank to the lower 4k bank
bank(0);
break;
case 0x0FF9:
// Set the current bank to the upper 4k bank
bank(1);
break;
default:
break;
}
// NOTE: This does not handle accessing RAM, however, this function
// should never be called for RAM because of the way page accessing
// has been setup
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeF8SC::bank(uInt16 bank)
{
// Remember what bank we're in
myCurrentBank = bank;
uInt16 offset = myCurrentBank << 12;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
// Map ROM image into the system
for(uInt32 address = 0x1100; address < (0x1FF8U & ~mask);
address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
mySystem->setPageAccess(address >> shift, access);
}
}

View File

@ -0,0 +1,105 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartF8SC.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#ifndef CARTRIDGEF8SC_HXX
#define CARTRIDGEF8SC_HXX
class CartridgeF8SC;
#include "bspf.hxx"
#include "Cart.hxx"
/**
Cartridge class used for Atari's 8K bankswitched games with
128 bytes of RAM. There are two 4K banks.
@author Bradford W. Mott
@version $Id: CartF8SC.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
*/
class CartridgeF8SC : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
CartridgeF8SC(const uInt8* image);
/**
Destructor
*/
virtual ~CartridgeF8SC();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
/**
Install pages for the specified bank in the system
@param bank The bank that should be installed in the system
*/
void bank(uInt16 bank);
private:
// Indicates which bank is currently active
uInt16 myCurrentBank;
// The 8K ROM image of the cartridge
uInt8 myImage[8192];
// The 128 bytes of RAM
uInt8 myRAM[128];
};
#endif

View File

@ -0,0 +1,188 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartFASC.cxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#include <assert.h>
#include "CartFASC.hxx"
#include "Random.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeFASC::CartridgeFASC(const uInt8* image)
{
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < 12288; ++addr)
{
myImage[addr] = image[addr];
}
// Initialize RAM with random values
Random random;
for(uInt32 i = 0; i < 256; ++i)
{
myRAM[i] = random.next();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeFASC::~CartridgeFASC()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartridgeFASC::name() const
{
return "CartridgeFASC";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFASC::reset()
{
// Upon reset we switch to bank 2
bank(2);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFASC::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert(((0x1100 & mask) == 0) && ((0x1200 & mask) == 0));
// Set the page accessing methods for the hot spots
System::PageAccess access;
for(uInt32 i = (0x1FF8 & ~mask); i < 0x2000; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
// Set the page accessing method for the RAM writing pages
for(uInt32 j = 0x1000; j < 0x1100; j += (1 << shift))
{
access.device = this;
access.directPeekBase = 0;
access.directPokeBase = &myRAM[j & 0x00FF];
mySystem->setPageAccess(j >> shift, access);
}
// Set the page accessing method for the RAM reading pages
for(uInt32 k = 0x1100; k < 0x1200; k += (1 << shift))
{
access.device = this;
access.directPeekBase = &myRAM[k & 0x00FF];
access.directPokeBase = 0;
mySystem->setPageAccess(k >> shift, access);
}
// Install pages for bank 2
bank(2);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeFASC::peek(uInt16 address)
{
address = address & 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF8:
// Set the current bank to the lower 4k bank
bank(0);
break;
case 0x0FF9:
// Set the current bank to the middle 4k bank
bank(1);
break;
case 0x0FFA:
// Set the current bank to the upper 4k bank
bank(2);
break;
default:
break;
}
// NOTE: This does not handle accessing RAM, however, this function
// should never be called for RAM because of the way page accessing
// has been setup
return myImage[myCurrentBank * 4096 + address];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFASC::poke(uInt16 address, uInt8)
{
address = address & 0x0FFF;
// Switch banks if necessary
switch(address)
{
case 0x0FF8:
// Set the current bank to the lower 4k bank
bank(0);
break;
case 0x0FF9:
// Set the current bank to the middle 4k bank
bank(1);
break;
case 0x0FFA:
// Set the current bank to the upper 4k bank
bank(2);
break;
default:
break;
}
// NOTE: This does not handle accessing RAM, however, this function
// should never be called for RAM because of the way page accessing
// has been setup
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFASC::bank(uInt16 bank)
{
// Remember what bank we're in
myCurrentBank = bank;
uInt16 offset = myCurrentBank * 4096;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Setup the page access methods for the current bank
System::PageAccess access;
access.device = this;
access.directPokeBase = 0;
// Map ROM image into the system
for(uInt32 address = 0x1200; address < (0x1FF8U & ~mask);
address += (1 << shift))
{
access.directPeekBase = &myImage[offset + (address & 0x0FFF)];
mySystem->setPageAccess(address >> shift, access);
}
}

View File

@ -0,0 +1,105 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartFASC.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#ifndef CARTRIDGEFASC_HXX
#define CARTRIDGEFASC_HXX
class CartridgeFASC;
#include "bspf.hxx"
#include "Cart.hxx"
/**
Cartridge class used for CBS' RAM Plus cartridges. There are
three 4K banks and 256 bytes of RAM.
@author Bradford W. Mott
@version $Id: CartFASC.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
*/
class CartridgeFASC : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
CartridgeFASC(const uInt8* image);
/**
Destructor
*/
virtual ~CartridgeFASC();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
/**
Install pages for the specified bank in the system
@param bank The bank that should be installed in the system
*/
void bank(uInt16 bank);
private:
// Indicates which bank is currently active
uInt16 myCurrentBank;
// The 12K ROM image of the cartridge
uInt8 myImage[12288];
// The 256 bytes of RAM on the cartridge
uInt8 myRAM[256];
};
#endif

View File

@ -0,0 +1,81 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartFE.cxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#include <assert.h>
#include "CartFE.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeFE::CartridgeFE(const uInt8* image)
{
// Copy the ROM image into my buffer
for(uInt32 addr = 0; addr < 8192; ++addr)
{
myImage[addr] = image[addr];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeFE::~CartridgeFE()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartridgeFE::name() const
{
return "CartridgeFE";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFE::reset()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFE::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert((0x1000 & mask) == 0);
// Map all of the accesses to call peek and poke
System::PageAccess access;
for(uInt32 i = 0x1000; i < 0x2000; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeFE::peek(uInt16 address)
{
// The bank is determined by A13 of the processor
return myImage[(address & 0x0FFF) + (((address & 0x2000) == 0) ? 4096 : 0)];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeFE::poke(uInt16, uInt8)
{
}

View File

@ -0,0 +1,103 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartFE.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
//============================================================================
#ifndef CARTRIDGEFE_HXX
#define CARTRIDGEFE_HXX
class CartridgeFE;
#include "bspf.hxx"
#include "Cart.hxx"
/**
Bankswitching method used by Activison's Robot Tank and Decathlon.
Kevin Horton describes FE as follows:
Used only on two carts (Robot Tank and Decathlon). These
carts are very weird. It does not use accesses to the stack
like was previously thought. Instead, if you watch the called
addresses very carefully, you can see that they are either Dxxx
or Fxxx. This determines the bank to use. Just monitor A13 of
the processor and use it to determine your bank! :-) Of course
the 6507 in the 2600 does not have an A13, so the cart must have
an extra bit in the ROM matrix to tell when to switch banks.
There is *no* way to determine which bank you want to be in from
monitoring the bus.
@author Bradford W. Mott
@version $Id: CartFE.hxx,v 1.1.1.1 2001-12-27 19:54:20 bwmott Exp $
*/
class CartridgeFE : public Cartridge
{
public:
/**
Create a new cartridge using the specified image
@param image Pointer to the ROM image
*/
CartridgeFE(const uInt8* image);
/**
Destructor
*/
virtual ~CartridgeFE();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address.
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
// The 8K ROM image of the cartridge
uInt8 myImage[8192];
};
#endif

View File

@ -0,0 +1,218 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartMC.cxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#include <assert.h>
#include "CartMC.hxx"
#include "Random.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeMC::CartridgeMC(const uInt8* image, uInt32 size)
: mySlot3Locked(false)
{
uInt32 i;
// Make sure size is reasonable
assert(size <= 128 * 1024);
// Allocate array for the cart's RAM
myRAM = new uInt8[32 * 1024];
// Initialize RAM with random values
Random random;
for(i = 0; i < 32 * 1024; ++i)
{
myRAM[i] = random.next();
}
// Allocate array for the ROM image
myImage = new uInt8[128 * 1024];
// Set the contents of the entire ROM to 0
for(i = 0; i < 128 * 1024; ++i)
{
myImage[i] = 0;
}
// Copy the ROM image to the end of the ROM buffer
for(i = 0; i < size; ++i)
{
myImage[128 * 1024 - size + i] = image[i];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartridgeMC::~CartridgeMC()
{
delete[] myRAM;
delete[] myImage;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* CartridgeMC::name() const
{
return "CartridgeMC";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeMC::reset()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeMC::install(System& system)
{
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert(((0x1000 & mask) == 0) && ((0x1400 & mask) == 0) &&
((0x1800 & mask) == 0) && ((0x1C00 & mask) == 0));
// Set the page accessing methods for the hot spots in the TIA. For
// correct emulation I would need to chain any accesses below 0x40 to
// the TIA but for now I'll just forget about them.
//
// TODO: These TIA accesses may need to be chained, however, at this
// point Chris isn't sure if the hardware will allow it or not
//
System::PageAccess access;
for(uInt32 i = 0x00; i < 0x40; i += (1 << shift))
{
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = this;
mySystem->setPageAccess(i >> shift, access);
}
// Map the cartridge into the system
for(uInt32 j = 0x1000; j < 0x2000; j += (1 << shift))
{
access.device = this;
access.directPeekBase = 0;
access.directPokeBase = 0;
mySystem->setPageAccess(j >> shift, access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeMC::peek(uInt16 address)
{
address = address & 0x1FFF;
// Accessing the RESET vector so lets handle the powerup special case
if((address == 0x1FFC) || (address == 0x1FFD))
{
// Indicate that slot 3 is locked for now
mySlot3Locked = true;
}
// Should we unlock slot 3?
else if(mySlot3Locked && (address >= 0x1000) && (address <= 0x1BFF))
{
// Indicate that slot 3 is unlocked now
mySlot3Locked = false;
}
// Handle reads made to the TIA addresses
if(address < 0x1000)
{
return 0;
}
else
{
uInt8 block;
if(mySlot3Locked && ((address & 0x0C00) == 0x0C00))
{
block = 0xFF;
}
else
{
block = myCurrentBlock[(address & 0x0C00) >> 10];
}
// Is this a RAM or a ROM access
if(block & 0x80)
{
// ROM access
return myImage[(uInt32)(block & 0x7F) * 1024 + (address & 0x03FF)];
}
else
{
// This is a RAM access, however, is it to the read or write port?
if(address & 0x0200)
{
// Reading from the read port of the RAM block
return myRAM[(uInt32)(block & 0x3F) * 512 + (address & 0x01FF)];
}
else
{
// Oops, reading from the write port of the RAM block!
myRAM[(uInt32)(block & 0x3F) * 512 + (address & 0x01FF)] = 0;
return 0;
}
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeMC::poke(uInt16 address, uInt8 value)
{
address = address & 0x1FFF;
// Accessing the RESET vector so lets handle the powerup special case
if((address == 0x1FFC) || (address == 0x1FFD))
{
// Indicate that slot 3 is locked for now
mySlot3Locked = true;
}
// Should we unlock slot 3?
else if(mySlot3Locked && (address >= 0x1000) && (address <= 0x1BFF))
{
// Indicate that slot 3 is unlocked now
mySlot3Locked = false;
}
// Handle bank-switching writes
if((address >= 0x003C) && (address <= 0x003F))
{
myCurrentBlock[address - 0x003C] = value;
}
else
{
uInt8 block;
if(mySlot3Locked && ((address & 0x0C00) == 0x0C00))
{
block = 0xFF;
}
else
{
block = myCurrentBlock[(address & 0x0C00) >> 10];
}
// Is this a RAM write access
if(!(block & 0x80) && !(address & 0x0200))
{
// Handle the write to RAM
myRAM[(uInt32)(block & 0x3F) * 512 + (address & 0x01FF)] = value;
}
}
}

View File

@ -0,0 +1,207 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: CartMC.hxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#ifndef CARTRIDGEMC_HXX
#define CARTRIDGEMC_HXX
class CartridgeMC;
#include "bspf.hxx"
#include "Cart.hxx"
/**
This is the cartridge class for Chris Wilkson's Megacart. It does not
handle battery-backed RAM at this time and the code could use some serious
speed improvements. It is based on the following Megacart specification:
Megacart Specification, Rev1.1
(c) 1997 Chris Wilkson
cwilkson@mit.edu
Description
-----------
The Megacart is an external memory cartridge for the Atari 2600 and compatible
home video game consoles. It plugs into the standard cartridge port, and
contains a total of 128K bytes of ROM storage and 32K bytes of battery-backed
RAM storage.
General Operation
-----------------
The Megacart uses "bank switching" to fit the 160K bytes of physical memory
into the console's available 4K address space. Physical memory is divided
into 64 RAM blocks of 512 bytes each, and 128 ROM blocks of 1K bytes each.
RAM blocks are numbered $00 through $3F, and ROM blocks are numbered $80
through $FF.
The console's address space is divided into 4 slots of 1K each. Any physical
memory block can be switched into any memory slot by writing its block number
to the "hot address" for the desired slot. Memory locations $3C through $3F
serve as "hot addresses" for memory slots 0 through 3, respectively.
Example:
To make ROM addresses $1A400-$1A7FF (block $E9) available to the console at
memory locations $F800-$FBFF (slot 2), write $E9 to memory location $3e.
Caution:
Note that these memory locations are write only. Trying to read the contents
of memory locations $3C through $3F will not only return invalid data, but
will also corrupt the contents causing the software to crash. Reading these
addresses should not be attempted.
Special Case - RAM
-------------------
RAM blocks differ from ROM blocks in that one of the console's address lines,
A9 in this case, must be used as a read/write select. Because of this, RAM
blocks are limited to 512 bytes each, yet still occupy an entire 1K slot.
To store a value A9 must be low. To retrieve a value A9 must high.
Example:
First, let's set slot 0 (console addresses $F000-$F3FF) to point to RAM
block $9 (RAM $1200-$13ff). To do this, write $9 to console address $3c.
To store the value $69 in RAM location $1234, write $69 to console address
$F034 (A9=0). To retrieve the value of RAM location $1234, read from console
address $F234 (A9=1).
Special Case - Powerup
-----------------------
Because the console's memory is randomized at powerup, there is no way to
predict the data initially contained in the "hot addresses". Therefore,
hardware will force slot 3 to always point to ROM block $FF immediately
after any read or write to the RESET vector at $FFFC-$FFFD. Block $FF
must contain code to initialize the 4 memory slots to point to the desired
physical memory blocks before any other code can be executed. After program
execution jumps out of the boot code, the hardware will release slot 3 and
it will function just like any other slot.
Example (the first column is the physical ROM address):
$00C00 JUNK ... ; random code and data
...
...
...
...
$1F400 START ... ; program starts here
... ; slot 3 now points to rom block $83
...
...
...
$1FFDD BOOT SEI ; disable interrupts
$1FFDE CLD ; set hexadecimal arithmetic mode
$1FFDF LDX #$FF ;
$1FFE1 TXS ; set stack pointer to $ff
$1FFE2 LDA #$00
$1FFE4 ZERO STA 00,X ; clear RIOT and TIA -BEFORE- setting
$1FFE6 DEX ; up banks
$1FFE7 BNE ZERO
$1FFE9 BANKS LDA #$00 ; ram block 0 ($0000-$01ff)
$1FFEB STA SLOT0 ; slot 0 points to ram block 0
$1FFED LDA #$34 ; ram block $34 ($6800-$69ff)
$1FFEF STA SLOT1 ; slot 1 points to ram block $34
$1FFF1 LDA #$FD ; rom block $fd ($1f400-$1f7ff)
$1FFF3 STA SLOT2 ; slot 2 points to rom block $fd
$1FFF5 LDA #$83 ; rom block $83 ($00C00-$01000)
$1FFF7 STA SLOT3 ; slot 3 points to bootcode
; (rom block $ff)
; until jumping out of slot 3
$1FFF9 JMP $F800 ; jump to slot 2
$1FFFC RESET .WORD $FFDD ; powerup reset vector
$1FFFE SWI .WORD $FFDD ; software interrupt vector (BRK)
@author Bradford W. Mott
@version $Id: CartMC.hxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
*/
class CartridgeMC : public Cartridge
{
public:
/**
Create a new cartridge using the specified image and size. If the
size of the image is less than 128K then the cartridge will pad the
beginning of the 128K ROM with zeros.
@param image Pointer to the ROM image
@param size The size of the ROM image
*/
CartridgeMC(const uInt8* image, uInt32 size);
/**
Destructor
*/
virtual ~CartridgeMC();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install cartridge in the specified system. Invoked by the system
when the cartridge is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
// Indicates which block is currently active for the four segments
uInt8 myCurrentBlock[4];
// Indicates if slot 3 is locked to block $FF or not
bool mySlot3Locked;
// Pointer to the 32K bytes of RAM for the cartridge
uInt8* myRAM;
// Pointer to the 128K bytes of ROM for the cartridge
uInt8* myImage;
};
#endif

View File

@ -0,0 +1,261 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Console.cxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#include <assert.h>
#include "Booster.hxx"
#include "Cart.hxx"
#include "Console.hxx"
#include "Control.hxx"
#include "Driving.hxx"
#include "Event.hxx"
#include "Joystick.hxx"
#include "Keyboard.hxx"
#include "M6502Low.hxx"
#include "M6502Hi.hxx"
#include "M6532.hxx"
#include "MD5.hxx"
#include "MediaSrc.hxx"
#include "Paddles.hxx"
#include "Props.hxx"
#include "PropsSet.hxx"
#include "Switches.hxx"
#include "System.hxx"
#include "TIA.hxx"
/**
Compare the two strings s1 and s2 ignoring the case of the
characters. Answers true iff they are equal.
@param s1 The first string to compare
@param s2 The second string to compare
@return true iff the two strings are equal
*/
static bool compare(const string& s1, const string& s2)
{
if(s1.length() != s2.length())
{
return false;
}
for(uInt32 i = 0; i < s1.length(); ++i)
{
if(tolower(s1[i]) != tolower(s2[i]))
{
return false;
}
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Console::Console(const uInt8* image, uInt32 size, const char* filename,
const Event& event, PropertiesSet& propertiesSet, Sound& sound)
: myEvent(event)
{
myControllers[0] = 0;
myControllers[1] = 0;
myMediaSource = 0;
mySwitches = 0;
mySystem = 0;
myProperties = defaultProperties();
// Get the MD5 message-digest for the ROM image
string md5 = MD5(image, size);
// Search through the properties set to see if some exist for this game
for(uInt32 i = 0; i < propertiesSet.size(); ++i)
{
const Properties& properties = propertiesSet.get(i);
if(properties.get("Cartridge.MD5") == md5)
{
// We have a match so let's use those properties
myProperties = properties;
break;
}
}
// If there was no MD5 match then let's search based on filename
if(md5 != myProperties.get("Cartridge.MD5"))
{
for(uInt32 i = 0; i < propertiesSet.size(); ++i)
{
const Properties& properties = propertiesSet.get(i);
if(compare(properties.get("Cartridge.Filename"), filename))
{
// We have a match so let's use those properties
myProperties = properties;
break;
}
}
}
// TODO: At some point I belive we'll need to set the properties'
// MD5 value so the user will be able to edit it.
// myProperties.save(cout);
// Setup the controllers based on properties
string left = myProperties.get("Controller.Left");
string right = myProperties.get("Controller.Right");
// Construct left controller
if(left == "Booster-Grip")
{
myControllers[0] = new BoosterGrip(Controller::Left, myEvent);
}
else if(left == "Driving")
{
myControllers[0] = new Driving(Controller::Left, myEvent);
}
else if((left == "Keyboard") || (left == "Keypad"))
{
myControllers[0] = new Keyboard(Controller::Left, myEvent);
}
else if(left == "Paddles")
{
myControllers[0] = new Paddles(Controller::Left, myEvent);
}
else
{
myControllers[0] = new Joystick(Controller::Left, myEvent);
}
// Construct right controller
if(right == "Booster-Grip")
{
myControllers[1] = new BoosterGrip(Controller::Right, myEvent);
}
else if(right == "Driving")
{
myControllers[1] = new Driving(Controller::Right, myEvent);
}
else if((right == "Keyboard") || (right == "Keypad"))
{
myControllers[1] = new Keyboard(Controller::Right, myEvent);
}
else if(right == "Paddles")
{
myControllers[1] = new Paddles(Controller::Right, myEvent);
}
else
{
myControllers[1] = new Joystick(Controller::Right, myEvent);
}
// Create switches for the console
mySwitches = new Switches(myEvent, myProperties);
// Now, we can construct the system and components
mySystem = new System(13, 6);
M6502* m6502;
if((myProperties.get("Emulation.CPU") == "High") ||
((myProperties.get("Emulation.CPU") == "Auto-detect") && !(size % 8448)))
{
m6502 = new M6502High(1);
}
else
{
m6502 = new M6502Low(1);
}
M6532* m6532 = new M6532(*this);
TIA* tia = new TIA(*this, sound);
Cartridge* cartridge = Cartridge::create(image, size, myProperties);
mySystem->attach(m6502);
mySystem->attach(m6532);
mySystem->attach(tia);
mySystem->attach(cartridge);
// Remember what my media source is
myMediaSource = tia;
// Reset, the system to its power-on state
mySystem->reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Console::Console(const Console& console)
: myEvent(console.myEvent)
{
// TODO: Write this method
assert(false);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Console::~Console()
{
delete mySystem;
delete mySwitches;
delete myControllers[0];
delete myControllers[1];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Properties& Console::properties() const
{
return myProperties;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Console& Console::operator = (const Console&)
{
// TODO: Write this method
assert(false);
return *this;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Properties& Console::defaultProperties()
{
// Make sure the <key,value> pairs are in the default properties object
ourDefaultProperties.set("Cartridge.Filename", "");
ourDefaultProperties.set("Cartridge.MD5", "");
ourDefaultProperties.set("Cartridge.Manufacturer", "");
ourDefaultProperties.set("Cartridge.ModelNo", "");
ourDefaultProperties.set("Cartridge.Name", "Untitled");
ourDefaultProperties.set("Cartridge.Note", "");
ourDefaultProperties.set("Cartridge.Rarity", "");
ourDefaultProperties.set("Cartridge.Type", "Auto-detect");
ourDefaultProperties.set("Console.LeftDifficulty", "B");
ourDefaultProperties.set("Console.RightDifficulty", "B");
ourDefaultProperties.set("Console.TelevisionType", "Color");
ourDefaultProperties.set("Controller.Left", "Joystick");
ourDefaultProperties.set("Controller.Right", "Joystick");
ourDefaultProperties.set("Display.Format", "NTSC");
ourDefaultProperties.set("Display.XStart", "0");
ourDefaultProperties.set("Display.Width", "160");
ourDefaultProperties.set("Display.YStart", "38");
ourDefaultProperties.set("Display.Height", "210");
ourDefaultProperties.set("Emulation.CPU", "Auto-detect");
ourDefaultProperties.set("Emulation.HmoveBlanks", "Yes");
return ourDefaultProperties;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Properties Console::ourDefaultProperties;

View File

@ -0,0 +1,159 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Console.hxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#ifndef CONSOLE_HXX
#define CONSOLE_HXX
class Console;
class Controller;
class Event;
class MediaSource;
class PropertiesSet;
class Sound;
class Switches;
class System;
#include "bspf.hxx"
#include "Control.hxx"
#include "Props.hxx"
/**
This class represents the entire game console.
@author Bradford W. Mott
@version $Id: Console.hxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
*/
class Console
{
public:
/**
Create a new console for emulating the specified game using the
given event object and game profiles.
@param image The ROM image of the game to emulate
@param size The size of the ROM image
@param filename The name of the file that contained the ROM image
@param event The event object to use
@param profiles The game profiles object to use
@param sound The sound object to use
*/
Console(const uInt8* image, uInt32 size, const char* filename,
const Event& event, PropertiesSet& propertiesSet, Sound& sound);
/**
Create a new console object by copying another one
@param console The object to copy
*/
Console(const Console& console);
/**
Destructor
*/
virtual ~Console();
public:
/**
Get the controller plugged into the specified jack
@return The specified controller
*/
Controller& controller(Controller::Jack jack) const
{
return (jack == Controller::Left) ? *myControllers[0] : *myControllers[1];
}
/**
Get the media source of the console
@return The media source
*/
MediaSource& mediaSource() const
{
return *myMediaSource;
}
/**
Get the properties being used by the game
@return The properties being used by the game
*/
const Properties& properties() const;
/**
Get the console switches
@return The console switches
*/
Switches& switches() const
{
return *mySwitches;
}
/**
Get the 6502 based system used by the console to emulate the game
@return The 6502 based system
*/
System& system() const
{
return *mySystem;
}
public:
/**
Overloaded assignment operator
@param console The console object to set myself equal to
@return Myself after assignment has taken place
*/
Console& operator = (const Console& console);
public:
/**
Get the default properties object to use for other properties objects
@return The default properties object
*/
static const Properties& defaultProperties();
private:
// Pointers to the left and right controllers
Controller* myControllers[2];
// Reference to the event object to use
const Event& myEvent;
// Pointer to the media source object
MediaSource* myMediaSource;
// Properties for the game
Properties myProperties;
// Pointer to the switches on the front of the console
Switches* mySwitches;
// Pointer to the 6502 based system being emulated
System* mySystem;
private:
// Default properties to use for properties objects
static Properties ourDefaultProperties;
};
#endif

View File

@ -0,0 +1,54 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Control.cxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#include <assert.h>
#include "Control.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Controller::Controller(Jack jack, const Event& event)
: myJack(jack),
myEvent(event)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Controller::~Controller()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Int32 Controller::maximumResistance = 0x7FFFFFFF;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Int32 Controller::minimumResistance = 0x00000000;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Controller::Controller(const Controller& c)
: myJack(c.myJack),
myEvent(c.myEvent)
{
assert(false);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Controller& Controller::operator = (const Controller&)
{
assert(false);
return *this;
}

View File

@ -0,0 +1,152 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Control.hxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#ifndef CONTROLLER_HXX
#define CONTROLLER_HXX
class Controller;
class Event;
#include "bspf.hxx"
/**
A controller is a device that plugs into either the left or right
controller jack of the Video Computer System (VCS). The pins of
the controller jacks are mapped as follows:
-------------
\ 1 2 3 4 5 /
\ 6 7 8 9 /
---------
Left Controller Right Controller
pin 1 D4 PIA SWCHA D0 PIA SWCHA
pin 2 D5 PIA SWCHA D1 PIA SWCHA
pin 3 D6 PIA SWCHA D2 PIA SWCHA
pin 4 D7 PIA SWCHA D3 PIA SWCHA
pin 5 D7 TIA INPT1 (Dumped) D7 TIA INPT3 (Dumped)
pin 6 D7 TIA INPT4 (Latched) D7 TIA INPT5 (Latched)
pin 7 +5 +5
pin 8 GND GND
pin 9 D7 TIA INPT0 (Dumped) D7 TIA INPT2 (Dumped)
Each of the pins connected to the PIA can be configured as an
input or output pin. The "dumped" TIA pins are used to charge
a capacitor. A potentiometer is sometimes connected to these
pins for analog input.
This is a base class for all controllers. It provides a view
of the controller from the prespective of the controller's jack.
@author Bradford W. Mott
@version $Id: Control.hxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
*/
class Controller
{
public:
/**
Enumeration of the controller jacks
*/
enum Jack
{
Left, Right
};
public:
/**
Create a new controller plugged into the specified jack
@param jack The jack the controller is plugged into
@param event The event object to use for events
*/
Controller(Jack jack, const Event& event);
/**
Destructor
*/
virtual ~Controller();
public:
/**
Enumeration of the digital pins of a controller port
*/
enum DigitalPin
{
One, Two, Three, Four, Six
};
/**
Enumeration of the analog pins of a controller port
*/
enum AnalogPin
{
Five, Nine
};
public:
/**
Read the value of the specified digital pin for this controller.
@param pin The pin of the controller jack to read
@return The state of the pin
*/
virtual bool read(DigitalPin pin) = 0;
/**
Read the resistance at the specified analog pin for this controller.
The returned value is the resistance measured in ohms.
@param pin The pin of the controller jack to read
@return The resistance at the specified pin
*/
virtual Int32 read(AnalogPin pin) = 0;
/**
Write the given value to the specified digital pin for this
controller. Writing is only allowed to the pins associated
with the PIA. Therefore you cannot write to pin six.
@param pin The pin of the controller jack to write to
@param value The value to write to the pin
*/
virtual void write(DigitalPin pin, bool value) = 0;
public:
/// Constant which represents maximum resistance for analog pins
static const Int32 maximumResistance;
/// Constant which represents minimum resistance for analog pins
static const Int32 minimumResistance;
protected:
/// Specifies which jack the controller is plugged in
const Jack myJack;
/// Reference to the event object this controller uses
const Event& myEvent;
protected:
// Copy constructor isn't supported by controllers so make it private
Controller(const Controller&);
// Assignment operator isn't supported by controllers so make it private
Controller& operator = (const Controller&);
};
#endif

View File

@ -0,0 +1,35 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DefProps.cxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#include "DefProps.hxx"
/**
The default properties file is generated from the 'stella.pro' file
using a sed script
*/
static const char* theScript[] = {
#include "DefProps.def"
0
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char** defaultPropertiesFile()
{
return theScript;
}

View File

@ -0,0 +1,31 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: DefProps.hxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#ifndef DEFAULTPROPERTIES_HXX
#define DEFAULTPROPERTIES_HXX
/**
Get the default properties file as an array of pointers to null-terminated
character arrays. The last entry in the array is the null pointer.
@return The default properties file
*/
const char** defaultPropertiesFile();
#endif

View File

@ -0,0 +1,128 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Driving.cxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#include <assert.h>
#include "Event.hxx"
#include "Driving.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Driving::Driving(Jack jack, const Event& event)
: Controller(jack, event)
{
myCounter = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Driving::~Driving()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Driving::read(DigitalPin pin)
{
// Gray codes for clockwise rotation
static const uInt8 clockwise[] = { 0x03, 0x01, 0x00, 0x02 };
// Gray codes for counter-clockwise rotation
static const uInt8 counterclockwise[] = { 0x03, 0x02, 0x00, 0x01 };
// Delay used for moving through the gray code tables
const uInt32 delay = 20;
switch(pin)
{
case One:
++myCounter;
if(myJack == Left)
{
if(myEvent.get(Event::JoystickZeroLeft) != 0)
{
return (counterclockwise[(myCounter / delay) & 0x03] & 0x01) != 0;
}
else if(myEvent.get(Event::JoystickZeroRight) != 0)
{
return (clockwise[(myCounter / delay) & 0x03] & 0x01) != 0;
}
}
else
{
if(myEvent.get(Event::JoystickOneLeft) != 0)
{
return (counterclockwise[(myCounter / delay) & 0x03] & 0x01) != 0;
}
else if(myEvent.get(Event::JoystickOneRight) != 0)
{
return (clockwise[(myCounter / delay) & 0x03] & 0x01) != 0;
}
}
case Two:
if(myJack == Left)
{
if(myEvent.get(Event::JoystickZeroLeft) != 0)
{
return (counterclockwise[(myCounter / delay) & 0x03] & 0x02) != 0;
}
else if(myEvent.get(Event::JoystickZeroRight) != 0)
{
return (clockwise[(myCounter / delay) & 0x03] & 0x02) != 0;
}
}
else
{
if(myEvent.get(Event::JoystickOneLeft) != 0)
{
return (counterclockwise[(myCounter / delay) & 0x03] & 0x02) != 0;
}
else if(myEvent.get(Event::JoystickOneRight) != 0)
{
return (clockwise[(myCounter / delay) & 0x03] & 0x02) != 0;
}
}
case Three:
return true;
case Four:
return true;
case Six:
return (myJack == Left) ? (myEvent.get(Event::JoystickZeroFire) == 0) :
(myEvent.get(Event::JoystickOneFire) == 0);
default:
return true;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 Driving::read(AnalogPin)
{
// Analog pins are not connect in driving controller so we have
// infinite resistance
return maximumResistance;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Driving::write(DigitalPin, bool)
{
// Writing doesn't do anything to the driving controller...
}

View File

@ -0,0 +1,84 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Driving.hxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#ifndef DRIVING_HXX
#define DRIVING_HXX
class Driving;
class System;
#include "bspf.hxx"
#include "Control.hxx"
/**
The standard Atari 2600 Indy 500 driving controller.
@author Bradford W. Mott
@version $Id: Driving.hxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
*/
class Driving : public Controller
{
public:
/**
Create a new Indy 500 driving controller plugged into
the specified jack
@param jack The jack the controller is plugged into
@param event The event object to use for events
*/
Driving(Jack jack, const Event& event);
/**
Destructor
*/
virtual ~Driving();
public:
/**
Read the value of the specified digital pin for this controller.
@param pin The pin of the controller jack to read
@return The state of the pin
*/
virtual bool read(DigitalPin pin);
/**
Read the resistance at the specified analog pin for this controller.
The returned value is the resistance measured in ohms.
@param pin The pin of the controller jack to read
@return The resistance at the specified pin
*/
virtual Int32 read(AnalogPin pin);
/**
Write the given value to the specified digital pin for this
controller. Writing is only allowed to the pins associated
with the PIA. Therefore you cannot write to pin six.
@param pin The pin of the controller jack to write to
@param value The value to write to the pin
*/
virtual void write(DigitalPin pin, bool value);
private:
// Counter to iterate through the gray codes
uInt32 myCounter;
};
#endif

View File

@ -0,0 +1,48 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Event.cxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#include "Event.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event::Event()
: myNumberOfTypes(Event::LastType)
{
// Set all of the events to 0 / false to start with
for(int i = 0; i < myNumberOfTypes; ++i)
{
myValues[i] = 0;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Event::~Event()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 Event::get(Type type) const
{
return myValues[type];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Event::set(Type type, Int32 value)
{
myValues[type] = value;
}

View File

@ -0,0 +1,102 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Event.hxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#ifndef EVENT_HXX
#define EVENT_HXX
class Event;
#include "bspf.hxx"
/**
@author Bradford W. Mott
@version $Id: Event.hxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
*/
class Event
{
public:
/**
Enumeration of console and controller event types
*/
enum Type
{
ConsoleOn, ConsoleOff, ConsoleColor, ConsoleBlackWhite,
ConsoleLeftDifficultyA, ConsoleLeftDifficultyB,
ConsoleRightDifficultyA, ConsoleRightDifficultyB,
ConsoleSelect, ConsoleReset,
JoystickZeroUp, JoystickZeroDown, JoystickZeroLeft,
JoystickZeroRight, JoystickZeroFire,
JoystickOneUp, JoystickOneDown, JoystickOneLeft,
JoystickOneRight, JoystickOneFire,
BoosterGripZeroTrigger, BoosterGripZeroBooster,
BoosterGripOneTrigger, BoosterGripOneBooster,
PaddleZeroResistance, PaddleZeroFire,
PaddleOneResistance, PaddleOneFire,
PaddleTwoResistance, PaddleTwoFire,
PaddleThreeResistance, PaddleThreeFire,
KeyboardZero1, KeyboardZero2, KeyboardZero3,
KeyboardZero4, KeyboardZero5, KeyboardZero6,
KeyboardZero7, KeyboardZero8, KeyboardZero9,
KeyboardZeroStar, KeyboardZero0, KeyboardZeroPound,
KeyboardOne1, KeyboardOne2, KeyboardOne3,
KeyboardOne4, KeyboardOne5, KeyboardOne6,
KeyboardOne7, KeyboardOne8, KeyboardOne9,
KeyboardOneStar, KeyboardOne0, KeyboardOnePound,
DrivingZeroClockwise, DrivingZeroCounterClockwise, DrivingZeroFire,
DrivingOneClockwise, DrivingOneCounterClockwise, DrivingOneFire,
LastType
};
public:
/**
Create a new event object
*/
Event();
/**
Destructor
*/
virtual ~Event();
public:
/**
Get the value associated with the event of the specified type
*/
virtual Int32 get(Type type) const;
/**
Set the value associated with the event of the specified type
*/
virtual void set(Type type, Int32 value);
protected:
// Number of event types there are
const Int32 myNumberOfTypes;
// Array of values associated with each event type
Int32 myValues[LastType];
};
#endif

View File

@ -0,0 +1,76 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Joystick.cxx,v 1.1.1.1 2001-12-27 19:54:21 bwmott Exp $
//============================================================================
#include <assert.h>
#include "Event.hxx"
#include "Joystick.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Joystick::Joystick(Jack jack, const Event& event)
: Controller(jack, event)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Joystick::~Joystick()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Joystick::read(DigitalPin pin)
{
switch(pin)
{
case One:
return (myJack == Left) ? (myEvent.get(Event::JoystickZeroUp) == 0) :
(myEvent.get(Event::JoystickOneUp) == 0);
case Two:
return (myJack == Left) ? (myEvent.get(Event::JoystickZeroDown) == 0) :
(myEvent.get(Event::JoystickOneDown) == 0);
case Three:
return (myJack == Left) ? (myEvent.get(Event::JoystickZeroLeft) == 0) :
(myEvent.get(Event::JoystickOneLeft) == 0);
case Four:
return (myJack == Left) ? (myEvent.get(Event::JoystickZeroRight) == 0) :
(myEvent.get(Event::JoystickOneRight) == 0);
case Six:
return (myJack == Left) ? (myEvent.get(Event::JoystickZeroFire) == 0) :
(myEvent.get(Event::JoystickOneFire) == 0);
default:
return true;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 Joystick::read(AnalogPin)
{
// Analog pins are not connect in joystick so we have infinite resistance
return maximumResistance;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Joystick::write(DigitalPin, bool)
{
// Writing doesn't do anything to the joystick...
}

View File

@ -0,0 +1,76 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Joystick.hxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
//============================================================================
#ifndef JOYSTICK_HXX
#define JOYSTICK_HXX
#include "bspf.hxx"
#include "Control.hxx"
/**
The standard Atari 2600 joystick controller.
@author Bradford W. Mott
@version $Id: Joystick.hxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
*/
class Joystick : public Controller
{
public:
/**
Create a new joystick controller plugged into the specified jack
@param jack The jack the controller is plugged into
@param event The event object to use for events
*/
Joystick(Jack jack, const Event& event);
/**
Destructor
*/
virtual ~Joystick();
public:
/**
Read the value of the specified digital pin for this controller.
@param pin The pin of the controller jack to read
@return The state of the pin
*/
virtual bool read(DigitalPin pin);
/**
Read the resistance at the specified analog pin for this controller.
The returned value is the resistance measured in ohms.
@param pin The pin of the controller jack to read
@return The resistance at the specified pin
*/
virtual Int32 read(AnalogPin pin);
/**
Write the given value to the specified digital pin for this
controller. Writing is only allowed to the pins associated
with the PIA. Therefore you cannot write to pin six.
@param pin The pin of the controller jack to write to
@param value The value to write to the pin
*/
virtual void write(DigitalPin pin, bool value);
};
#endif

View File

@ -0,0 +1,207 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Keyboard.cxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
//============================================================================
#include "Event.hxx"
#include "Keyboard.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Keyboard::Keyboard(Jack jack, const Event& event)
: Controller(jack, event),
myPinState(0)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Keyboard::~Keyboard()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Keyboard::read(DigitalPin pin)
{
if(pin == Six)
{
if((myPinState & 0x01) == 0)
{
return (myJack == Left) ? (myEvent.get(Event::KeyboardZero3) == 0) :
(myEvent.get(Event::KeyboardOne3) == 0);
}
else if((myPinState & 0x02) == 0)
{
return (myJack == Left) ? (myEvent.get(Event::KeyboardZero6) == 0) :
(myEvent.get(Event::KeyboardOne6) == 0);
}
else if((myPinState & 0x04) == 0)
{
return (myJack == Left) ? (myEvent.get(Event::KeyboardZero9) == 0) :
(myEvent.get(Event::KeyboardOne9) == 0);
}
else if((myPinState & 0x08) == 0)
{
return (myJack == Left) ? (myEvent.get(Event::KeyboardZeroPound) == 0) :
(myEvent.get(Event::KeyboardOnePound) == 0);
}
}
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 Keyboard::read(AnalogPin pin)
{
if(pin == Nine)
{
if((myPinState & 0x01) == 0)
{
if(myJack == Left)
{
return (myEvent.get(Event::KeyboardZero1) != 0) ?
maximumResistance : minimumResistance;
}
else
{
return (myEvent.get(Event::KeyboardOne1) != 0) ?
maximumResistance : minimumResistance;
}
}
else if((myPinState & 0x02) == 0)
{
if(myJack == Left)
{
return (myEvent.get(Event::KeyboardZero4) != 0) ?
maximumResistance : minimumResistance;
}
else
{
return (myEvent.get(Event::KeyboardOne4) != 0) ?
maximumResistance : minimumResistance;
}
}
else if((myPinState & 0x04) == 0)
{
if(myJack == Left)
{
return (myEvent.get(Event::KeyboardZero7) != 0) ?
maximumResistance : minimumResistance;
}
else
{
return (myEvent.get(Event::KeyboardOne7) != 0) ?
maximumResistance : minimumResistance;
}
}
else if((myPinState & 0x08) == 0)
{
if(myJack == Left)
{
return (myEvent.get(Event::KeyboardZeroStar) != 0) ?
maximumResistance : minimumResistance;
}
else
{
return (myEvent.get(Event::KeyboardOneStar) != 0) ?
maximumResistance : minimumResistance;
}
}
}
else
{
if((myPinState & 0x01) == 0)
{
if(myJack == Left)
{
return (myEvent.get(Event::KeyboardZero2) != 0) ?
maximumResistance : minimumResistance;
}
else
{
return (myEvent.get(Event::KeyboardOne2) != 0) ?
maximumResistance : minimumResistance;
}
}
else if((myPinState & 0x02) == 0)
{
if(myJack == Left)
{
return (myEvent.get(Event::KeyboardZero5) != 0) ?
maximumResistance : minimumResistance;
}
else
{
return (myEvent.get(Event::KeyboardOne5) != 0) ?
maximumResistance : minimumResistance;
}
}
else if((myPinState & 0x04) == 0)
{
if(myJack == Left)
{
return (myEvent.get(Event::KeyboardZero8) != 0) ?
maximumResistance : minimumResistance;
}
else
{
return (myEvent.get(Event::KeyboardOne8) != 0) ?
maximumResistance : minimumResistance;
}
}
else if((myPinState & 0x08) == 0)
{
if(myJack == Left)
{
return (myEvent.get(Event::KeyboardZero0) != 0) ?
maximumResistance : minimumResistance;
}
else
{
return (myEvent.get(Event::KeyboardOne0) != 0) ?
maximumResistance : minimumResistance;
}
}
}
return maximumResistance;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Keyboard::write(DigitalPin pin, bool value)
{
// Change the pin state based on value
switch(pin)
{
case One:
myPinState = (myPinState & 0x0E) | (value ? 0x01 : 0x00);
break;
case Two:
myPinState = (myPinState & 0x0D) | (value ? 0x02 : 0x00);
break;
case Three:
myPinState = (myPinState & 0x0B) | (value ? 0x04 : 0x00);
break;
case Four:
myPinState = (myPinState & 0x07) | (value ? 0x08 : 0x00);
break;
default:
break;
}
}

View File

@ -0,0 +1,80 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Keyboard.hxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
//============================================================================
#ifndef KEYBOARD_HXX
#define KEYBOARD_HXX
#include "bspf.hxx"
#include "Control.hxx"
/**
The standard Atari 2600 keyboard controller
@author Bradford W. Mott
@version $Id: Keyboard.hxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
*/
class Keyboard : public Controller
{
public:
/**
Create a new keyboard controller plugged into the specified jack
@param jack The jack the controller is plugged into
@param event The event object to use for events
*/
Keyboard(Jack jack, const Event& event);
/**
Destructor
*/
virtual ~Keyboard();
public:
/**
Read the value of the specified digital pin for this controller.
@param pin The pin of the controller jack to read
@return The state of the pin
*/
virtual bool read(DigitalPin pin);
/**
Read the resistance at the specified analog pin for this controller.
The returned value is the resistance measured in ohms.
@param pin The pin of the controller jack to read
@return The resistance at the specified pin
*/
virtual Int32 read(AnalogPin pin);
/**
Write the given value to the specified digital pin for this
controller. Writing is only allowed to the pins associated
with the PIA. Therefore you cannot write to pin six.
@param pin The pin of the controller jack to write to
@param value The value to write to the pin
*/
virtual void write(DigitalPin pin, bool value);
private:
// State of the output pins
uInt8 myPinState;
};
#endif

View File

@ -0,0 +1,306 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6532.cxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
//============================================================================
#include <assert.h>
#include "Console.hxx"
#include "M6532.hxx"
#include "Random.hxx"
#include "Switches.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6532::M6532(const Console& console)
: myConsole(console)
{
// Randomize the 128 bytes of memory
Random random;
for(uInt32 t = 0; t < 128; ++t)
{
myRAM[t] = random.next();
}
// Initialize other data members
reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6532::~M6532()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* M6532::name() const
{
return "M6532";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::reset()
{
myTimer = 100;
myIntervalShift = 6;
myCyclesWhenTimerSet = 0;
myCyclesWhenInterruptReset = 0;
myTimerReadAfterInterrupt = false;
// Zero the I/O registers
myDDRA = 0x00;
myDDRB = 0x00;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::systemCyclesReset()
{
// System cycles are being reset to zero so we need to adjust
// the cycle count we remembered when the timer was last set
myCyclesWhenTimerSet -= mySystem->cycles();
myCyclesWhenInterruptReset -= mySystem->cycles();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::install(System& system)
{
// Remember which system I'm installed in
mySystem = &system;
uInt16 shift = mySystem->pageShift();
uInt16 mask = mySystem->pageMask();
// Make sure the system we're being installed in has a page size that'll work
assert((0x1080 & mask) == 0);
// All accesses are to this device
System::PageAccess access;
access.device = this;
// We're installing in a 2600 system
for(int address = 0; address < 8192; address += (1 << shift))
{
if((address & 0x1080) == 0x0080)
{
if((address & 0x0200) == 0x0000)
{
access.directPeekBase = &myRAM[address & 0x007f];
access.directPokeBase = &myRAM[address & 0x007f];
mySystem->setPageAccess(address >> shift, access);
}
else
{
access.directPeekBase = 0;
access.directPokeBase = 0;
mySystem->setPageAccess(address >> shift, access);
}
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 M6532::peek(uInt16 addr)
{
switch(addr & 0x07)
{
case 0x00: // Port A I/O Register (Joystick)
{
uInt8 value = 0x00;
if(myConsole.controller(Controller::Left).read(Controller::One))
value |= 0x10;
if(myConsole.controller(Controller::Left).read(Controller::Two))
value |= 0x20;
if(myConsole.controller(Controller::Left).read(Controller::Three))
value |= 0x40;
if(myConsole.controller(Controller::Left).read(Controller::Four))
value |= 0x80;
if(myConsole.controller(Controller::Right).read(Controller::One))
value |= 0x01;
if(myConsole.controller(Controller::Right).read(Controller::Two))
value |= 0x02;
if(myConsole.controller(Controller::Right).read(Controller::Three))
value |= 0x04;
if(myConsole.controller(Controller::Right).read(Controller::Four))
value |= 0x08;
return value;
}
case 0x01: // Port A Data Direction Register
{
return myDDRA;
}
case 0x02: // Port B I/O Register (Console switches)
{
return myConsole.switches().read();
}
case 0x03: // Port B Data Direction Register
{
return myDDRB;
}
case 0x04: // Timer Output
case 0x06:
{
uInt32 cycles = mySystem->cycles() - 1;
uInt32 delta = cycles - myCyclesWhenTimerSet;
Int32 timer = (Int32)myTimer - (Int32)(delta >> myIntervalShift) - 1;
// See if the timer has expired yet?
if(timer >= 0)
{
return (uInt8)timer;
}
else
{
timer = (Int32)(myTimer << myIntervalShift) - (Int32)delta - 1;
if((timer <= -2) && !myTimerReadAfterInterrupt)
{
// Indicate that timer has been read after interrupt occured
myTimerReadAfterInterrupt = true;
myCyclesWhenInterruptReset = mySystem->cycles();
}
if(myTimerReadAfterInterrupt)
{
Int32 offset = myCyclesWhenInterruptReset -
(myCyclesWhenTimerSet + (myTimer << myIntervalShift));
timer = (Int32)myTimer - (Int32)(delta >> myIntervalShift) - offset;
}
return (uInt8)timer;
}
}
case 0x05: // Interrupt Flag
case 0x07:
{
uInt32 cycles = mySystem->cycles() - 1;
uInt32 delta = cycles - myCyclesWhenTimerSet;
Int32 timer = (Int32)myTimer - (Int32)(delta >> myIntervalShift) - 1;
if((timer >= 0) || myTimerReadAfterInterrupt)
return 0x00;
else
return 0x80;
}
default:
{
#ifdef DEBUG_ACCESSES
cerr << "BAD M6532 Peek: " << hex << addr << endl;
#endif
return 0;
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6532::poke(uInt16 addr, uInt8 value)
{
if((addr & 0x07) == 0x00) // Port A I/O Register (Joystick)
{
uInt8 a = value & myDDRA;
myConsole.controller(Controller::Left).write(Controller::One, a & 0x10);
myConsole.controller(Controller::Left).write(Controller::Two, a & 0x20);
myConsole.controller(Controller::Left).write(Controller::Three, a & 0x40);
myConsole.controller(Controller::Left).write(Controller::Four, a & 0x80);
myConsole.controller(Controller::Right).write(Controller::One, a & 0x01);
myConsole.controller(Controller::Right).write(Controller::Two, a & 0x02);
myConsole.controller(Controller::Right).write(Controller::Three, a & 0x04);
myConsole.controller(Controller::Right).write(Controller::Four, a & 0x08);
}
else if((addr & 0x07) == 0x01) // Port A Data Direction Register
{
myDDRA = value;
}
else if((addr & 0x07) == 0x02) // Port B I/O Register (Console switches)
{
return;
}
else if((addr & 0x07) == 0x03) // Port B Data Direction Register
{
// myDDRB = value;
return;
}
else if((addr & 0x17) == 0x14) // Write timer divide by 1
{
myTimer = value;
myIntervalShift = 0;
myCyclesWhenTimerSet = mySystem->cycles();
myTimerReadAfterInterrupt = false;
}
else if((addr & 0x17) == 0x15) // Write timer divide by 8
{
myTimer = value;
myIntervalShift = 3;
myCyclesWhenTimerSet = mySystem->cycles();
myTimerReadAfterInterrupt = false;
}
else if((addr & 0x17) == 0x16) // Write timer divide by 64
{
myTimer = value;
myIntervalShift = 6;
myCyclesWhenTimerSet = mySystem->cycles();
myTimerReadAfterInterrupt = false;
}
else if((addr & 0x17) == 0x17) // Write timer divide by 1024
{
myTimer = value;
myIntervalShift = 10;
myCyclesWhenTimerSet = mySystem->cycles();
myTimerReadAfterInterrupt = false;
}
else if((addr & 0x14) == 0x04) // Write Edge Detect Control
{
#ifdef DEBUG_ACCESSES
cerr << "M6532 Poke (Write Edge Detect): "
<< ((addr & 0x02) ? "PA7 enabled" : "PA7 disabled")
<< ", "
<< ((addr & 0x01) ? "Positive edge" : "Negative edge")
<< endl;
#endif
}
else
{
#ifdef DEBUG_ACCESSES
cerr << "BAD M6532 Poke: " << hex << addr << endl;
#endif
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6532::M6532(const M6532& c)
: myConsole(c.myConsole)
{
assert(false);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6532& M6532::operator = (const M6532&)
{
assert(false);
return *this;
}

View File

@ -0,0 +1,129 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6532.hxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
//============================================================================
#ifndef M6532_HXX
#define M6532_HXX
class Console;
class System;
#include "bspf.hxx"
#include "Device.hxx"
/**
RIOT
@author Bradford W. Mott
@version $Id: M6532.hxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
*/
class M6532 : public Device
{
public:
/**
Create a new 6532 for the specified console
@param console The console the 6532 is associated with
*/
M6532(const Console& console);
/**
Destructor
*/
virtual ~M6532();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset cartridge to its power-on state
*/
virtual void reset();
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
virtual void systemCyclesReset();
/**
Install 6532 in the specified system. Invoked by the system
when the 6532 is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
private:
// Reference to the console
const Console& myConsole;
// An amazing 128 bytes of RAM
uInt8 myRAM[128];
// Current value of my Timer
uInt32 myTimer;
// Log base 2 of the number of cycles in a timer interval
uInt32 myIntervalShift;
// Indicates the number of cycles when the timer was last set
Int32 myCyclesWhenTimerSet;
// Indicates when the timer was read after timer interrupt occured
Int32 myCyclesWhenInterruptReset;
// Indicates if a read from timer has taken place after interrupt occured
bool myTimerReadAfterInterrupt;
// Data Direction Register for Port A
uInt8 myDDRA;
// Data Direction Register for Port B
uInt8 myDDRB;
private:
// Copy constructor isn't supported by this class so make it private
M6532(const M6532&);
// Assignment operator isn't supported by this class so make it private
M6532& operator = (const M6532&);
};
#endif

347
stella/src/emucore/MD5.cxx Normal file
View File

@ -0,0 +1,347 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// This file is derived from the RSA Data Security, Inc. MD5 Message-Digest
// Algorithm. See the header below for copyright information.
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: MD5.cxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
//============================================================================
#include "MD5.hxx"
/*
Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
// Setup the types used by the MD5 routines
typedef unsigned char* POINTER;
typedef uInt16 UINT2;
typedef uInt32 UINT4;
// MD5 context.
typedef struct
{
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
// Constants for MD5Transform routine.
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
static void MD5Init(MD5_CTX*);
static void MD5Update(MD5_CTX*, const unsigned char*, unsigned int);
static void MD5Final(unsigned char[16], MD5_CTX*);
static void MD5Transform(UINT4 [4], const unsigned char [64]);
static void Encode(unsigned char*, UINT4*, unsigned int);
static void Decode(UINT4*, const unsigned char*, unsigned int);
static void MD5_memcpy(POINTER, POINTER, unsigned int);
static void MD5_memset(POINTER, int, unsigned int);
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
// F, G, H and I are basic MD5 functions.
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
// ROTATE_LEFT rotates x left n bits.
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
// Rotation is separate from addition to prevent recomputation.
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
// MD5 initialization. Begins an MD5 operation, writing a new context.
static void MD5Init(MD5_CTX* context)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants. */
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
// MD5 block update operation. Continues an MD5 message-digest
// operation, processing another message block, and updating the
// context.
static void MD5Update(MD5_CTX* context, const unsigned char* input,
unsigned int inputLen)
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible. */
if (inputLen >= partLen) {
MD5_memcpy ((POINTER)&context->buffer[index], (POINTER)input, partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
MD5_memcpy((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
}
// MD5 finalization. Ends an MD5 message-digest operation, writing the
// the message digest and zeroizing the context.
static void MD5Final(unsigned char digest[16], MD5_CTX* context)
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64. */
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information. */
MD5_memset ((POINTER)context, 0, sizeof (*context));
}
// MD5 basic transformation. Transforms state based on block.
static void MD5Transform(UINT4 state[4], const unsigned char block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information. */
MD5_memset ((POINTER)x, 0, sizeof (x));
}
// Encodes input (UINT4) into output (unsigned char). Assumes len is
// a multiple of 4.
static void Encode(unsigned char* output, UINT4* input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
// Decodes input (unsigned char) into output (UINT4). Assumes len is
// a multiple of 4.
static void Decode(UINT4* output, const unsigned char* input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
// Note: Replace "for loop" with standard memcpy if possible.
static void MD5_memcpy(POINTER output, POINTER input, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
// Note: Replace "for loop" with standard memset if possible.
static void MD5_memset(POINTER output, int value, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string MD5(const uInt8* buffer, uInt32 length)
{
char hex[] = "0123456789abcdef";
MD5_CTX context;
unsigned char md5[16];
MD5Init(&context);
MD5Update(&context, buffer, length);
MD5Final(md5, &context);
string result;
for(int t = 0; t < 16; ++t)
{
result += hex[(md5[t] >> 4) & 0x0f];
result += hex[md5[t] & 0x0f];
}
return result;
}

View File

@ -0,0 +1,35 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: MD5.hxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
//============================================================================
#ifndef MD5_HXX
#define MD5_HXX
#include "bspf.hxx"
/**
Get the MD5 Message-Digest of the specified message with the
given length. The digest consists of 32 hexadecimal digits.
@param buffer The message to compute the digest of
@param length The length of the message
@return The message-digest
*/
string MD5(const uInt8* buffer, uInt32 length);
#endif

View File

@ -0,0 +1,44 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: MediaSrc.cxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
//============================================================================
#include <assert.h>
#include "MediaSrc.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MediaSource::MediaSource()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MediaSource::~MediaSource()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MediaSource::MediaSource(const MediaSource&)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
MediaSource& MediaSource::operator = (const MediaSource&)
{
assert(false);
return *this;
}

View File

@ -0,0 +1,105 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: MediaSrc.hxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
//============================================================================
#ifndef MEDIASOURCE_HXX
#define MEDIASOURCE_HXX
class MediaSource;
#include "bspf.hxx"
/**
This class provides an interface for accessing graphics data.
@author Bradford W. Mott
@version $Id: MediaSrc.hxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
*/
class MediaSource
{
public:
/**
Create a new media source
*/
MediaSource();
/**
Destructor
*/
virtual ~MediaSource();
public:
/**
This method should be called at an interval corresponding to
the desired frame rate to update the media source.
*/
virtual void update() = 0;
/**
Answers the current frame buffer
@return Pointer to the current frame buffer
*/
virtual uInt8* currentFrameBuffer() const = 0;
/**
Answers the previous frame buffer
@return Pointer to the previous frame buffer
*/
virtual uInt8* previousFrameBuffer() const = 0;
public:
/**
Get the palette which maps frame data to RGB values.
@return Array of integers which represent the palette (RGB)
*/
virtual const uInt32* palette() const = 0;
/**
Answers the height of the frame buffer
@return The frame's height
*/
virtual uInt32 height() const = 0;
/**
Answers the width of the frame buffer
@return The frame's width
*/
virtual uInt32 width() const = 0;
public:
/**
Answers the total number of scanlines the media source generated
in producing the current frame buffer.
@return The total number of scanlines generated
*/
virtual uInt32 scanlines() const = 0;
private:
// Copy constructor isn't supported by this class so make it private
MediaSource(const MediaSource&);
// Assignment operator isn't supported by this class so make it private
MediaSource& operator = (const MediaSource&);
};
#endif

View File

@ -0,0 +1,76 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Paddles.cxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $
//============================================================================
#include <assert.h>
#include "Event.hxx"
#include "Paddles.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Paddles::Paddles(Jack jack, const Event& event)
: Controller(jack, event)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Paddles::~Paddles()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Paddles::read(DigitalPin pin)
{
switch(pin)
{
case Three:
return (myJack == Left) ? (myEvent.get(Event::PaddleOneFire) == 0) :
(myEvent.get(Event::PaddleThreeFire) == 0);
case Four:
return (myJack == Left) ? (myEvent.get(Event::PaddleZeroFire) == 0) :
(myEvent.get(Event::PaddleTwoFire) == 0);
default:
// Other pins are not connected (floating high)
return true;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 Paddles::read(AnalogPin pin)
{
switch(pin)
{
case Five:
return (myJack == Left) ? myEvent.get(Event::PaddleOneResistance) :
myEvent.get(Event::PaddleThreeResistance);
case Nine:
return (myJack == Left) ? myEvent.get(Event::PaddleZeroResistance) :
myEvent.get(Event::PaddleTwoResistance);
default:
return maximumResistance;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Paddles::write(DigitalPin, bool)
{
// Writing doesn't do anything to the paddles...
}

View File

@ -0,0 +1,76 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Paddles.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
//============================================================================
#ifndef PADDLES_HXX
#define PADDLES_HXX
#include "bspf.hxx"
#include "Control.hxx"
/**
The standard Atari 2600 pair of paddle controllers.
@author Bradford W. Mott
@version $Id: Paddles.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
*/
class Paddles : public Controller
{
public:
/**
Create a new pair of paddle controllers plugged into the specified jack
@param jack The jack the controller is plugged into
@param event The event object to use for events
*/
Paddles(Jack jack, const Event& event);
/**
Destructor
*/
virtual ~Paddles();
public:
/**
Read the value of the specified digital pin for this controller.
@param pin The pin of the controller jack to read
@return The state of the pin
*/
virtual bool read(DigitalPin pin);
/**
Read the resistance at the specified analog pin for this controller.
The returned value is the resistance measured in ohms.
@param pin The pin of the controller jack to read
@return The resistance at the specified pin
*/
virtual Int32 read(AnalogPin pin);
/**
Write the given value to the specified digital pin for this
controller. Writing is only allowed to the pins associated
with the PIA. Therefore you cannot write to pin six.
@param pin The pin of the controller jack to write to
@param value The value to write to the pin
*/
virtual void write(DigitalPin pin, bool value);
};
#endif

View File

@ -0,0 +1,258 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Props.cxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
//============================================================================
#include "Props.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Properties::Properties(const Properties* defaults)
{
myDefaults = defaults;
myCapacity = 16;
myProperties = new Property[myCapacity];
mySize = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Properties::Properties(const Properties& properties)
{
copy(properties);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Properties::~Properties()
{
// Free the properties array
delete[] myProperties;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string Properties::get(const string& key) const
{
// Try to find the named property and answer its value
for(uInt32 i = 0; i < mySize; ++i)
{
if(key == myProperties[i].key)
{
return myProperties[i].value;
}
}
// Oops, property wasn't found so ask defaults if we have one
if(myDefaults != 0)
{
// Ask the default properties object to find the key
return myDefaults->get(key);
}
else
{
// No default properties object so just return the empty string
return "";
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Properties::set(const string& key, const string& value)
{
// See if the property already exists
for(uInt32 i = 0; i < mySize; ++i)
{
if(key == myProperties[i].key)
{
myProperties[i].value = value;
return;
}
}
// See if the array needs to be resized
if(mySize == myCapacity)
{
// Yes, so we'll make the array twice as large
Property* newProperties = new Property[myCapacity * 2];
for(uInt32 i = 0; i < mySize; ++i)
{
newProperties[i] = myProperties[i];
}
delete[] myProperties;
myProperties = newProperties;
myCapacity *= 2;
}
// Add new property to the array
myProperties[mySize].key = key;
myProperties[mySize].value = value;
++mySize;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Properties::load(istream& in)
{
// Empty my property array
mySize = 0;
// Loop reading properties
for(;;)
{
// Get the key associated with this property
string key = readQuotedString(in);
// Make sure the stream is still okay
if(!in)
{
return;
}
// A null key signifies the end of the property list
if(key == "")
{
break;
}
// Get the value associated with this property
string value = readQuotedString(in);
// Make sure the stream is still okay
if(!in)
{
return;
}
// Set the property
set(key, value);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Properties::save(ostream& out)
{
// Write out each of the key and value pairs
for(uInt32 i = 0; i < mySize; ++i)
{
writeQuotedString(out, myProperties[i].key);
out.put(' ');
writeQuotedString(out, myProperties[i].value);
out.put('\n');
}
// Put a trailing null string so we know when to stop reading
writeQuotedString(out, "");
out.put('\n');
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string Properties::readQuotedString(istream& in)
{
char c;
// Read characters until we see a quote
while(in.get(c))
{
if(c == '"')
{
break;
}
}
// Read characters until we see the close quote
string s;
while(in.get(c))
{
if((c == '\\') && (in.peek() == '"'))
{
in.get(c);
}
else if((c == '\\') && (in.peek() == '\\'))
{
in.get(c);
}
else if(c == '"')
{
break;
}
else if(c == '\r')
{
continue;
}
s += c;
}
return s;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Properties::writeQuotedString(ostream& out, const string& s)
{
out.put('"');
for(uInt32 i = 0; i < s.length(); ++i)
{
if(s[i] == '\\')
{
out.put('\\');
out.put('\\');
}
else if(s[i] == '\"')
{
out.put('\\');
out.put('"');
}
else
{
out.put(s[i]);
}
}
out.put('"');
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Properties& Properties::operator = (const Properties& properties)
{
// Do the assignment only if this isn't a self assignment
if(this != &properties)
{
// Free the properties array
delete[] myProperties;
// Now, make myself a copy of the given object
copy(properties);
}
return *this;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Properties::copy(const Properties& properties)
{
// Remember the defaults to use
myDefaults = properties.myDefaults;
// Create an array of the same size as properties
myCapacity = properties.myCapacity;
myProperties = new Property[myCapacity];
// Now, copy each property from properties
mySize = properties.mySize;
for(uInt32 i = 0; i < mySize; ++i)
{
myProperties[i] = properties.myProperties[i];
}
}

View File

@ -0,0 +1,150 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Props.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
//============================================================================
#ifndef PROPERTIES_HXX
#define PROPERTIES_HXX
#include "bspf.hxx"
/**
This class represents objects which maintain a collection of
properties. A property is a key and its corresponding value.
A properties object can contain a reference to another properties
object as its "defaults"; this second properties object is searched
if the property key is not found in the original property list.
@author Bradford W. Mott
@version $Id: Props.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
*/
class Properties
{
public:
/**
Creates an empty properties object with the specified defaults. The
new properties object does not claim ownership of the defaults.
@param defaults The defaults
*/
Properties(const Properties* defaults = 0);
/**
Creates a properties list by copying another one
@param properties The properties to copy
*/
Properties(const Properties& properties);
/**
Destructor
*/
virtual ~Properties();
public:
/**
Get the value assigned to the specified key. If the key does
not exist then the empty string is returned.
@param key The key of the property to lookup
@return The value of the property
*/
string get(const string& key) const;
/**
Set the value associated with key to the given value.
@param key The key of the property to set
@param value The value to assign to the property
*/
void set(const string& key, const string& value);
public:
/**
Load properties from the specified input stream
@param in The input stream to use
*/
void load(istream& in);
/**
Save properties to the specified output stream
@param out The output stream to use
*/
void save(ostream& out);
public:
/**
Read the next quoted string from the specified input stream
and returns it.
@param in The input stream to use
@return The string inside the quotes
*/
static string readQuotedString(istream& in);
/**
Write the specified string to the given output stream as a
quoted string.
@param out The output stream to use
@param s The string to output
*/
static void writeQuotedString(ostream& out, const string& s);
public:
/**
Overloaded assignment operator
@param properties The properties object to set myself equal to
@return Myself after assignment has taken place
*/
Properties& operator = (const Properties& properties);
private:
/**
Helper function to perform a deep copy of the specified
properties. Assumes that old properties have already been
freed.
@param properties The properties object to copy myself from
*/
void copy(const Properties& properties);
private:
// Structure used for storing properties
struct Property
{
string key;
string value;
};
// Pointer to properties object to use for defaults or the null pointer
const Properties* myDefaults;
// Pointer to a dynamically allocated array of properties
Property* myProperties;
// Current capacity of the properties array
unsigned int myCapacity;
// Size of the properties array (i.e. the number of <key,value> pairs)
unsigned int mySize;
};
#endif

View File

@ -0,0 +1,206 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: PropsSet.cxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
//============================================================================
#include <assert.h>
#include "Props.hxx"
#include "PropsSet.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropertiesSet::PropertiesSet(const string& key)
: myKey(key)
{
myCapacity = 16;
myProperties = new Properties[myCapacity];
mySize = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropertiesSet::PropertiesSet(const PropertiesSet& p)
: myKey(p.myKey)
{
myCapacity = p.myCapacity;
myProperties = new Properties[myCapacity];
mySize = p.mySize;
// Copy the properties from the other set
for(uInt32 i = 0; i < mySize; ++i)
{
myProperties[i] = p.myProperties[i];
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropertiesSet::~PropertiesSet()
{
delete[] myProperties;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const Properties& PropertiesSet::get(uInt32 i)
{
// Make sure index is within range
assert(i < mySize);
return myProperties[i];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PropertiesSet::insert(const Properties& properties)
{
uInt32 i;
uInt32 j;
// Get the key of the properties
string name = properties.get(myKey);
// See if the key already exists (we could use a binary search here...)
for(i = 0; i < mySize; ++i)
{
if(name == myProperties[i].get(myKey))
{
// Copy the properties which are being inserted
myProperties[i] = properties;
return;
}
}
// See if the properties array needs to be resized
if(mySize == myCapacity)
{
Properties* newProperties = new Properties[myCapacity *= 2];
for(i = 0; i < mySize; ++i)
{
newProperties[i] = myProperties[i];
}
delete[] myProperties;
myProperties = newProperties;
}
// Find the correct place to insert the properties at
for(i = 0; (i < mySize) && (myProperties[i].get(myKey) < name); ++i);
// Okay, make room for the properties
for(j = mySize; j > i; --j)
{
myProperties[j] = myProperties[j - 1];
}
// Now, put the properties in the array
myProperties[i] = properties;
++mySize;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 PropertiesSet::size() const
{
return mySize;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PropertiesSet::erase(uInt32 i)
{
// Make sure index is within range
assert(i < mySize);
for(uInt32 j = i + 1; j < mySize; ++j)
{
myProperties[j - 1] = myProperties[j];
}
--mySize;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PropertiesSet::load(istream& in, const Properties* defaults)
{
// Empty my properties array
mySize = 0;
// Loop reading properties
for(;;)
{
// Read char's until we see a quote as the next char or EOF is reached
while(in && (in.peek() != '"'))
{
char c;
in.get(c);
// If we see the comment character then ignore the line
if(c == ';')
{
while(in && (c != '\n'))
{
in.get(c);
}
}
}
// Make sure the stream is still good or we're done
if(!in)
{
break;
}
// Get the property list associated with this profile
Properties properties(defaults);
properties.load(in);
// If the stream is still good then insert the properties
if(in)
{
insert(properties);
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PropertiesSet::save(ostream& out)
{
// Write each of the properties out
for(uInt32 i = 0; i < mySize; ++i)
{
myProperties[i].save(out);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropertiesSet& PropertiesSet::operator = (const PropertiesSet& p)
{
if(this != &p)
{
delete[] myProperties;
myKey = p.myKey;
myCapacity = p.myCapacity;
myProperties = new Properties[myCapacity];
mySize = p.mySize;
// Copy the properties from the other set
for(uInt32 i = 0; i < mySize; ++i)
{
myProperties[i] = p.myProperties[i];
}
}
return *this;
}

View File

@ -0,0 +1,128 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: PropsSet.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
//============================================================================
#ifndef PROPERTIESSET_HXX
#define PROPERTIESSET_HXX
class Properties;
#include "bspf.hxx"
#include "Props.hxx"
/**
This class maintains a sorted collection of properties. Upon
construction one property is distinguished as the key for sorting.
@author Bradford W. Mott
@version $Id: PropsSet.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
*/
class PropertiesSet
{
public:
/**
Create an empty properties set object using the specified
property as the key for sorting.
@param key The property to use as the key
*/
PropertiesSet(const string& key);
/**
Create a properties set object by copying another one
@param set The properties set to copy
*/
PropertiesSet(const PropertiesSet& set);
/**
Destructor
*/
virtual ~PropertiesSet();
public:
/**
Get the i'th properties from the set
@param i The index of the properties to get
@return The properties stored at the i'th location
*/
const Properties& get(uInt32 i);
/**
Insert the properties into the set. If a duplicate is inserted
the old properties are overwritten with the new ones.
@param properties The collection of properties
*/
void insert(const Properties& properties);
/**
Get the number of properties in the collection.
@return The number of properties in the collection
*/
uInt32 size() const;
/**
Erase the i'th properties from the collection.
@param i The profile index
*/
void erase(uInt32 i);
public:
/**
Load properties from the specified input stream. Use the given
defaults properties as the defaults for any properties loaded.
@param in The input stream to use
@param defaults The default properties to use
*/
void load(istream& in, const Properties* defaults);
/**
Save properties to the specified output stream
@param out The output stream to use
*/
void save(ostream& out);
public:
/**
Overloaded assignment operator
@param propertiesSet The properties set to set myself equal to
@return Myself after assignment has taken place
*/
PropertiesSet& operator = (const PropertiesSet& propertiesSet);
private:
// Property to use as the key
string myKey;
// Pointer to a dynamically allocated array of properties
Properties* myProperties;
// Current capacity of the properties array
unsigned int myCapacity;
// The size of the properties array (i.e. the number of properties in it)
unsigned int mySize;
};
#endif

View File

@ -0,0 +1,53 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Random.cxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
//============================================================================
#include <time.h>
#include "Random.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Random::seed(uInt32 value)
{
ourSeed = value;
ourSeeded = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Random::Random()
{
// If we haven't been seeded then seed ourself
if(!ourSeeded)
{
ourSeed = (uInt32)time(0);
ourSeeded = true;
}
myValue = ourSeed;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 Random::next()
{
return (myValue = (myValue * 2416 + 374441) % 1771875);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 Random::ourSeed = 0;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool Random::ourSeeded = false;

View File

@ -0,0 +1,69 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Random.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
//============================================================================
#ifndef RANDOM_HXX
#define RANDOM_HXX
#include "bspf.hxx"
/**
This is a quick-and-dirty random number generator. It is based on
information in Chapter 7 of "Numerical Recipes in C". It's a simple
linear congruential generator.
@author Bradford W. Mott
@version $Id: Random.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
*/
class Random
{
public:
/**
Class method which allows you to set the seed that'll be used
for created new instances of this class
@param value The value to seed the random number generator with
*/
static void seed(uInt32 value);
public:
/**
Create a new random number generator
*/
Random();
public:
/**
Answer the next random number from the random number generator
@return A random number
*/
uInt32 next();
private:
// Indicates the next random number
uInt32 myValue;
private:
// Seed to use for creating new random number generators
static uInt32 ourSeed;
// Indicates if seed has been set or not
static bool ourSeeded;
};
#endif

View File

@ -0,0 +1,44 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Sound.cxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
//============================================================================
#include "Sound.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Sound::Sound()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Sound::~Sound()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Sound::set(Sound::Register, uInt8)
{
// This sound class doesn't do anything when a register is set
// since we're not handling sound
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Sound::mute(bool)
{
// There's nothing for us to do when the sound is muted since
// we're not handling sound
}

View File

@ -0,0 +1,71 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Sound.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
//============================================================================
#ifndef SOUND_HXX
#define SOUND_HXX
#include "bspf.hxx"
/**
Base class that defines the standard API for sound classes. You
should derive a new class from this one to create a new sound system
for a specific operating system.
@author Bradford W. Mott
@version $Id: Sound.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
*/
class Sound
{
public:
/**
Enumeration of the TIA sound registers
*/
enum Register
{
AUDF0, AUDF1, AUDC0, AUDC1, AUDV0, AUDV1
};
public:
/**
Create a new sound object
*/
Sound();
/**
Destructor
*/
virtual ~Sound();
public:
/**
Set the value of the specified sound register
@param reg The sound register to set
@param val The new value for the sound register
*/
virtual void set(Sound::Register reg, uInt8 val);
/**
Set the mute state of the sound object
@param state Mutes sound iff true
*/
virtual void mute(bool state);
};
#endif

View File

@ -0,0 +1,111 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Switches.cxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
//============================================================================
#include "Event.hxx"
#include "Props.hxx"
#include "Switches.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Switches::Switches(const Event& event, const Properties& properties)
: myEvent(event),
mySwitches(0xFF)
{
if(properties.get("Console.RightDifficulty") == "B")
{
mySwitches &= ~0x80;
}
else
{
mySwitches |= 0x80;
}
if(properties.get("Console.LeftDifficulty") == "B")
{
mySwitches &= ~0x40;
}
else
{
mySwitches |= 0x40;
}
if(properties.get("Console.TelevisionType") == "Color")
{
mySwitches |= 0x08;
}
else
{
mySwitches &= ~0x08;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Switches::~Switches()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 Switches::read()
{
if(myEvent.get(Event::ConsoleColor) != 0)
{
mySwitches |= 0x08;
}
else if(myEvent.get(Event::ConsoleBlackWhite) != 0)
{
mySwitches &= ~0x08;
}
if(myEvent.get(Event::ConsoleRightDifficultyA) != 0)
{
mySwitches &= ~0x80;
}
else if(myEvent.get(Event::ConsoleRightDifficultyB) != 0)
{
mySwitches |= 0x80;
}
if(myEvent.get(Event::ConsoleLeftDifficultyA) != 0)
{
mySwitches &= ~0x40;
}
else if(myEvent.get(Event::ConsoleLeftDifficultyB) != 0)
{
mySwitches |= 0x40;
}
if(myEvent.get(Event::ConsoleSelect) != 0)
{
mySwitches &= ~0x02;
}
else
{
mySwitches |= 0x02;
}
if(myEvent.get(Event::ConsoleReset) != 0)
{
mySwitches &= ~0x01;
}
else
{
mySwitches |= 0x01;
}
return mySwitches;
}

View File

@ -0,0 +1,66 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Switches.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
//============================================================================
#ifndef SWITCHES_HXX
#define SWITCHES_HXX
class Event;
class Properties;
class Switches;
#include "bspf.hxx"
/**
This class represents the console switches of the game console.
@author Bradford W. Mott
@version $Id: Switches.hxx,v 1.1.1.1 2001-12-27 19:54:23 bwmott Exp $
*/
class Switches
{
public:
/**
Create a new set of switches using the specified events and
properties
@param event The event object to use for events
*/
Switches(const Event& event, const Properties& properties);
/**
Destructor
*/
virtual ~Switches();
public:
/**
Get the value of the console switches
@return The 8 bits which represent the state of the console switches
*/
uInt8 read();
private:
// Reference to the event object to use
const Event& myEvent;
// State of the console switches
uInt8 mySwitches;
};
#endif

2698
stella/src/emucore/TIA.cxx Normal file

File diff suppressed because it is too large Load Diff

422
stella/src/emucore/TIA.hxx Normal file
View File

@ -0,0 +1,422 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: TIA.hxx,v 1.1.1.1 2001-12-27 19:54:25 bwmott Exp $
//============================================================================
#ifndef TIA_HXX
#define TIA_HXX
class Console;
class System;
#include "bspf.hxx"
#include "Device.hxx"
#include "MediaSrc.hxx"
/**
This class is a device that emulates the Television Interface Adapator
found in the Atari 2600 and 7800 consoles. The Television Interface
Adapator is an integrated circuit designed to interface between an
eight bit microprocessor and a television video modulator. It converts
eight bit parallel data into serial outputs for the color, luminosity,
and composite sync required by a video modulator.
This class outputs the serial data into a frame buffer which can then
be displayed on screen.
@author Bradford W. Mott
@version $Id: TIA.hxx,v 1.1.1.1 2001-12-27 19:54:25 bwmott Exp $
*/
class TIA : public Device , public MediaSource
{
public:
/**
Create a new TIA for the specified console
@param console The console the TIA is associated with
*/
TIA(const Console& console, Sound& sound);
/**
Destructor
*/
virtual ~TIA();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
virtual void systemCyclesReset();
/**
Install TIA in the specified system. Invoked by the system
when the TIA is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
public:
/**
This method should be called at an interval corresponding to
the desired frame rate to update the media source.
*/
virtual void update();
/**
Answers the current frame buffer
@return Pointer to the current frame buffer
*/
uInt8* currentFrameBuffer() const { return myCurrentFrameBuffer; }
/**
Answers the previous frame buffer
@return Pointer to the previous frame buffer
*/
uInt8* previousFrameBuffer() const { return myPreviousFrameBuffer; }
/**
Get the palette which maps frame data to RGB values.
@return Array of integers which represent the palette (RGB)
*/
virtual const uInt32* palette() const;
/**
Answers the height of the frame buffer
@return The frame's height
*/
uInt32 height() const;
/**
Answers the width of the frame buffer
@return The frame's width
*/
uInt32 width() const;
/**
Answers the total number of scanlines the media source generated
in producing the current frame buffer.
@return The total number of scanlines generated
*/
uInt32 scanlines() const;
private:
// Compute the ball mask table
void computeBallMaskTable();
// Compute the collision decode table
void computeCollisionTable();
// Compute the missle mask table
void computeMissleMaskTable();
// Compute the player mask table
void computePlayerMaskTable();
// Compute the player position reset when table
void computePlayerPositionResetWhenTable();
// Compute the player reflect table
void computePlayerReflectTable();
// Compute playfield mask table
void computePlayfieldMaskTable();
private:
// Update the current frame buffer up to one scanline
void updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos);
// Update the current frame buffer to the specified color clock
void updateFrame(Int32 clock);
// Waste cycles until the current scanline is finished
void waitHorizontalSync();
private:
// Console the TIA is associated with
const Console& myConsole;
// Sound object used by the TIA
Sound& mySound;
private:
// Pointer to the current frame buffer
uInt8* myCurrentFrameBuffer;
// Pointer to the previous frame buffer
uInt8* myPreviousFrameBuffer;
// Pointer to the next pixel that will be drawn in the current frame buffer
uInt8* myFramePointer;
// Indicates where the scanline should start being displayed
uInt32 myFrameXStart;
// Indicates the width of the scanline
uInt32 myFrameWidth;
// Indicated what scanline the frame should start being drawn at
uInt32 myFrameYStart;
// Indicates the height of the frame in scanlines
uInt32 myFrameHeight;
private:
// Indicates offset in color clocks when display should begin
uInt32 myStartDisplayOffset;
// Indicates offset in color clocks when display should stop
uInt32 myStopDisplayOffset;
private:
// Indicates color clocks when the current frame began
Int32 myClockWhenFrameStarted;
// Indicates color clocks when frame should begin to be drawn
Int32 myClockStartDisplay;
// Indicates color clocks when frame should stop being drawn
Int32 myClockStopDisplay;
// Indicates color clocks when the frame was last updated
Int32 myClockAtLastUpdate;
// Indicates how many color clocks remain until the end of
// current scanline. This value is valid during the
// displayed portion of the frame.
Int32 myClocksToEndOfScanLine;
// Indicates the total number of scanlines generated by the last frame
Int32 myScanlineCountForFrame;
private:
// Color clock when VSYNC ending causes a new frame to be started
Int32 myVSYNCFinishClock;
private:
enum
{
myP0Bit = 0x01, // Bit for Player 0
myM0Bit = 0x02, // Bit for Missle 0
myP1Bit = 0x04, // Bit for Player 1
myM1Bit = 0x08, // Bit for Missle 1
myBLBit = 0x10, // Bit for Ball
myPFBit = 0x20, // Bit for Playfield
ScoreBit = 0x40, // Bit for Playfield score mode
PriorityBit = 0x080 // Bit for Playfield priority
};
// Bitmap of the objects that should be considered while drawing
uInt8 myEnabledObjects;
private:
uInt8 myVSYNC; // Holds the VSYNC register value
uInt8 myVBLANK; // Holds the VBLANK register value
uInt8 myNUSIZ0; // Number and size of player 0 and missle 0
uInt8 myNUSIZ1; // Number and size of player 1 and missle 1
uInt8 myPlayfieldPriorityAndScore;
uInt32 myColor[4];
uInt8 myPriorityEncoder[2][256];
uInt32& myCOLUBK; // Background color register (replicated 4 times)
uInt32& myCOLUPF; // Playfield color register (replicated 4 times)
uInt32& myCOLUP0; // Player 0 color register (replicated 4 times)
uInt32& myCOLUP1; // Player 1 color register (replicated 4 times)
uInt8 myCTRLPF; // Playfield control register
bool myREFP0; // Indicates if player 0 is being reflected
bool myREFP1; // Indicates if player 1 is being reflected
uInt32 myPF; // Playfield graphics (19-12:PF2 11-4:PF1 3-0:PF0)
uInt8 myGRP0; // Player 0 graphics register
uInt8 myGRP1; // Player 1 graphics register
uInt8 myDGRP0; // Player 0 delayed graphics register
uInt8 myDGRP1; // Player 1 delayed graphics register
bool myENAM0; // Indicates if missle 0 is enabled
bool myENAM1; // Indicates if missle 0 is enabled
bool myENABL; // Indicates if the ball is enabled
bool myDENABL; // Indicates if the virtically delayed ball is enabled
Int8 myHMP0; // Player 0 horizontal motion register
Int8 myHMP1; // Player 1 horizontal motion register
Int8 myHMM0; // Missle 0 horizontal motion register
Int8 myHMM1; // Missle 1 horizontal motion register
Int8 myHMBL; // Ball horizontal motion register
bool myVDELP0; // Indicates if player 0 is being virtically delayed
bool myVDELP1; // Indicates if player 1 is being virtically delayed
bool myVDELBL; // Indicates if the ball is being virtically delayed
bool myRESMP0; // Indicates if missle 0 is reset to player 0
bool myRESMP1; // Indicates if missle 1 is reset to player 1
uInt16 myCollision; // Collision register
// Note that these position registers contain the color clock
// on which the object's serial output should begin (0 to 159)
Int16 myPOSP0; // Player 0 position register
Int16 myPOSP1; // Player 1 position register
Int16 myPOSM0; // Missle 0 position register
Int16 myPOSM1; // Missle 1 position register
Int16 myPOSBL; // Ball position register
private:
// Graphics for Player 0 that should be displayed. This will be
// reflected if the player is being reflected.
uInt8 myCurrentGRP0;
// Graphics for Player 1 that should be displayed. This will be
// reflected if the player is being reflected.
uInt8 myCurrentGRP1;
// It's VERY important that the BL, M0, M1, P0 and P1 current
// mask pointers are always on a uInt32 boundary. Otherwise,
// the TIA code will fail on a good number of CPUs.
// Pointer to the currently active mask array for the ball
uInt8* myCurrentBLMask;
// Pointer to the currently active mask array for missle 0
uInt8* myCurrentM0Mask;
// Pointer to the currently active mask array for missle 1
uInt8* myCurrentM1Mask;
// Pointer to the currently active mask array for player 0
uInt8* myCurrentP0Mask;
// Pointer to the currently active mask array for player 1
uInt8* myCurrentP1Mask;
// Pointer to the currently active mask array for the playfield
uInt32* myCurrentPFMask;
private:
// Indicates when the dump for paddles was last set
Int32 myDumpDisabledCycle;
// Indicates if the dump is current enabled for the paddles
bool myDumpEnabled;
private:
// Color clock when last HMOVE occured
Int32 myLastHMOVEClock;
// Indicates if HMOVE blanks are currently enabled
bool myHMOVEBlankEnabled;
// Indicates if we're allowing HMOVE blanks to be enabled
bool myAllowHMOVEBlanks;
// TIA M0 "bug" used for stars in Cosmic Ark flag
bool myM0CosmicArkMotionEnabled;
// Counter used for TIA M0 "bug"
uInt32 myM0CosmicArkCounter;
private:
// Ball mask table (entries are true or false)
static uInt8 ourBallMaskTable[4][4][320];
// Used to set the collision register to the correct value
static uInt16 ourCollisionTable[64];
// A mask table which can be used when an object is disabled
static uInt8 ourDisabledMaskTable[640];
// Indicates the update delay associated with poking at a TIA address
static const Int16 ourPokeDelayTable[64];
// Missle mask table (entries are true or false)
static uInt8 ourMissleMaskTable[4][8][4][320];
// Used to convert value written in a motion register into
// its internal representation
static const Int32 ourCompleteMotionTable[76][16];
// Indicates if HMOVE blanks should occur for the corresponding cycle
static const bool ourHMOVEBlankEnableCycles[76];
// Player mask table
static uInt8 ourPlayerMaskTable[4][2][8][320];
// Indicates if player is being reset during delay, display or other times
static Int8 ourPlayerPositionResetWhenTable[8][160][160];
// Used to reflect a players graphics
static uInt8 ourPlayerReflectTable[256];
// Playfield mask table for reflected and non-reflected playfields
static uInt32 ourPlayfieldTable[2][160];
// Table of RGB values for NTSC
static const uInt32 ourNTSCPalette[256];
// Table of RGB values for PAL
static const uInt32 ourPALPalette[256];
private:
// Copy constructor isn't supported by this class so make it private
TIA(const TIA&);
// Assignment operator isn't supported by this class so make it private
TIA& operator = (const TIA&);
};
#endif

View File

@ -0,0 +1,37 @@
===============================================================================
MM MM 6666 555555 0000 2222
MMMM MMMM 66 66 55 00 00 22 22
MM MMM MM 66 55 00 00 22
MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
MM MM 66 66 55 00 00 22
MM MM 66 66 55 55 00 00 22
MM MM 6666 5555 0000 222222
===============================================================================
License Information and Copyright Notice
===============================================================================
Copyright (C) 1995-2002 Bradford W. Mott <bwmott@acm.org>
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 any later version.
You should have received a copy of the GNU General Public License version 2
along with this program (License.txt); if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES
THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111 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
Appendix: 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) 19yy <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., 59 Temple Place, Suite 330, Boston, MA 02111 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) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -0,0 +1,187 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: D6502.cxx,v 1.1.1.1 2001-12-27 19:54:29 bwmott Exp $
//============================================================================
#include <stdio.h>
#include "D6502.hxx"
#include "M6502.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
D6502::D6502(System* system)
: mySystem(system)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
D6502::~D6502()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static uInt16 dpeek(System* system, uInt16 address)
{
return (uInt16)system->peek(address) |
(((uInt16)system->peek(address + 1)) << 8);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 D6502::disassemble(uInt16 address, char* buffer)
{
uInt8 opcode = mySystem->peek(address);
switch(M6502::ourAddressingModeTable[opcode])
{
case M6502::Absolute:
sprintf(buffer, "%s $%04X", M6502::ourInstructionMnemonicTable[opcode],
dpeek(mySystem, address + 1));
return 3;
case M6502::AbsoluteX:
sprintf(buffer, "%s $%04X,x", M6502::ourInstructionMnemonicTable[opcode],
dpeek(mySystem, address + 1));
return 3;
case M6502::AbsoluteY:
sprintf(buffer, "%s $%04X,y", M6502::ourInstructionMnemonicTable[opcode],
dpeek(mySystem, address + 1));
return 3;
case M6502::Immediate:
sprintf(buffer, "%s #$%02X", M6502::ourInstructionMnemonicTable[opcode],
mySystem->peek(address + 1));
return 2;
case M6502::Implied:
sprintf(buffer, "%s", M6502::ourInstructionMnemonicTable[opcode]);
return 1;
case M6502::Indirect:
sprintf(buffer, "%s ($%04X)", M6502::ourInstructionMnemonicTable[opcode],
dpeek(mySystem, address + 1));
return 3;
case M6502::IndirectX:
sprintf(buffer, "%s ($%02X,x)",
M6502::ourInstructionMnemonicTable[opcode],
mySystem->peek(address + 1));
return 2;
case M6502::IndirectY:
sprintf(buffer, "%s ($%02X),y",
M6502::ourInstructionMnemonicTable[opcode],
mySystem->peek(address + 1));
return 2;
case M6502::Relative:
sprintf(buffer, "%s $%04X", M6502::ourInstructionMnemonicTable[opcode],
address + 2 + ((Int16)(Int8)mySystem->peek(address + 1)));
return 2;
case M6502::Zero:
sprintf(buffer, "%s $%02X", M6502::ourInstructionMnemonicTable[opcode],
mySystem->peek(address + 1));
return 2;
case M6502::ZeroX:
sprintf(buffer, "%s $%02X,x", M6502::ourInstructionMnemonicTable[opcode],
mySystem->peek(address + 1));
return 2;
case M6502::ZeroY:
sprintf(buffer, "%s $%02X,y", M6502::ourInstructionMnemonicTable[opcode],
mySystem->peek(address + 1));
return 2;
default:
sprintf(buffer, "dc $%02X", opcode);
return 1;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 D6502::a()
{
return mySystem->m6502().A;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void D6502::a(uInt8 value)
{
mySystem->m6502().A = value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt16 D6502::pc()
{
return mySystem->m6502().PC;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void D6502::pc(uInt16 value)
{
mySystem->m6502().PC = value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 D6502::ps()
{
return mySystem->m6502().PS();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void D6502::ps(uInt8 value)
{
mySystem->m6502().PS(value);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 D6502::sp()
{
return mySystem->m6502().SP;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void D6502::sp(uInt8 value)
{
mySystem->m6502().SP = value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 D6502::x()
{
return mySystem->m6502().X;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void D6502::x(uInt8 value)
{
mySystem->m6502().X = value;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 D6502::y()
{
return mySystem->m6502().Y;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void D6502::y(uInt8 value)
{
mySystem->m6502().Y = value;
}

View File

@ -0,0 +1,152 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: D6502.hxx,v 1.1.1.1 2001-12-27 19:54:29 bwmott Exp $
//============================================================================
#ifndef D6502_HXX
#define D6502_HXX
class D6502;
class M6502;
class System;
#include "bspf.hxx"
/**
This is a base class for 6502 debuggers. This class provides the
basic functionality needed for interactive debuggers.
@author Bradford W. Mott
@version $Id: D6502.hxx,v 1.1.1.1 2001-12-27 19:54:29 bwmott Exp $
*/
class D6502
{
public:
/**
Create a new 6502 debugger for the specified system
@param system The system the debugger should operate on
*/
D6502(System* system);
/**
Destructor
*/
virtual ~D6502();
public:
/**
Disassemble a single instruction at the specified address into
the given buffer and answer the number of bytes disassembled.
The buffer should be at least 20 characters long.
@param address The address to disassemble code at
@param buffer The buffer where the ASCII disassemble should be stored
@return The number of bytes disassembled
*/
uInt16 disassemble(uInt16 address, char* buffer);
public:
/**
Get the value of the accumulator
@return The accumulator's value
*/
uInt8 a();
/**
Change value of the accumulator
@param value The value to set the accumulator to
*/
void a(uInt8 value);
/**
Get value of the program counter
@return The program counter's value
*/
uInt16 pc();
/**
Change value of the program counter
@param value The value to set the program counter to
*/
void pc(uInt16 value);
/**
Get the value of the processor status register
@return The processor status register's value
*/
uInt8 ps();
/**
Change value of the processor status register
@param value The value to set the processor status register to
*/
void ps(uInt8 value);
/**
Get the value of the stack pointer
@return The stack pointer's value
*/
uInt8 sp();
/**
Change value of the stack pointer
@param value The value to set the stack pointer to
*/
void sp(uInt8 value);
/**
Get the value of the X index register
@return The X register's value
*/
uInt8 x();
/**
Change value of the X index register
@param value The value to set the X register to
*/
void x(uInt8 value);
/**
Get the value of the Y index register
@return The Y register's value
*/
uInt8 y();
/**
Change value of the Y index register
@param value The value to set the Y register to
*/
void y(uInt8 value);
protected:
// Pointer to the system I'm debugging
System* mySystem;
};
#endif

View File

@ -0,0 +1,37 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Device.cxx,v 1.1.1.1 2001-12-27 19:54:29 bwmott Exp $
//============================================================================
#include "Device.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Device::Device()
: mySystem(0)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Device::~Device()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Device::systemCyclesReset()
{
// By default I do nothing when my system resets its cycle counter
}

View File

@ -0,0 +1,95 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: Device.hxx,v 1.1.1.1 2001-12-27 19:54:29 bwmott Exp $
//============================================================================
#ifndef DEVICE_HXX
#define DEVICE_HXX
class System;
#include "bspf.hxx"
/**
Abstract base class for devices which can be attached to a 6502
based system.
@author Bradford W. Mott
@version $Id: Device.hxx,v 1.1.1.1 2001-12-27 19:54:29 bwmott Exp $
*/
class Device
{
public:
/**
Create a new device
*/
Device();
/**
Destructor
*/
virtual ~Device();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const = 0;
/**
Reset device to its power-on state
*/
virtual void reset() = 0;
/**
Notification method invoked by the system right before the
system resets its cycle counter to zero. It may be necessary
to override this method for devices that remember cycle counts.
*/
virtual void systemCyclesReset();
/**
Install device in the specified system. Invoked by the system
when the device is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system) = 0;
public:
/**
Get the byte at the specified address
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address) = 0;
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value) = 0;
protected:
/// Pointer to the system the device is installed in or the null pointer
System* mySystem;
};
#endif

View File

@ -0,0 +1,335 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502.cxx,v 1.1.1.1 2001-12-27 19:54:30 bwmott Exp $
//============================================================================
#include "M6502.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6502::M6502(uInt32 systemCyclesPerProcessorCycle)
: myExecutionStatus(0),
mySystem(0),
mySystemCyclesPerProcessorCycle(systemCyclesPerProcessorCycle)
{
uInt16 t;
// Compute the BCD lookup table
for(t = 0; t < 256; ++t)
{
ourBCDTable[0][t] = ((t >> 4) * 10) + (t & 0x0f);
ourBCDTable[1][t] = (((t % 100) / 10) << 4) | (t % 10);
}
// Compute the System Cycle table
for(t = 0; t < 256; ++t)
{
myInstructionSystemCycleTable[t] = ourInstructionProcessorCycleTable[t] *
mySystemCyclesPerProcessorCycle;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6502::~M6502()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502::install(System& system)
{
// Remember which system I'm installed in
mySystem = &system;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502::reset()
{
// Clear the execution status flags
myExecutionStatus = 0;
// Set registers to default values
A = X = Y = 0;
SP = 0xff;
PS(0x20);
// Load PC from the reset vector
PC = (uInt16)mySystem->peek(0xfffc) | ((uInt16)mySystem->peek(0xfffd) << 8);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502::irq()
{
myExecutionStatus |= MaskableInterruptBit;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502::nmi()
{
myExecutionStatus |= NonmaskableInterruptBit;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502::stop()
{
myExecutionStatus |= StopExecutionBit;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6502::AddressingMode M6502::addressingMode(uInt8 opcode) const
{
return ourAddressingModeTable[opcode];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 M6502::PS() const
{
uInt8 ps = 0x20;
if(N)
ps |= 0x80;
if(V)
ps |= 0x40;
if(B)
ps |= 0x10;
if(D)
ps |= 0x08;
if(I)
ps |= 0x04;
if(!notZ)
ps |= 0x02;
if(C)
ps |= 0x01;
return ps;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502::PS(uInt8 ps)
{
N = ps & 0x80;
V = ps & 0x40;
B = ps & 0x10;
D = ps & 0x08;
I = ps & 0x04;
notZ = !(ps & 0x02);
C = ps & 0x01;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ostream& operator<<(ostream& out, const M6502::AddressingMode& mode)
{
switch(mode)
{
case M6502::Absolute:
out << "$nnnn ";
break;
case M6502::AbsoluteX:
out << "$nnnn,X";
break;
case M6502::AbsoluteY:
out << "$nnnn,Y";
break;
case M6502::Implied:
out << "implied";
break;
case M6502::Immediate:
out << "#$nn ";
break;
case M6502::Indirect:
out << "($nnnn)";
break;
case M6502::IndirectX:
out << "($nn,X)";
break;
case M6502::IndirectY:
out << "($nn),Y";
break;
case M6502::Invalid:
out << "invalid";
break;
case M6502::Relative:
out << "$nn ";
break;
case M6502::Zero:
out << "$nn ";
break;
case M6502::ZeroX:
out << "$nn,X ";
break;
case M6502::ZeroY:
out << "$nn,Y ";
break;
}
return out;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 M6502::ourBCDTable[2][256];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6502::AddressingMode M6502::ourAddressingModeTable[256] = {
Implied, IndirectX, Invalid, IndirectX, // 0x0?
Zero, Zero, Zero, Zero,
Implied, Immediate, Implied, Invalid,
Absolute, Absolute, Absolute, Absolute,
Relative, IndirectY, Invalid, IndirectY, // 0x1?
ZeroX, ZeroX, ZeroX, ZeroX,
Implied, AbsoluteY, Implied, AbsoluteY,
AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX,
Absolute, IndirectX, Invalid, IndirectX, // 0x2?
Zero, Zero, Zero, Zero,
Implied, Immediate, Implied, Invalid,
Absolute, Absolute, Absolute, Absolute,
Relative, IndirectY, Invalid, IndirectY, // 0x3?
ZeroX, ZeroX, ZeroX, ZeroX,
Implied, AbsoluteY, Implied, AbsoluteY,
AbsoluteX, AbsoluteX, AbsoluteX, AbsoluteX,
Implied, IndirectX, Invalid, Invalid, // 0x4?
Zero, Zero, Zero, Invalid,
Implied, Immediate, Implied, Invalid,
Absolute, Absolute, Absolute, Invalid,
Relative, IndirectY, Invalid, Invalid, // 0x5?
ZeroX, ZeroX, ZeroX, Invalid,
Implied, AbsoluteY, Implied, Invalid,
AbsoluteX, AbsoluteX, AbsoluteX, Invalid,
Implied, IndirectX, Invalid, Invalid, // 0x6?
Zero, Zero, Zero, Invalid,
Implied, Immediate, Implied, Invalid,
Indirect, Absolute, Absolute, Invalid,
Relative, IndirectY, Invalid, Invalid, // 0x7?
ZeroX, ZeroX, ZeroX, Invalid,
Implied, AbsoluteY, Implied, Invalid,
AbsoluteX, AbsoluteX, AbsoluteX, Invalid,
Immediate, IndirectX, Immediate, IndirectX, // 0x8?
Zero, Zero, Zero, Zero,
Implied, Invalid, Implied, Invalid,
Absolute, Absolute, Absolute, Absolute,
Relative, IndirectY, Invalid, Invalid, // 0x9?
ZeroX, ZeroX, ZeroY, ZeroY,
Implied, AbsoluteY, Implied, Invalid,
Invalid, AbsoluteX, Invalid, Invalid,
Immediate, IndirectX, Immediate, Invalid, // 0xA?
Zero, Zero, Zero, Invalid,
Implied, Immediate, Implied, Invalid,
Absolute, Absolute, Absolute, Invalid,
Relative, IndirectY, Invalid, Invalid, // 0xB?
ZeroX, ZeroX, ZeroY, Invalid,
Implied, AbsoluteY, Implied, Invalid,
AbsoluteX, AbsoluteX, AbsoluteY, Invalid,
Immediate, IndirectX, Immediate, Invalid, // 0xC?
Zero, Zero, Zero, Invalid,
Implied, Immediate, Implied, Invalid,
Absolute, Absolute, Absolute, Invalid,
Relative, IndirectY, Invalid, Invalid, // 0xD?
ZeroX, ZeroX, ZeroX, Invalid,
Implied, AbsoluteY, Implied, Invalid,
AbsoluteX, AbsoluteX, AbsoluteX, Invalid,
Immediate, IndirectX, Immediate, Invalid, // 0xE?
Zero, Zero, Zero, Invalid,
Implied, Immediate, Implied, Invalid,
Absolute, Absolute, Absolute, Invalid,
Relative, IndirectY, Invalid, Invalid, // 0xF?
ZeroX, ZeroX, ZeroX, Invalid,
Implied, AbsoluteY, Implied, Invalid,
AbsoluteX, AbsoluteX, AbsoluteX, Invalid
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt32 M6502::ourInstructionProcessorCycleTable[256] = {
// 0 1 2 3 4 5 6 7 8 9 a b c d e f
7, 6, 2, 8, 3, 3, 5, 5, 3, 2, 2, 2, 4, 4, 6, 6, // 0
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // 1
6, 6, 2, 8, 3, 3, 5, 5, 4, 2, 2, 2, 4, 4, 6, 6, // 2
2, 5, 2, 8, 4, 4, 6, 6, 2, 4, 2, 7, 4, 4, 7, 7, // 3
6, 6, 2, 2, 3, 3, 5, 2, 3, 2, 2, 2, 3, 4, 6, 2, // 4
2, 5, 2, 2, 4, 4, 6, 2, 2, 4, 2, 2, 4, 4, 7, 2, // 5
6, 6, 2, 2, 3, 3, 5, 2, 4, 2, 2, 2, 5, 4, 6, 2, // 6
2, 5, 2, 2, 4, 4, 6, 2, 2, 4, 2, 2, 4, 4, 7, 2, // 7
2, 6, 2, 6, 3, 3, 3, 3, 2, 2, 2, 2, 4, 4, 4, 4, // 8
2, 6, 2, 2, 4, 4, 4, 4, 2, 5, 2, 2, 2, 5, 2, 2, // 9
2, 6, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 4, 4, 4, 2, // a
2, 5, 2, 2, 4, 4, 4, 2, 2, 4, 2, 2, 4, 4, 4, 2, // b
2, 6, 2, 2, 3, 3, 5, 2, 2, 2, 2, 2, 4, 4, 6, 2, // c
2, 5, 2, 2, 4, 4, 6, 2, 2, 4, 2, 2, 4, 4, 7, 2, // d
2, 6, 2, 2, 3, 3, 5, 2, 2, 2, 2, 2, 4, 4, 6, 2, // e
2, 5, 2, 2, 4, 4, 6, 2, 2, 4, 2, 2, 4, 4, 7, 2 // f
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* M6502::ourInstructionMnemonicTable[256] = {
"BRK", "ORA", "n/a", "aso", "nop", "ORA", "ASL", "aso", // 0x0?
"PHP", "ORA", "ASLA", "n/a", "nop", "ORA", "ASL", "aso",
"BPL", "ORA", "n/a", "aso", "nop", "ORA", "ASL", "aso", // 0x1?
"CLC", "ORA", "nop", "aso", "nop", "ORA", "ASL", "aso",
"JSR", "AND", "n/a", "rla", "BIT", "AND", "ROL", "rla", // 0x2?
"PLP", "AND", "ROLA", "n/a", "BIT", "AND", "ROL", "rla",
"BMI", "AND", "rla", "n/a", "nop", "AND", "ROL", "rla", // 0x3?
"SEC", "AND", "nop", "rla", "nop", "AND", "ROL", "rla",
"RTI", "EOR", "n/a", "n/a", "nop", "EOR", "LSR", "n/a", // 0x4?
"PHA", "EOR", "LSRA", "n/a", "JMP", "EOR", "LSR", "n/a",
"BVC", "EOR", "n/a", "n/a", "nop", "EOR", "LSR", "n/a", // 0x5?
"CLI", "EOR", "nop", "n/a", "nop", "EOR", "LSR", "n/a",
"RTS", "ADC", "n/a", "n/a", "nop", "ADC", "ROR", "n/a", // 0x6?
"PLA", "ADC", "RORA", "n/a", "JMP", "ADC", "ROR", "n/a",
"BVS", "ADC", "n/a", "n/a", "nop", "ADC", "ROR", "n/a", // 0x7?
"SEI", "ADC", "nop", "n/a", "nop", "ADC", "ROR", "n/a",
"nop", "STA", "nop", "axs", "STY", "STA", "STX", "axs", // 0x8?
"DEY", "n/a", "TXA", "n/a", "STY", "STA", "STX", "axs",
"BCC", "STA", "n/a", "n/a", "STY", "STA", "STX", "axs", // 0x9?
"TYA", "STA", "TXS", "n/a", "n/a", "STA", "n/a", "n/a",
"LDY", "LDA", "LDX", "n/a", "LDY", "LDA", "LDX", "n/a", // 0xA?
"TAY", "LDA", "TAX", "n/a", "LDY", "LDA", "LDX", "n/a",
"BCS", "LDA", "n/a", "n/a", "LDY", "LDA", "LDX", "n/a", // 0xB?
"CLV", "LDA", "TSX", "n/a", "LDY", "LDA", "LDX", "n/a",
"CPY", "CMP", "nop", "n/a", "CPY", "CMP", "DEC", "n/a", // 0xC?
"INY", "CMP", "DEX", "n/a", "CPY", "CMP", "DEC", "n/a",
"BNE", "CMP", "n/a", "n/a", "nop", "CMP", "DEC", "n/a", // 0xD?
"CLD", "CMP", "nop", "n/a", "nop", "CMP", "DEC", "n/a",
"CPX", "SBC", "nop", "n/a", "CPX", "SBC", "INC", "n/a", // 0xE?
"INX", "SBC", "NOP", "n/a", "CPX", "SBC", "INC", "n/a",
"BEQ", "SBC", "n/a", "n/a", "nop", "SBC", "INC", "n/a", // 0xF?
"SED", "SBC", "nop", "n/a", "nop", "SBC", "INC", "n/a"
};

View File

@ -0,0 +1,219 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502.hxx,v 1.1.1.1 2001-12-27 19:54:30 bwmott Exp $
//============================================================================
#ifndef M6502_HXX
#define M6502_HXX
class D6502;
class M6502;
#include "bspf.hxx"
#include "System.hxx"
/**
This is an abstract base class for classes that emulate the
6502 microprocessor. The 6502 is an 8-bit microprocessor that
has a 64K addressing space.
@author Bradford W. Mott
@version $Id: M6502.hxx,v 1.1.1.1 2001-12-27 19:54:30 bwmott Exp $
*/
class M6502
{
public:
/**
The 6502 debugger class is a friend who needs special access
*/
friend class D6502;
public:
/**
Enumeration of the 6502 addressing modes
*/
enum AddressingMode
{
Absolute, AbsoluteX, AbsoluteY, Immediate, Implied,
Indirect, IndirectX, IndirectY, Invalid, Relative,
Zero, ZeroX, ZeroY
};
public:
/**
Create a new 6502 microprocessor with the specified cycle
multiplier. The cycle multiplier is the number of system cycles
per processor cycle.
@param systemCyclesPerProcessorCycle The cycle multiplier
*/
M6502(uInt32 systemCyclesPerProcessorCycle);
/**
Destructor
*/
virtual ~M6502();
public:
/**
Install the processor in the specified system. Invoked by the
system when the processor is attached to it.
@param system The system the processor should install itself in
*/
virtual void install(System& system);
public:
/**
Reset the processor to its power-on state. This method should not
be invoked until the entire 6502 system is constructed and installed
since it involves reading the reset vector from memory.
*/
virtual void reset();
/**
Request a maskable interrupt
*/
virtual void irq();
/**
Request a non-maskable interrupt
*/
virtual void nmi();
public:
/**
Get the addressing mode of the specified instruction
@param opcode The opcode of the instruction
@return The addressing mode of the instruction
*/
AddressingMode addressingMode(uInt8 opcode) const;
public:
/**
Execute instructions until the specified number of instructions
is executed, someone stops execution, or an error occurs. Answers
true iff execution stops normally.
@param number Indicates the number of instructions to execute
@return true iff execution stops normally
*/
virtual bool execute(uInt32 number) = 0;
/**
Tell the processor to stop executing instructions. Invoking this
method while the processor is executing instructions will stop
execution as soon as possible.
*/
void stop();
/**
Answer true iff a fatal error has occured from which the processor
cannot recover (i.e. illegal instruction, etc.)
@return true iff a fatal error has occured
*/
bool fatalError() const
{
return myExecutionStatus & FatalErrorBit;
}
public:
/**
Overload the ostream output operator for addressing modes.
@param out The stream to output the addressing mode to
@param mode The addressing mode to output
*/
friend ostream& operator<<(ostream& out, const AddressingMode& mode);
protected:
/**
Get the 8-bit value of the Processor Status register.
@return The processor status register
*/
uInt8 PS() const;
/**
Change the Processor Status register to correspond to the given value.
@param ps The value to set the processor status register to
*/
void PS(uInt8 ps);
protected:
uInt8 A; // Accumulator
uInt8 X; // X index register
uInt8 Y; // Y index register
uInt8 SP; // Stack Pointer
uInt8 IR; // Instruction register
uInt16 PC; // Program Counter
bool N; // N flag for processor status register
bool V; // V flag for processor status register
bool B; // B flag for processor status register
bool D; // D flag for processor status register
bool I; // I flag for processor status register
bool notZ; // Z flag complement for processor status register
bool C; // C flag for processor status register
/**
Bit fields used to indicate that certain conditions need to be
handled such as stopping execution, fatal errors, maskable interrupts
and non-maskable interrupts
*/
uInt8 myExecutionStatus;
/**
Constants used for setting bits in myExecutionStatus
*/
enum
{
StopExecutionBit = 0x01,
FatalErrorBit = 0x02,
MaskableInterruptBit = 0x04,
NonmaskableInterruptBit = 0x08
};
/// Pointer to the system the processor is installed in or the null pointer
System* mySystem;
/// Indicates the number of system cycles per processor cycle
const uInt32 mySystemCyclesPerProcessorCycle;
/// Table of system cycles for each instruction
uInt32 myInstructionSystemCycleTable[256];
protected:
/// Addressing mode for each of the 256 opcodes
static AddressingMode ourAddressingModeTable[256];
/// Lookup table used for binary-code-decimal math
static uInt8 ourBCDTable[2][256];
/**
Table of instruction processor cycle times. In some cases additional
cycles will be added during the execution of an instruction.
*/
static uInt32 ourInstructionProcessorCycleTable[256];
/// Table of instruction mnemonics
static const char* ourInstructionMnemonicTable[256];
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,169 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502Hi.cxx,v 1.1.1.1 2001-12-27 19:54:30 bwmott Exp $
//============================================================================
#include "M6502Hi.hxx"
#define debugStream cout
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6502High::M6502High(uInt32 systemCyclesPerProcessorCycle)
: M6502(systemCyclesPerProcessorCycle)
{
myNumberOfDistinctAccesses = 0;
myLastAddress = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6502High::~M6502High()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline uInt8 M6502High::peek(uInt16 address)
{
if(address != myLastAddress)
{
myNumberOfDistinctAccesses++;
myLastAddress = address;
}
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
return mySystem->peek(address);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void M6502High::poke(uInt16 address, uInt8 value)
{
if(address != myLastAddress)
{
myNumberOfDistinctAccesses++;
myLastAddress = address;
}
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
mySystem->poke(address, value);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool M6502High::execute(uInt32 number)
{
// Clear all of the execution status bits except for the fatal error bit
myExecutionStatus &= FatalErrorBit;
// Loop until execution is stopped or a fatal error occurs
for(;;)
{
for(; !myExecutionStatus && (number != 0); --number)
{
uInt16 operandAddress = 0;
uInt8 operand = 0;
#ifdef DEBUG
debugStream << "PC=" << hex << setw(4) << PC << " ";
#endif
// Fetch instruction at the program counter
IR = peek(PC++);
#ifdef DEBUG
debugStream << "IR=" << hex << setw(2) << (int)IR << " ";
debugStream << "<" << ourAddressingModeTable[IR] << " ";
#endif
// Call code to execute the instruction
switch(IR)
{
// 6502 instruction emulation is generated by an M4 macro file
#include "M6502Hi.ins"
default:
// Oops, illegal instruction executed so set fatal error flag
myExecutionStatus |= FatalErrorBit;
}
#ifdef DEBUG
debugStream << hex << setw(4) << operandAddress << " ";
debugStream << setw(4) << ourInstructionMnemonicTable[IR];
debugStream << "> ";
debugStream << "A=" << ::hex << setw(2) << (int)A << " ";
debugStream << "X=" << ::hex << setw(2) << (int)X << " ";
debugStream << "Y=" << ::hex << setw(2) << (int)Y << " ";
debugStream << "PS=" << ::hex << setw(2) << (int)PS() << " ";
debugStream << "SP=" << ::hex << setw(2) << (int)SP << " ";
debugStream << "Cyc=" << dec << mySystem->cycles();
debugStream << endl;
#endif
}
// See if we need to handle an interrupt
if((myExecutionStatus & MaskableInterruptBit) ||
(myExecutionStatus & NonmaskableInterruptBit))
{
// Yes, so handle the interrupt
interruptHandler();
}
// See if execution has been stopped
if(myExecutionStatus & StopExecutionBit)
{
// Yes, so answer that everything finished fine
return true;
}
// See if a fatal error has occured
if(myExecutionStatus & FatalErrorBit)
{
// Yes, so answer that something when wrong
return false;
}
// See if we've executed the specified number of instructions
if(number == 0)
{
// Yes, so answer that everything finished fine
return true;
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502High::interruptHandler()
{
// Handle the interrupt
if((myExecutionStatus & MaskableInterruptBit) && !I)
{
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
D = false;
I = true;
PC = (uInt16)mySystem->peek(0xFFFE) | ((uInt16)mySystem->peek(0xFFFF) << 8);
}
else if(myExecutionStatus & NonmaskableInterruptBit)
{
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
D = false;
PC = (uInt16)mySystem->peek(0xFFFA) | ((uInt16)mySystem->peek(0xFFFB) << 8);
}
// Clear the interrupt bits in myExecutionStatus
myExecutionStatus &= ~(MaskableInterruptBit | NonmaskableInterruptBit);
}

View File

@ -0,0 +1,108 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502Hi.hxx,v 1.1.1.1 2001-12-27 19:54:30 bwmott Exp $
//============================================================================
#ifndef M6502HIGH_HXX
#define M6502HIGH_HXX
class M6502High;
#include "bspf.hxx"
#include "M6502.hxx"
/**
This class provides a high compatibility 6502 microprocessor emulator.
The memory accesses and cycle counts it generates are valid at the
sub-instruction level and "false" reads are generated (such as the ones
produced by the Indirect,X addressing when it crosses a page boundary).
This provides provides better compatibility for hardware that has side
effects and for games which are very time sensitive.
@author Bradford W. Mott
@version $Id: M6502Hi.hxx,v 1.1.1.1 2001-12-27 19:54:30 bwmott Exp $
*/
class M6502High : public M6502
{
public:
/**
Create a new high compatibility 6502 microprocessor with the
specified cycle multiplier.
@param systemCyclesPerProcessorCycle The cycle multiplier
*/
M6502High(uInt32 systemCyclesPerProcessorCycle);
/**
Destructor
*/
virtual ~M6502High();
public:
/**
Execute instructions until the specified number of instructions
is executed, someone stops execution, or an error occurs. Answers
true iff execution stops normally.
@param number Indicates the number of instructions to execute
@return true iff execution stops normally
*/
virtual bool execute(uInt32 number);
public:
/**
Get the number of memory accesses to distinct memory locations
@return The number of memory accesses to distinct memory locations
*/
uInt32 distinctAccesses() const
{
return myNumberOfDistinctAccesses;
}
protected:
/**
Called after an interrupt has be requested using irq() or nmi()
*/
void interruptHandler();
protected:
/*
Get the byte at the specified address and update the cycle
count
@return The byte at the specified address
*/
inline uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value and
update the cycle count
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
inline void poke(uInt16 address, uInt8 value);
private:
// Indicates the numer of distinct memory accesses
uInt32 myNumberOfDistinctAccesses;
// Indicates the last address which was accessed
uInt16 myLastAddress;
};
#endif

View File

@ -0,0 +1,314 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502Hi.m4,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
//============================================================================
/**
Code to handle addressing modes and branch instructions for
high compatibility emulation
@author Bradford W. Mott
@version $Id: M6502Hi.m4,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
*/
#ifndef NOTSAMEPAGE
#define NOTSAMEPAGE(_addr1, _addr2) (((_addr1) ^ (_addr2)) & 0xff00)
#endif
define(M6502_IMPLIED, `{
peek(PC);
}')
define(M6502_IMMEDIATE_READ, `{
operand = peek(PC++);
}')
define(M6502_ABSOLUTE_READ, `{
uInt16 address = peek(PC++);
address |= ((uInt16)peek(PC++) << 8);
operand = peek(address);
}')
define(M6502_ABSOLUTE_WRITE, `{
operandAddress = peek(PC++);
operandAddress |= ((uInt16)peek(PC++) << 8);
}')
define(M6502_ABSOLUTE_READMODIFYWRITE, `{
operandAddress = peek(PC++);
operandAddress |= ((uInt16)peek(PC++) << 8);
operand = peek(operandAddress);
poke(operandAddress, operand);
}')
define(M6502_ABSOLUTEX_READ, `{
uInt16 low = peek(PC++);
uInt16 high = ((uInt16)peek(PC++) << 8);
operand = peek(high | (uInt8)(low + X));
if((low + X) > 0xFF)
operand = peek((high | low) + X);
}')
define(M6502_ABSOLUTEX_WRITE, `{
uInt16 low = peek(PC++);
uInt16 high = ((uInt16)peek(PC++) << 8);
peek(high | (uInt8)(low + X));
operandAddress = (high | low) + X;
}')
define(M6502_ABSOLUTEX_READMODIFYWRITE, `{
uInt16 low = peek(PC++);
uInt16 high = ((uInt16)peek(PC++) << 8);
peek(high | (uInt8)(low + X));
operandAddress = (high | low) + X;
operand = peek(operandAddress);
poke(operandAddress, operand);
}')
define(M6502_ABSOLUTEY_READ, `{
uInt16 low = peek(PC++);
uInt16 high = ((uInt16)peek(PC++) << 8);
operand = peek(high | (uInt8)(low + Y));
if((low + Y) > 0xFF)
operand = peek((high | low) + Y);
}')
define(M6502_ABSOLUTEY_WRITE, `{
uInt16 low = peek(PC++);
uInt16 high = ((uInt16)peek(PC++) << 8);
peek(high | (uInt8)(low + Y));
operandAddress = (high | low) + Y;
}')
define(M6502_ABSOLUTEY_READMODIFYWRITE, `{
uInt16 low = peek(PC++);
uInt16 high = ((uInt16)peek(PC++) << 8);
peek(high | (uInt8)(low + Y));
operandAddress = (high | low) + Y;
operand = peek(operandAddress);
poke(operandAddress, operand);
}')
define(M6502_ZERO_READ, `{
operand = peek(peek(PC++));
}')
define(M6502_ZERO_WRITE, `{
operandAddress = peek(PC++);
}')
define(M6502_ZERO_READMODIFYWRITE, `{
operandAddress = peek(PC++);
operand = peek(operandAddress);
poke(operandAddress, operand);
}')
define(M6502_ZEROX_READ, `{
uInt8 address = peek(PC++);
peek(address);
address += X;
operand = peek(address);
}')
define(M6502_ZEROX_WRITE, `{
operandAddress = peek(PC++);
peek(operandAddress);
operandAddress = (operandAddress + X) & 0xFF;
}')
define(M6502_ZEROX_READMODIFYWRITE, `{
operandAddress = peek(PC++);
peek(operandAddress);
operandAddress = (operandAddress + X) & 0xFF;
operand = peek(operandAddress);
poke(operandAddress, operand);
}')
define(M6502_ZEROY_READ, `{
uInt8 address = peek(PC++);
peek(address);
address += Y;
operand = peek(address);
}')
define(M6502_ZEROY_WRITE, `{
operandAddress = peek(PC++);
peek(operandAddress);
operandAddress = (operandAddress + Y) & 0xFF;
}')
define(M6502_ZEROY_READMODIFYWRITE, `{
operandAddress = peek(PC++);
peek(operandAddress);
operandAddress = (operandAddress + Y) & 0xFF;
operand = peek(operandAddress);
poke(operandAddress, operand);
}')
define(M6502_INDIRECT, `{
uInt16 addr = peek(PC++);
addr |= ((uInt16)peek(PC++) << 8);
// Simulate the error in the indirect addressing mode!
uInt16 high = NOTSAMEPAGE(addr, addr + 1) ? (addr & 0xff00) : (addr + 1);
operandAddress = peek(addr);
operandAddress |= ((uInt16)peek(high) << 8);
}')
define(M6502_INDIRECTX_READ, `{
uInt8 pointer = peek(PC++);
peek(pointer);
pointer += X;
uInt16 address = peek(pointer++);
address |= ((uInt16)peek(pointer) << 8);
operand = peek(address);
}')
define(M6502_INDIRECTX_WRITE, `{
uInt8 pointer = peek(PC++);
peek(pointer);
pointer += X;
operandAddress = peek(pointer++);
operandAddress |= ((uInt16)peek(pointer) << 8);
}')
define(M6502_INDIRECTX_READMODIFYWRITE, `{
uInt8 pointer = peek(PC++);
peek(pointer);
pointer += X;
operandAddress = peek(pointer++);
operandAddress |= ((uInt16)peek(pointer) << 8);
operand = peek(operandAddress);
poke(operandAddress, operand);
}')
define(M6502_INDIRECTY_READ, `{
uInt8 pointer = peek(PC++);
uInt16 low = peek(pointer++);
uInt16 high = ((uInt16)peek(pointer) << 8);
operand = peek(high | (uInt8)(low + Y));
if((low + Y) > 0xFF)
operand = peek((high | low) + Y);
}')
define(M6502_INDIRECTY_WRITE, `{
uInt8 pointer = peek(PC++);
uInt16 low = peek(pointer++);
uInt16 high = ((uInt16)peek(pointer) << 8);
peek(high | (uInt8)(low + Y));
operandAddress = (high | low) + Y;
}')
define(M6502_INDIRECTY_READMODIFYWRITE, `{
uInt8 pointer = peek(PC++);
uInt16 low = peek(pointer++);
uInt16 high = ((uInt16)peek(pointer) << 8);
peek(high | (uInt8)(low + Y));
operandAddress = (high | low) + Y;
operand = peek(operandAddress);
poke(operandAddress, operand);
}')
define(M6502_BCC, `{
if(!C)
{
peek(PC);
uInt16 address = PC + (Int8)operand;
if(NOTSAMEPAGE(PC, address))
peek((PC & 0xFF00) | (address & 0x00FF));
PC = address;
}
}')
define(M6502_BCS, `{
if(C)
{
peek(PC);
uInt16 address = PC + (Int8)operand;
if(NOTSAMEPAGE(PC, address))
peek((PC & 0xFF00) | (address & 0x00FF));
PC = address;
}
}')
define(M6502_BEQ, `{
if(!notZ)
{
peek(PC);
uInt16 address = PC + (Int8)operand;
if(NOTSAMEPAGE(PC, address))
peek((PC & 0xFF00) | (address & 0x00FF));
PC = address;
}
}')
define(M6502_BMI, `{
if(N)
{
peek(PC);
uInt16 address = PC + (Int8)operand;
if(NOTSAMEPAGE(PC, address))
peek((PC & 0xFF00) | (address & 0x00FF));
PC = address;
}
}')
define(M6502_BNE, `{
if(notZ)
{
peek(PC);
uInt16 address = PC + (Int8)operand;
if(NOTSAMEPAGE(PC, address))
peek((PC & 0xFF00) | (address & 0x00FF));
PC = address;
}
}')
define(M6502_BPL, `{
if(!N)
{
peek(PC);
uInt16 address = PC + (Int8)operand;
if(NOTSAMEPAGE(PC, address))
peek((PC & 0xFF00) | (address & 0x00FF));
PC = address;
}
}')
define(M6502_BVC, `{
if(!V)
{
peek(PC);
uInt16 address = PC + (Int8)operand;
if(NOTSAMEPAGE(PC, address))
peek((PC & 0xFF00) | (address & 0x00FF));
PC = address;
}
}')
define(M6502_BVS, `{
if(V)
{
peek(PC);
uInt16 address = PC + (Int8)operand;
if(NOTSAMEPAGE(PC, address))
peek((PC & 0xFF00) | (address & 0x00FF));
PC = address;
}
}')

View File

@ -0,0 +1,159 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502Low.cxx,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
//============================================================================
#include "M6502Low.hxx"
#define debugStream cout
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6502Low::M6502Low(uInt32 systemCyclesPerProcessorCycle)
: M6502(systemCyclesPerProcessorCycle)
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
M6502Low::~M6502Low()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline uInt8 M6502Low::peek(uInt16 address)
{
return mySystem->peek(address);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void M6502Low::poke(uInt16 address, uInt8 value)
{
mySystem->poke(address, value);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool M6502Low::execute(uInt32 number)
{
// Clear all of the execution status bits except for the fatal error bit
myExecutionStatus &= FatalErrorBit;
// Loop until execution is stopped or a fatal error occurs
for(;;)
{
for(; !myExecutionStatus && (number != 0); --number)
{
uInt16 operandAddress = 0;
uInt8 operand = 0;
#ifdef DEBUG
debugStream << "PC=" << hex << setw(4) << PC << " ";
#endif
// Fetch instruction at the program counter
IR = peek(PC++);
#ifdef DEBUG
debugStream << "IR=" << hex << setw(2) << (int)IR << " ";
debugStream << "<" << ourAddressingModeTable[IR] << " ";
#endif
// Update system cycles
mySystem->incrementCycles(myInstructionSystemCycleTable[IR]);
// Call code to execute the instruction
switch(IR)
{
// 6502 instruction emulation is generated by an M4 macro file
#include "M6502Low.ins"
default:
// Oops, illegal instruction executed so set fatal error flag
myExecutionStatus |= FatalErrorBit;
cerr << "Illegal Instruction! " << hex << (int) IR << endl;
}
#ifdef DEBUG
debugStream << hex << setw(4) << operandAddress << " ";
debugStream << setw(4) << ourInstructionMnemonicTable[IR];
debugStream << "> ";
debugStream << "A=" << ::hex << setw(2) << (int)A << " ";
debugStream << "X=" << ::hex << setw(2) << (int)X << " ";
debugStream << "Y=" << ::hex << setw(2) << (int)Y << " ";
debugStream << "PS=" << ::hex << setw(2) << (int)PS() << " ";
debugStream << "SP=" << ::hex << setw(2) << (int)SP << " ";
debugStream << "Cyc=" << dec << mySystem->cycles();
debugStream << endl;
#endif
}
// See if we need to handle an interrupt
if((myExecutionStatus & MaskableInterruptBit) ||
(myExecutionStatus & NonmaskableInterruptBit))
{
// Yes, so handle the interrupt
interruptHandler();
}
// See if execution has been stopped
if(myExecutionStatus & StopExecutionBit)
{
// Yes, so answer that everything finished fine
return true;
}
// See if a fatal error has occured
if(myExecutionStatus & FatalErrorBit)
{
// Yes, so answer that something when wrong
return false;
}
// See if we've executed the specified number of instructions
if(number == 0)
{
// Yes, so answer that everything finished fine
return true;
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void M6502Low::interruptHandler()
{
// Handle the interrupt
if((myExecutionStatus & MaskableInterruptBit) && !I)
{
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
D = false;
I = true;
PC = (uInt16)mySystem->peek(0xFFFE) | ((uInt16)mySystem->peek(0xFFFF) << 8);
}
else if(myExecutionStatus & NonmaskableInterruptBit)
{
mySystem->incrementCycles(7 * mySystemCyclesPerProcessorCycle);
mySystem->poke(0x0100 + SP--, (PC - 1) >> 8);
mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff);
mySystem->poke(0x0100 + SP--, PS() & (~0x10));
D = false;
PC = (uInt16)mySystem->peek(0xFFFA) | ((uInt16)mySystem->peek(0xFFFB) << 8);
}
// Clear the interrupt bits in myExecutionStatus
myExecutionStatus &= ~(MaskableInterruptBit | NonmaskableInterruptBit);
}

View File

@ -0,0 +1,94 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502Low.hxx,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
//============================================================================
#ifndef M6507LOW_HXX
#define M6507LOW_HXX
class M6507Low;
#include "bspf.hxx"
#include "M6502.hxx"
/**
This class provides a low compatibility 6502 microprocessor emulator.
The memory accesses and cycle updates of this emulator are not 100%
accurate as shown below:
1. Only memory accesses which are actually needed are done
(i.e. no "false" reads and writes are performed)
2. Cycle counts are updated at the beginning of the instruction
execution and not valid at the sub-instruction level
If speed is the most important issue then use this class, however, if
better compatibility is neccessary use one of the other 6502 classes.
@author Bradford W. Mott
@version $Id: M6502Low.hxx,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
*/
class M6502Low : public M6502
{
public:
/**
Create a new low compatibility 6502 microprocessor with the specified
cycle multiplier.
@param systemCyclesPerProcessorCycle The cycle multiplier
*/
M6502Low(uInt32 systemCyclesPerProcessorCycle);
/**
Destructor
*/
virtual ~M6502Low();
public:
/**
Execute instructions until the specified number of instructions
is executed, someone stops execution, or an error occurs. Answers
true iff execution stops normally.
@param number Indicates the number of instructions to execute
@return true iff execution stops normally
*/
virtual bool execute(uInt32 number);
protected:
/**
Called after an interrupt has be requested using irq() or nmi()
*/
void interruptHandler();
protected:
/*
Get the byte at the specified address
@return The byte at the specified address
*/
inline uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
inline void poke(uInt16 address, uInt8 value);
};
#endif

View File

@ -0,0 +1,286 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: M6502Low.m4,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
//============================================================================
/**
Code to handle addressing modes and branch instructions for
low compatibility emulation
@author Bradford W. Mott
@version $Id: M6502Low.m4,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
*/
#ifndef NOTSAMEPAGE
#define NOTSAMEPAGE(_addr1, _addr2) (((_addr1) ^ (_addr2)) & 0xff00)
#endif
define(M6502_IMPLIED, `{
}')
define(M6502_IMMEDIATE_READ, `{
operandAddress = PC++;
operand = peek(operandAddress);
}')
define(M6502_ABSOLUTE_READ, `{
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
PC += 2;
operand = peek(operandAddress);
}')
define(M6502_ABSOLUTE_WRITE, `{
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
PC += 2;
}')
define(M6502_ABSOLUTE_READMODIFYWRITE, `{
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
PC += 2;
operand = peek(operandAddress);
}')
define(M6502_ABSOLUTEX_READ, `{
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
PC += 2;
// See if we need to add one cycle for indexing across a page boundary
if(NOTSAMEPAGE(operandAddress, operandAddress + X))
{
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
}
operandAddress += X;
operand = peek(operandAddress);
}')
define(M6502_ABSOLUTEX_WRITE, `{
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
PC += 2;
operandAddress += X;
}')
define(M6502_ABSOLUTEX_READMODIFYWRITE, `{
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
PC += 2;
operandAddress += X;
operand = peek(operandAddress);
}')
define(M6502_ABSOLUTEY_READ, `{
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
PC += 2;
// See if we need to add one cycle for indexing across a page boundary
if(NOTSAMEPAGE(operandAddress, operandAddress + Y))
{
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
}
operandAddress += Y;
operand = peek(operandAddress);
}')
define(M6502_ABSOLUTEY_WRITE, `{
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
PC += 2;
operandAddress += Y;
}')
define(M6502_ABSOLUTEY_READMODIFYWRITE, `{
operandAddress = (uInt16)peek(PC) | ((uInt16)peek(PC + 1) << 8);
PC += 2;
operandAddress += Y;
operand = peek(operandAddress);
}')
define(M6502_ZERO_READ, `{
operandAddress = peek(PC++);
operand = peek(operandAddress);
}')
define(M6502_ZERO_WRITE, `{
operandAddress = peek(PC++);
}')
define(M6502_ZERO_READMODIFYWRITE, `{
operandAddress = peek(PC++);
operand = peek(operandAddress);
}')
define(M6502_ZEROX_READ, `{
operandAddress = (uInt8)(peek(PC++) + X);
operand = peek(operandAddress);
}')
define(M6502_ZEROX_WRITE, `{
operandAddress = (uInt8)(peek(PC++) + X);
}')
define(M6502_ZEROX_READMODIFYWRITE, `{
operandAddress = (uInt8)(peek(PC++) + X);
operand = peek(operandAddress);
}')
define(M6502_ZEROY_READ, `{
operandAddress = (uInt8)(peek(PC++) + Y);
operand = peek(operandAddress);
}')
define(M6502_ZEROY_WRITE, `{
operandAddress = (uInt8)(peek(PC++) + Y);
}')
define(M6502_ZEROY_READMODIFYWRITE, `{
operandAddress = (uInt8)(peek(PC++) + Y);
operand = peek(operandAddress);
}')
define(M6502_INDIRECT, `{
uInt16 addr = peek(PC) | ((uInt16)peek(PC + 1) << 8);
PC += 2;
// Simulate the error in the indirect addressing mode!
uInt16 high = NOTSAMEPAGE(addr, addr + 1) ? (addr & 0xff00) : (addr + 1);
operandAddress = peek(addr) | ((uInt16)peek(high) << 8);
}')
define(M6502_INDIRECTX_READ, `{
uInt8 pointer = peek(PC++) + X;
operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
operand = peek(operandAddress);
}')
define(M6502_INDIRECTX_WRITE, `{
uInt8 pointer = peek(PC++) + X;
operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
}')
define(M6502_INDIRECTX_READMODIFYWRITE, `{
uInt8 pointer = peek(PC++) + X;
operandAddress = peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
operand = peek(operandAddress);
}')
define(M6502_INDIRECTY_READ, `{
uInt8 pointer = peek(PC++);
operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
if(NOTSAMEPAGE(operandAddress, operandAddress + Y))
{
mySystem->incrementCycles(mySystemCyclesPerProcessorCycle);
}
operandAddress += Y;
operand = peek(operandAddress);
}')
define(M6502_INDIRECTY_WRITE, `{
uInt8 pointer = peek(PC++);
operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
operandAddress += Y;
}')
define(M6502_INDIRECTY_READMODIFYWRITE, `{
uInt8 pointer = peek(PC++);
operandAddress = (uInt16)peek(pointer) | ((uInt16)peek(pointer + 1) << 8);
operandAddress += Y;
operand = peek(operandAddress);
}')
define(M6502_BCC, `{
if(!C)
{
uInt16 address = PC + (Int8)operand;
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
PC = address;
}
}')
define(M6502_BCS, `{
if(C)
{
uInt16 address = PC + (Int8)operand;
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
PC = address;
}
}')
define(M6502_BEQ, `{
if(!notZ)
{
uInt16 address = PC + (Int8)operand;
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
PC = address;
}
}')
define(M6502_BMI, `{
if(N)
{
uInt16 address = PC + (Int8)operand;
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
PC = address;
}
}')
define(M6502_BNE, `{
if(notZ)
{
uInt16 address = PC + (Int8)operand;
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
PC = address;
}
}')
define(M6502_BPL, `{
if(!N)
{
uInt16 address = PC + (Int8)operand;
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
PC = address;
}
}')
define(M6502_BVC, `{
if(!V)
{
uInt16 address = PC + (Int8)operand;
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
PC = address;
}
}')
define(M6502_BVS, `{
if(V)
{
uInt16 address = PC + (Int8)operand;
mySystem->incrementCycles(NOTSAMEPAGE(PC, address) ?
mySystemCyclesPerProcessorCycle << 1 : mySystemCyclesPerProcessorCycle);
PC = address;
}
}')

View File

@ -0,0 +1,60 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: NullDev.cxx,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
//============================================================================
#include "NullDev.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NullDevice::NullDevice()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NullDevice::~NullDevice()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* NullDevice::name() const
{
return "NULL";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullDevice::reset()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullDevice::install(System& system)
{
mySystem = &system;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 NullDevice::peek(uInt16 address)
{
cerr << hex << "NullDevice: peek(" << address << ")" << endl;
return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void NullDevice::poke(uInt16 address, uInt8 value)
{
cerr << hex << "NullDevice: poke(" << address << "," << value << ")" << endl;
}

View File

@ -0,0 +1,86 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: NullDev.hxx,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
//============================================================================
#ifndef NULLDEVICE_HXX
#define NULLDEVICE_HXX
class System;
#include "bspf.hxx"
#include "Device.hxx"
/**
Class that represents a "null" device. The basic idea is that a
null device is installed in a 6502 based system anywhere there are
holes in the address space (i.e. no real device attached).
@author Bradford W. Mott
@version $Id: NullDev.hxx,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
*/
class NullDevice : public Device
{
public:
/**
Create a new null device
*/
NullDevice();
/**
Destructor
*/
virtual ~NullDevice();
public:
/**
Get a null terminated string which is the device's name (i.e. "M6532")
@return The name of the device
*/
virtual const char* name() const;
/**
Reset device to its power-on state
*/
virtual void reset();
/**
Install device in the specified system. Invoked by the system
when the device is attached to it.
@param system The system the device should install itself in
*/
virtual void install(System& system);
public:
/**
Get the byte at the specified address
@return The byte at the specified address
*/
virtual uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
virtual void poke(uInt16 address, uInt8 value);
};
#endif

View File

@ -0,0 +1,160 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: System.cxx,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
//============================================================================
#include <assert.h>
#include "Device.hxx"
#include "M6502.hxx"
#include "System.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
System::System(uInt16 n, uInt16 m)
: myAddressMask((1 << n) - 1),
myPageShift(m),
myPageMask((1 << m) - 1),
myNumberOfPages(1 << (n - m)),
myNumberOfDevices(0),
myM6502(0),
myCycles(0)
{
// Make sure the arguments are reasonable
assert((1 <= m) && (m <= n) && (n <= 16));
// Allocate page table
myPageAccessTable = new PageAccess[myNumberOfPages];
// Initialize page access table
PageAccess access;
access.directPeekBase = 0;
access.directPokeBase = 0;
access.device = &myNullDevice;
for(int page = 0; page < myNumberOfPages; ++page)
{
setPageAccess(page, access);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
System::~System()
{
// Free the devices attached to me, since I own them
for(uInt32 i = 0; i < myNumberOfDevices; ++i)
{
delete myDevices[i];
}
// Free the M6502 that I own
delete myM6502;
// Free my page access table
delete[] myPageAccessTable;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void System::reset()
{
// Reset system cycle counter
resetCycles();
// Frist we reset the devices attached to myself
for(uInt32 i = 0; i < myNumberOfDevices; ++i)
{
myDevices[i]->reset();
}
// Now we reset the processor if it exists
if(myM6502 != 0)
{
myM6502->reset();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void System::attach(Device* device)
{
assert(myNumberOfDevices < 100);
// Add device to my collection of devices
myDevices[myNumberOfDevices++] = device;
// Ask the device to install itself
device->install(*this);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void System::attach(M6502* m6502)
{
// Remember the processor
myM6502 = m6502;
// Ask the processor to install itself
myM6502->install(*this);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void System::resetCycles()
{
// Frist we let all of the device attached to me know about the reset
for(uInt32 i = 0; i < myNumberOfDevices; ++i)
{
myDevices[i]->systemCyclesReset();
}
// Now, we reset cycle count to zero
myCycles = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void System::setPageAccess(uInt16 page, const PageAccess& access)
{
// Make sure the page is within range
assert(page <= myNumberOfPages);
// Make sure the access methods make sense
assert(access.device != 0);
myPageAccessTable[page] = access;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const System::PageAccess& System::getPageAccess(uInt16 page)
{
// Make sure the page is within range
assert(page <= myNumberOfPages);
return myPageAccessTable[page];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
System::System(const System& s)
: myAddressMask(s.myAddressMask),
myPageShift(s.myPageShift),
myPageMask(s.myPageMask),
myNumberOfPages(s.myNumberOfPages)
{
assert(false);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
System& System::operator = (const System&)
{
assert(false);
return *this;
}

View File

@ -0,0 +1,310 @@
//============================================================================
//
// MM MM 6666 555555 0000 2222
// MMMM MMMM 66 66 55 00 00 22 22
// MM MMM MM 66 55 00 00 22
// MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator"
// MM MM 66 66 55 00 00 22
// MM MM 66 66 55 55 00 00 22
// MM MM 6666 5555 0000 222222
//
// Copyright (c) 1995-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: System.hxx,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
//============================================================================
#ifndef SYSTEM_HXX
#define SYSTEM_HXX
class Device;
class M6502;
class NullDevice;
#include "bspf.hxx"
#include "Device.hxx"
#include "NullDev.hxx"
/**
This class represents a system consisting of a 6502 microprocessor
and a set of devices. The devices are mapped into an addressing
space of 2^n bytes (1 <= n <= 16). The addressing space is broken
into 2^m byte pages (1 <= m <= n), where a page is the smallest unit
a device can use when installing itself in the system.
In general the addressing space will be 8192 (2^13) bytes for a
6507 based system and 65536 (2^16) bytes for a 6502 based system.
TODO: To allow for dynamic code generation we probably need to
add a tag to each page that indicates if it is read only
memory. We also need to notify the processor anytime a
page access method is changed so that it can clear the
dynamic code for that page of memory.
@author Bradford W. Mott
@version $Id: System.hxx,v 1.1.1.1 2001-12-27 19:54:31 bwmott Exp $
*/
class System
{
public:
/**
Create a new system with an addressing space of 2^n bytes and
pages of 2^m bytes.
@param n Log base 2 of the addressing space size
@param m Log base 2 of the page size
*/
System(uInt16 n, uInt16 m);
/**
Destructor
*/
virtual ~System();
public:
/**
Reset the system cycle counter, the attached devices, and the
attached processor of the system.
*/
void reset();
public:
/**
Attach the specified device and claim ownership of it. The device
will be asked to install itself.
@param device The device to attach to the system
*/
void attach(Device* device);
/**
Attach the specified processor and claim ownership of it. The
processor will be asked to install itself.
@param m6502 The 6502 microprocessor to attach to the system
*/
void attach(M6502* m6502);
public:
/**
Answer the 6502 microprocessor attached to the system. If a
processor has not been attached calling this function will fail.
@return The attached 6502 microprocessor
*/
M6502& m6502()
{
return *myM6502;
}
/**
Get the null device associated with the system. Every system
has a null device associated with it that's used by pages which
aren't mapped to "real" devices.
@return The null device associated with the system
*/
NullDevice& nullDevice()
{
return myNullDevice;
}
/**
Get the total number of pages available in the system.
@return The total number of pages available
*/
uInt16 numberOfPages() const
{
return myNumberOfPages;
}
/**
Get the amount to right shift an address by to obtain its page.
@return The amount to right shift an address by to get its page
*/
uInt16 pageShift() const
{
return myPageShift;
}
/**
Get the mask to apply to an address to obtain its page offset.
@return The mask to apply to an address to obtain its page offset
*/
uInt16 pageMask() const
{
return myPageMask;
}
public:
/**
Get the number of system cycles which have passed since the last
time cycles were reset or the system was reset.
@return The number of system cycles which have passed
*/
uInt32 cycles() const
{
return myCycles;
}
/**
Increment the system cycles by the specified number of cycles.
@param amount The amount to add to the system cycles counter
*/
void incrementCycles(uInt32 amount)
{
myCycles += amount;
}
/**
Reset the system cycle count to zero. The first thing that
happens is that all devices are notified of the reset by invoking
their systemCyclesReset method then the system cycle count is
reset to zero.
*/
void resetCycles();
public:
/*
Get the byte at the specified address. No masking of the
address occurs before it's sent to the device mapped at
the address.
@return The byte at the specified address
*/
uInt8 peek(uInt16 address);
/**
Change the byte at the specified address to the given value.
No masking of the address occurs before it's sent to the device
mapped at the address.
@param address The address where the value should be stored
@param value The value to be stored at the address
*/
void poke(uInt16 address, uInt8 value);
public:
/**
Structure used to specify access methods for a page
*/
struct PageAccess
{
/**
Pointer to a block of memory or the null pointer. The null pointer
indicates that the device's peek method should be invoked for reads
to this page, while other values are the base address of an array
to directly access for reads to this page.
*/
uInt8* directPeekBase;
/**
Pointer to a block of memory or the null pointer. The null pointer
indicates that the device's poke method should be invoked for writes
to this page, while other values are the base address of an array
to directly access for pokes to this page.
*/
uInt8* directPokeBase;
/**
Pointer to the device associated with this page or to the system's
null device if the page hasn't been mapped to a device
*/
Device* device;
};
/**
Set the page accessing method for the specified page.
@param page The page accessing methods should be set for
@param access The accessing methods to be used by the page
*/
void setPageAccess(uInt16 page, const PageAccess& access);
/**
Get the page accessing method for the specified page.
@param page The page to get accessing methods for
@return The accessing methods used by the page
*/
const PageAccess& getPageAccess(uInt16 page);
private:
// Mask to apply to an address before accessing memory
const uInt16 myAddressMask;
// Amount to shift an address by to determine what page it's on
const uInt16 myPageShift;
// Mask to apply to an address to obtain its page offset
const uInt16 myPageMask;
// Number of pages in the system
const uInt16 myNumberOfPages;
// Pointer to a dynamically allocated array of PageAccess structures
PageAccess* myPageAccessTable;
// Array of all the devices attached to the system
Device* myDevices[100];
// Number of devices attached to the system
uInt32 myNumberOfDevices;
// 6502 processor attached to the system or the null pointer
M6502* myM6502;
// Number of system cycles executed since the last reset
uInt32 myCycles;
// Null device to use for page which are not installed
NullDevice myNullDevice;
private:
// Copy constructor isn't supported by this class so make it private
System(const System&);
// Assignment operator isn't supported by this class so make it private
System& operator = (const System&);
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline uInt8 System::peek(uInt16 addr)
{
PageAccess& access = myPageAccessTable[(addr & myAddressMask) >> myPageShift];
// See if this page uses direct accessing or not
if(access.directPeekBase != 0)
{
return *(access.directPeekBase + (addr & myPageMask));
}
else
{
return access.device->peek(addr);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void System::poke(uInt16 addr, uInt8 value)
{
PageAccess& access = myPageAccessTable[(addr & myAddressMask) >> myPageShift];
// See if this page uses direct accessing or not
if(access.directPokeBase != 0)
{
*(access.directPokeBase + (addr & myPageMask)) = value;
}
else
{
access.device->poke(addr, value);
}
}
#endif

View File

@ -0,0 +1,37 @@
===============================================================================
BBBBB SSSS PPPPP FFFFFF
BB BB SS SS PP PP FF
BB BB SS PP PP FF
BBBBB SSSS PPPPP FFFF -- "Brad's Simple Portability Framework"
BB BB SS PP FF
BB BB SS SS PP FF
BBBBB SSSS PP FF
===============================================================================
License Information and Copyright Notice
===============================================================================
Copyright (C) 1995-2002 Bradford W. Mott <bwmott@acm.org>
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 any later version.
You should have received a copy of the GNU General Public License version 2
along with this program (License.txt); if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY
PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES
THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111 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
Appendix: 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) 19yy <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., 59 Temple Place, Suite 330, Boston, MA 02111 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) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -0,0 +1,72 @@
//============================================================================
//
// BBBBB SSSS PPPPP FFFFFF
// BB BB SS SS PP PP FF
// BB BB SS PP PP FF
// BBBBB SSSS PPPPP FFFF -- "Brad's Simple Portability Framework"
// BB BB SS PP FF
// BB BB SS SS PP FF
// BBBBB SSSS PP FF
//
// Copyright (c) 1997-1998 by Bradford W. Mott
//
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: bspf.hxx,v 1.1.1.1 2001-12-27 19:54:32 bwmott Exp $
//============================================================================
#ifndef BSPF_HXX
#define BSPF_HXX
/**
This file defines various basic data types and preprocessor variables
that need to be defined for different operating systems.
@author Bradford W. Mott
@version $Id: bspf.hxx,v 1.1.1.1 2001-12-27 19:54:32 bwmott Exp $
*/
// Types for 8-bit signed and unsigned integers
typedef signed char Int8;
typedef unsigned char uInt8;
// Types for 16-bit signed and unsigned integers
typedef signed short Int16;
typedef unsigned short uInt16;
// Types for 32-bit signed and unsigned integers
typedef signed int Int32;
typedef unsigned int uInt32;
// The following code should provide access to the standard C++ objects and
// types: cout, cerr, string, ostream, istream, etc.
#ifdef BSPF_WIN32
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
#else
#include <iostream.h>
#include <iomanip.h>
#include <string>
#endif
// Some compilers do not support the bool type yet :-(
#ifdef BSPF_BOOL
#define bool int
#define true 1
#define false 0
#endif
// Defines to help with path handling
#if defined BSPF_UNIX
#define BSPF_PATH_SEPARATOR '/'
#elif (defined(BSPF_DOS) || defined(BSPF_WIN32) || defined(BSPF_OS2))
#define BSPF_PATH_SEPARATOR '\\'
#elif defined BSPF_MACOS
#define BSPF_PATH_SEPARATOR ':'
#endif
#endif

View File

@ -0,0 +1,29 @@
/**
Simple program that produces a hex list of a binary object file
@author Bradford W. Mott
@version $Id: romtohex.cxx,v 1.1.1.1 2001-12-27 19:54:32 bwmott Exp $
*/
#include <iomanip.h>
#include <fstream.h>
main()
{
ifstream in("rom.o");
for(int t = 0; ; ++t)
{
unsigned char c;
in.get(c);
if(in.eof())
break;
cout << "0x" << hex << (int)c << ", ";
if((t % 8) == 7)
cout << endl;
}
cout << endl;
}

View File

@ -0,0 +1,81 @@
;;============================================================================
;;
;; SSSS tt lll lll
;; SS SS tt ll ll
;; SS tttttt eeee ll ll aaaa
;; SSSS tt ee ee ll ll aa
;; SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
;; SS SS tt ee ll ll aa aa
;; SSSS ttt eeeee llll llll aaaaa
;;
;; Copyright (c) 1995-1998 by Bradford W. Mott
;;
;; See the file "license" for information on usage and redistribution of
;; this file, and for a DISCLAIMER OF ALL WARRANTIES.
;;
;; $Id: scrom.asm,v 1.1.1.1 2001-12-27 19:54:32 bwmott Exp $
;;============================================================================
;;
;; This file contains a "dummy" Supercharger ROM for Stella. It basically
;; contains some bootstrapping code to get the game up and running.
;;
;;============================================================================
processor 6502
org $FA00
;;
;; Normal clear page zero routine for initial program load
;;
LDA #0
LDX #0
clear STA $80,X
INX
CPX #$80
BNE clear
JMP cpcode
;;
;; Clear page zero routine for multi-load
;;
org $FA20
LDA #0
LDX #0
mlclr STA $80,X
INX
CPX #$1E
BNE mlclr
;;
;; Now, copy some code into page zero to do the initial bank switch
;;
cpcode LDX #0
copy LDA code,X
STA $fa,X
INX
CPX #6
BNE copy
;;
;; Initialize X and Y registers
;;
LDX #$ff
LDY #$00
;;
;; Store the bank configuration in $80 and in CMP instruction
;;
LDA #$00 ;; $00 is changed by emulator to the correct value
STA $80
CMP $f000 ;; $00 is changed by emulator to the correct value
;;
;; Execute the code to do bank switch and start running cartridge code
;;
JMP $fa
code dc.b $ad, $f8, $ff ;; LDA $fff8
dc.b $4c, $00, $00 ;; JMP $???? ($???? is filled in by emulator)

Some files were not shown because too many files have changed in this diff Show More