mirror of https://github.com/stella-emu/stella.git
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:
parent
1dbf9ae846
commit
b87826ae62
|
@ -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!
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
|
@ -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
|
||||||
|
|
|
@ -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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
|
|
@ -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...
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 :-)
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 :-)
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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";
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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...
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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...
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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...
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
};
|
||||||
|
|
|
@ -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
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}')
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}')
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
Loading…
Reference in New Issue