mirror of
https://github.com/cmosher01/Epple-II.git
synced 2024-05-31 13:41:31 +00:00
Initial import from subversion repo
This commit is contained in:
parent
90823c3c46
commit
8f9eac131a
674
COPYING
Normal file
674
COPYING
Normal file
|
@ -0,0 +1,674 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. 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
|
||||
them 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 prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. 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.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey 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;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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 that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
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.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
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.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program 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, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU 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 Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
20
COPYING.other
Normal file
20
COPYING.other
Normal file
|
@ -0,0 +1,20 @@
|
|||
For the analogtv class, portions were inspired by Trevor Blackwell's analog
|
||||
TV module for xscreensaver. For those portions:
|
||||
/* analogtv, Copyright (c) 2003, 2004 Trevor Blackwell <tlb@tlb.org>
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation. No representations are made about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express or
|
||||
* implied warranty.
|
||||
*/
|
||||
Thanks, Trevor, for your code and your inspiration.
|
||||
|
||||
|
||||
|
||||
The ADC and SBC instructions of the CPU class were based on those taken
|
||||
from Verhille Arnaud's POM1 Apple 1 emulator. For those portions:
|
||||
// Copyright (C) 2000, by Verhille Arnaud, GPLv2 license.
|
||||
Thanks, Verhille.
|
180
COPYING.sdl
Normal file
180
COPYING.sdl
Normal file
|
@ -0,0 +1,180 @@
|
|||
EPPLE ][ makes use of the Simple DirectMedia Layer (SDL) library.
|
||||
|
||||
SDL is included under the terms of the LGPL license, a copy of which
|
||||
is provided below.
|
||||
|
||||
Windows: The EPPLE ][ executable (epple2.exe) links against SDL.dll.
|
||||
Linux: The EPPLE ][ executable (/bin/epple2) links against libSDL.so.
|
||||
These are standard versions of the SDL libaray, which are available
|
||||
from the SDL web site: http://wsw.libsdl.org
|
||||
|
||||
Many thanks to those who are responsible for making SDL what it is today,
|
||||
and making it freely available for others.
|
||||
|
||||
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser 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
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
167
INSTALL
Normal file
167
INSTALL
Normal file
|
@ -0,0 +1,167 @@
|
|||
Basic Installation
|
||||
==================
|
||||
|
||||
These are generic installation instructions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, a file
|
||||
`config.cache' that saves the results of its tests to speed up
|
||||
reconfiguring, and a file `config.log' containing compiler output
|
||||
(useful mainly for debugging `configure').
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If at some point `config.cache'
|
||||
contains results you don't want to keep, you may remove or edit it.
|
||||
|
||||
The file `configure.in' is used to create `configure' by a program
|
||||
called `autoconf'. You only need `configure.in' if you want to change
|
||||
it or regenerate `configure' using a newer version of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system. If you're
|
||||
using `csh' on an old version of System V, you might need to type
|
||||
`sh ./configure' instead to prevent `csh' from trying to execute
|
||||
`configure' itself.
|
||||
|
||||
Running `configure' takes a while. While running, it prints some
|
||||
messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Type `make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
4. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. You can give `configure'
|
||||
initial values for variables by setting them in the environment. Using
|
||||
a Bourne-compatible shell, you can do that on the command line like
|
||||
this:
|
||||
CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
|
||||
|
||||
Or on systems that have the `env' program, you can do it like this:
|
||||
env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you must use a version of `make' that
|
||||
supports the `VPATH' variable, such as GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'.
|
||||
|
||||
If you have to use a `make' that does not supports the `VPATH'
|
||||
variable, you have to compile the package for one architecture at a time
|
||||
in the source code directory. After you have installed the package for
|
||||
one architecture, use `make distclean' before reconfiguring for another
|
||||
architecture.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' will install the package's files in
|
||||
`/usr/local/bin', `/usr/local/man', etc. You can specify an
|
||||
installation prefix other than `/usr/local' by giving `configure' the
|
||||
option `--prefix=PATH'.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
give `configure' the option `--exec-prefix=PATH', the package will use
|
||||
PATH as the prefix for installing programs and libraries.
|
||||
Documentation and other data files will still use the regular prefix.
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' can not figure out
|
||||
automatically, but needs to determine by the type of host the package
|
||||
will run on. Usually `configure' can figure that out, but if it prints
|
||||
a message saying it can not guess the host type, give it the
|
||||
`--host=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name with three fields:
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the host type.
|
||||
|
||||
If you are building compiler tools for cross-compiling, you can also
|
||||
use the `--target=TYPE' option to select the type of system they will
|
||||
produce code for and the `--build=TYPE' option to select the type of
|
||||
system on which you are compiling the package.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Operation Controls
|
||||
==================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Use and save the results of the tests in FILE instead of
|
||||
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
|
||||
debugging `configure'.
|
||||
|
||||
`--help'
|
||||
Print a summary of the options to `configure', and exit.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made.
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`--version'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options.
|
||||
|
25
Makefile.am
Normal file
25
Makefile.am
Normal file
|
@ -0,0 +1,25 @@
|
|||
SUBDIRS = src conf installer
|
||||
|
||||
NAME = epple2
|
||||
VERSION = 1.0
|
||||
ARCH = i386
|
||||
|
||||
EXTRA_DIST = COPYING.sdl COPYING.other epple2.spec
|
||||
|
||||
RPM := $(abspath rpm)
|
||||
|
||||
package: $(NAME).spec dist
|
||||
mkdir -p $(RPM)/BUILD
|
||||
mkdir -p $(RPM)/BUILDROOT
|
||||
mkdir -p $(RPM)/RPMS
|
||||
mkdir -p $(RPM)/SOURCES
|
||||
mkdir -p $(RPM)/SPECS
|
||||
mkdir -p $(RPM)/SRPMS
|
||||
mkdir -p $(RPM)/VPATH
|
||||
cp $(NAME)-$(VERSION).tar.gz $(RPM)/SOURCES
|
||||
touch .rpmmacros
|
||||
echo "%_prefix $(prefix)" >>$(RPM)/.rpmmacros
|
||||
echo "%_sysconfdir $(sysconfdir)" >>$(RPM)/.rpmmacros
|
||||
echo "%_topdir $(RPM)" >>$(RPM)/.rpmmacros
|
||||
HOME=$(RPM) rpmbuild -ba --clean --buildroot $(RPM)/BUILDROOT $<
|
||||
fakeroot alien $(RPM)/RPMS/$(ARCH)/$(NAME)-$(VERSION)-1.$(ARCH).rpm
|
135
README
Normal file
135
README
Normal file
|
@ -0,0 +1,135 @@
|
|||
epple2 (Emulated Apple ][)
|
||||
--------------------------
|
||||
|
||||
|
||||
epple2 is an emulator of the Apple ][ and Apple ][ plus
|
||||
computers from Apple, Inc. It strives to faithfully simulate
|
||||
much of the internal workings of the original Apple ][,
|
||||
including the individual cycles of the 6502 CPU, and the
|
||||
NTSC video signal generation, including the "strange orange
|
||||
line", other color anomalies, and the "floating data bus."
|
||||
Understanding the Apple ][, by Jim Sather, is the primary
|
||||
source for information about the internals of the Apple ][.
|
||||
|
||||
The CPU and video timings are synchronized, and the emulator
|
||||
is designed to run at the same speed as the original
|
||||
machine (if your computer is fast enough). It also emulates
|
||||
several different types of television screens and monitors
|
||||
for the display.
|
||||
|
||||
It includes emulation of a Disk ][ controller card, a ROM
|
||||
firmware card, and a RAM "Language" card, as well as a
|
||||
simple clock card.
|
||||
|
||||
epple2 is written in C++, and is designed to be buildable
|
||||
on Windows (with MSYS/MinGW or Visual C++ 2008, Express
|
||||
Edition) or Linux (gcc).
|
||||
|
||||
The SDL library (http://www.libsdl.org) is the only dependency
|
||||
of epple2 (see below).
|
||||
|
||||
The epple2 is released under GPLv3.
|
||||
|
||||
|
||||
|
||||
RUNNING
|
||||
-------
|
||||
SDL:
|
||||
To run epple2, you need to have the SDL libraries installed.
|
||||
See http://www.libsdl.org for information on SDL.
|
||||
You'll need to download and install the "Runtime Libraries"
|
||||
for your platform (Win32 or Linux).
|
||||
|
||||
ROM:
|
||||
With epple2 and SDL, you can run the emulator, but it won't
|
||||
do too much without the appropriate Apple ROM code. You can
|
||||
use ROM images from your own original Apple ][ or ][ plus, or
|
||||
you can find some on the Internet (check the Asimov Apple
|
||||
repository).
|
||||
Alternatively, you can build the ROMs yourself from assembly
|
||||
language source files I've created; these are available in
|
||||
the apple2src project. (See that project for details).
|
||||
|
||||
Disks:
|
||||
You will also probably want floppy disk images. Again, you can
|
||||
download some from the Internet, especially from Asimov. The
|
||||
epple2 only reads NIBBLE IMAGES. If you only have 16 sector
|
||||
images, you will need to convert them to nibble images; you
|
||||
can use CiderPress (http://ciderpress.sourceforge.net).
|
||||
|
||||
|
||||
|
||||
|
||||
BUILDING
|
||||
--------
|
||||
See INSTALL for generic instructions on building and installing
|
||||
a normal distribution.
|
||||
|
||||
If you want to build epple2 from the source distribution,
|
||||
you'll need to have the SDL development libraries installed.
|
||||
See http://www.libsdl.org for information on SDL.
|
||||
You'll need to download and install the "Development Libraries"
|
||||
for your platform (Win32 or Linux).
|
||||
|
||||
Developers fetching directly from the repository instead of
|
||||
downloading the distribution will need to execute the bootstrap
|
||||
script before running ./configure or make.
|
||||
|
||||
|
||||
|
||||
PLATFORM-SPECIFIC BUILDING
|
||||
--------------------------
|
||||
|
||||
Windows/MSYS
|
||||
--------------
|
||||
Install MSYS into C:\MSYS\1.0
|
||||
Install MinGW into C:\mingw
|
||||
|
||||
Install SDL. At http://www.libsdl.org/ find the download page.
|
||||
Download the "Development Libraries" for Win32, mingw, for example:
|
||||
SDL-devel-1.2.13-mingw32.tar.gz (Mingw32)
|
||||
And save it to your MSYS home directory.
|
||||
Untar the SDL archive to your home directory:
|
||||
$ cd
|
||||
$ tar xzvf SDL-devel-1.2.13-mingw32.tar.gz
|
||||
Then follow the instructions to install SDL, for example:
|
||||
$ cd SDL-1.2.13
|
||||
$ make native
|
||||
|
||||
|
||||
|
||||
Run MSYS, and at the bash prompt, go to your home directory and
|
||||
untar the epple2 source distribution tar file and cd to the
|
||||
epple2 directory. For example:
|
||||
$ cd
|
||||
$ tar xzvf epple2-1.0.tar.gz
|
||||
|
||||
NOTE: If you checked out epple2 from subversion, rather
|
||||
than downloading the distribution, you need to first run
|
||||
the bootstrap script. But first you'll need to install
|
||||
autoconf, automake, etc.
|
||||
$ cd
|
||||
$ cd epple2
|
||||
$ ./bootstrap
|
||||
|
||||
|
||||
|
||||
Then build as follows. I recommend doing a VPATH build, in
|
||||
which you build into a different directory that the source
|
||||
directory. To accomplish this, create a new directory for
|
||||
building, somewhere, such as:
|
||||
$ cd
|
||||
$ mkdir buildepple2
|
||||
$ cd buildepple2
|
||||
Then run configure from there. For the MSYS build to work,
|
||||
you need some extra parameters to the build, and you could
|
||||
also add some compiler options to optimize the build. For
|
||||
example (from the buildepple2 directory you just created):
|
||||
$ ~/epple2/configure --prefix= \
|
||||
CXXFLAGS="-I/usr/include -O4 -msse3" \
|
||||
CFLAGS="-I/usr/include" \
|
||||
LDFLAGS="-L/usr/lib -mconsole -mthreads -mno-cygwin"
|
||||
$ make
|
||||
$ make install
|
||||
|
||||
Then follow the instruction above under "RUNNING" for ROM and disks.
|
25
conf/Makefile.am
Normal file
25
conf/Makefile.am
Normal file
|
@ -0,0 +1,25 @@
|
|||
etcdir = $(sysconfdir)/epple2
|
||||
|
||||
if HAVE_WINDOWS
|
||||
CONF_PREFIX =
|
||||
else
|
||||
CONF_PREFIX = $(prefix)/
|
||||
endif
|
||||
|
||||
%.conf: %.conf.in
|
||||
sed -e 's,$$(PREFIX),$(CONF_PREFIX),g' <$< >$@
|
||||
|
||||
CONF_FILES = \
|
||||
epple2.conf \
|
||||
epple2.a2bare.conf \
|
||||
epple2.a2dos33.conf \
|
||||
epple2.a2pbare.conf \
|
||||
epple2.a2ploaded.conf \
|
||||
epple2.rev0bare.conf \
|
||||
epple2.a2dos31.conf \
|
||||
epple2.a2loaded.conf \
|
||||
epple2.a2pdos33.conf
|
||||
|
||||
etc_DATA = $(CONF_FILES)
|
||||
|
||||
EXTRA_DIST = $(etc_DATA)
|
11
conf/epple2.a2bare.conf.in
Normal file
11
conf/epple2.a2bare.conf.in
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Apple ][ (with revision 1 or later motherboard), bare
|
||||
#
|
||||
# This set up is a standard Apple ][ (with a newer motherboard,
|
||||
# that is, not an original revision zero motherboard), and
|
||||
# nothing in any slots. It has Integer BASIC and the old Monitor ROMs.
|
||||
|
||||
|
||||
|
||||
import motherboard rom 1000 $(PREFIX)lib/apple2/system/intbasic/intbasic.ex65
|
||||
import motherboard rom 2425 $(PREFIX)lib/apple2/system/other/other.ex65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/monitor/apple2/monitor.ex65
|
24
conf/epple2.a2dos31.conf.in
Normal file
24
conf/epple2.a2dos31.conf.in
Normal file
|
@ -0,0 +1,24 @@
|
|||
# Apple ][ with (13-sector) DOS 3.1 (the original version of DOS 3.3).
|
||||
#
|
||||
# After power-up, type C600G to boot the DOS 3.1 System Master disk.
|
||||
#
|
||||
# Since this System Master disk has "APPLESOFT" on it, you can type
|
||||
# FP at the Integer BASIC prompt to run Applesoft BASIC. When you do
|
||||
# it this way, you get an interesting title page for Applesoft, showing
|
||||
# copyright notices for Apple and Microsoft.
|
||||
|
||||
|
||||
|
||||
# Integer BASIC and old Monitor ROMs
|
||||
import motherboard rom 1000 $(PREFIX)lib/apple2/system/intbasic/intbasic.ex65
|
||||
import motherboard rom 2425 $(PREFIX)lib/apple2/system/other/other.ex65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/monitor/apple2/monitor.ex65
|
||||
|
||||
|
||||
|
||||
# Disk ][ card with 13-sector ROMs
|
||||
slot 6 disk
|
||||
import slot 6 rom 0 $(PREFIX)lib/apple2/dos3x/13sector/controller/disk2.ex65
|
||||
|
||||
# Insert DOS 3.1 System Master disk into drive 1
|
||||
load slot 6 drive 1 $(PREFIX)lib/apple2/dos3x/13sector/disks/dos310/clean31sysmas_stock_rawdos.nib
|
29
conf/epple2.a2dos33.conf.in
Normal file
29
conf/epple2.a2dos33.conf.in
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Apple ][ with language card and DOS 3.3 (original version)
|
||||
#
|
||||
# After power-on, type C600G to boot the DOS 3.3 System Master disk.
|
||||
# Notice it shows "APPLE II STANDARD" for this machine, and then it
|
||||
# loads APPLESOFT into the language card.
|
||||
#
|
||||
# You can use FP to switch to Applesoft, and INT to switch
|
||||
# back to Integer BASIC. As you do this, notice the "R" reading
|
||||
# indicator on the language card line turning on or off.
|
||||
|
||||
|
||||
# Integer BASIC and old Monitor ROMs
|
||||
import motherboard rom 1000 $(PREFIX)lib/apple2/system/intbasic/intbasic.ex65
|
||||
import motherboard rom 2425 $(PREFIX)lib/apple2/system/other/other.ex65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/monitor/apple2/monitor.ex65
|
||||
|
||||
|
||||
|
||||
# Language card in slot 0
|
||||
slot 0 language
|
||||
|
||||
|
||||
|
||||
# Disk ][ controller card in slot 6, with 16-sector ROMs
|
||||
slot 6 disk
|
||||
import slot 6 rom 0 $(PREFIX)lib/apple2/dos3x/16sector/controller/disk2.ex65
|
||||
|
||||
# Insert DOS 3.3 System Master disk (original version) in drive 1
|
||||
load slot 6 drive 1 $(PREFIX)lib/apple2/dos3x/16sector/disks/dos330/clean330sysmas.nib
|
68
conf/epple2.a2loaded.conf.in
Normal file
68
conf/epple2.a2loaded.conf.in
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Apple ][, loaded
|
||||
#
|
||||
# This is an Apple ][ (Integer BASIC and old Monitor), with
|
||||
# every card provided by the EPPLE ][ Emulator installed.
|
||||
#
|
||||
# Since this machine doesn't have the Autostart Monitor, after powering
|
||||
# it on you'll need to type C600G to boot the DOS 3.3 System Master,
|
||||
# or C500G to boot the DOS 3.1 System Master.
|
||||
|
||||
|
||||
|
||||
# Integer BASIC and old Monitor ROMs
|
||||
import motherboard rom 1000 $(PREFIX)lib/apple2/system/intbasic/intbasic.ex65
|
||||
import motherboard rom 2425 $(PREFIX)lib/apple2/system/other/other.ex65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/monitor/apple2/monitor.ex65
|
||||
|
||||
|
||||
|
||||
# Language card in slot 0. When the DOS 3.3 System Master boots,
|
||||
# it will load Applesoft into the language card.
|
||||
slot 0 language
|
||||
|
||||
|
||||
|
||||
# Standard-output "card" in slot 1, so typing
|
||||
# PR#1 will start sending characters to standard output of the emulator
|
||||
slot 1 stdout
|
||||
import slot 1 rom 0 $(PREFIX)lib/epple2/cards/stdout.ex65
|
||||
|
||||
|
||||
|
||||
# Standard-input "card" in slot 2, so typing
|
||||
# IN#2 will start reading characters from standard input of the emulator
|
||||
slot 2 stdin
|
||||
import slot 2 rom 0 $(PREFIX)lib/epple2/cards/stdin.ex65
|
||||
|
||||
|
||||
|
||||
# Clock card in slot 4
|
||||
slot 4 clock
|
||||
import slot 4 rom 0 $(PREFIX)lib/epple2/cards/clock.ex65
|
||||
|
||||
|
||||
|
||||
# Disk ][ controller card in slot 5, with 13-sector ROMs.
|
||||
# This will read (DOS 3.1, 3.2, and 3.2.1) disks, which
|
||||
# have 13 sectors per track.
|
||||
slot 5 disk
|
||||
import slot 5 rom 0 $(PREFIX)lib/apple2/dos3x/13sector/controller/disk2.ex65
|
||||
# Insert the DOS 3.1 System Master disk into drive 1 of slot 5
|
||||
load slot 5 drive 1 $(PREFIX)lib/apple2/dos3x/13sector/disks/dos310/clean31sysmas_stock_rawdos.nib
|
||||
|
||||
|
||||
|
||||
# Disk ][ controller card in slot 6, with 16-sector ROMs.
|
||||
# This will read (DOS 3.3) disks, which have 16 sectors per track.
|
||||
slot 6 disk
|
||||
import slot 6 rom 0 $(PREFIX)lib/apple2/dos3x/16sector/controller/disk2.ex65
|
||||
# Insert the DOS 3.3 System Master disk (original version) into slot 6
|
||||
load slot 6 drive 1 $(PREFIX)lib/apple2/dos3x/16sector/disks/dos330/clean330sysmas.nib
|
||||
|
||||
|
||||
|
||||
# Firmware card with Applesoft and Autostart Monitor.
|
||||
# DOS will not use this firmware card, because it is not in slot 0.
|
||||
slot 7 firmware
|
||||
import slot 7 rombank 0000 $(PREFIX)lib/apple2/system/applesoft/applesoft.ex65
|
||||
import slot 7 rombank 2800 $(PREFIX)lib/apple2/system/monitor/apple2plus/monitor.ex65
|
10
conf/epple2.a2pbare.conf.in
Normal file
10
conf/epple2.a2pbare.conf.in
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Apple ][ plus, bare
|
||||
#
|
||||
# This set up is a standard Apple ][ plus, and
|
||||
# nothing in any slots. It has Applesoft BASIC
|
||||
# and the Autostart Monitor ROMs.
|
||||
|
||||
|
||||
|
||||
import motherboard rom 0000 $(PREFIX)lib/apple2/system/applesoft/applesoft.ex65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/monitor/apple2plus/monitor.ex65
|
28
conf/epple2.a2pdos33.conf.in
Normal file
28
conf/epple2.a2pdos33.conf.in
Normal file
|
@ -0,0 +1,28 @@
|
|||
# Apple ][ plus, with language card and DOS 3.3 (original version)
|
||||
#
|
||||
# After power-on, it will boot the DOS 3.3 System Master disk.
|
||||
# Notice it shows "APPLE II PLUS OR ROMCARD" for this machine, and then it
|
||||
# loads Integer BASIC into the language card.
|
||||
#
|
||||
# You can use FP to switch to Applesoft, and INT to switch
|
||||
# back to Integer BASIC. As you do this, notice the "R" reading
|
||||
# indicator on the language card line turning on or off.
|
||||
|
||||
|
||||
# Applesoft BASIC and Autostart Monitor ROMs
|
||||
import motherboard rom 0000 $(PREFIX)lib/apple2/system/applesoft/applesoft.ex65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/monitor/apple2plus/monitor.ex65
|
||||
|
||||
|
||||
|
||||
# Language card in slot 0
|
||||
slot 0 language
|
||||
|
||||
|
||||
|
||||
# Disk ][ controller card in slot 6, with 16-sector ROMs
|
||||
slot 6 disk
|
||||
import slot 6 rom 0 $(PREFIX)lib/apple2/dos3x/16sector/controller/disk2.ex65
|
||||
|
||||
# Insert DOS 3.3 System Master disk (original version) in drive 1
|
||||
load slot 6 drive 1 $(PREFIX)lib/apple2/dos3x/16sector/disks/dos330/clean330sysmas.nib
|
68
conf/epple2.a2ploaded.conf.in
Normal file
68
conf/epple2.a2ploaded.conf.in
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Apple ][ plus, loaded
|
||||
#
|
||||
# This is an Apple ][ plus (Applesoft BASIC and Autostart Monitor), with
|
||||
# every card provided by the EPPLE ][ Emulator installed.
|
||||
#
|
||||
# This machine has two Disk ][ controller cards; the Autostart Monitor
|
||||
# searches from slot 7 downwards for a Disk ][ card, so it will boot
|
||||
# the disk in slot 6, the DOS 3.3 System Master.
|
||||
|
||||
|
||||
|
||||
# Applesoft BASIC and Autostart Monitor ROMs
|
||||
import motherboard rom 0000 $(PREFIX)lib/apple2/system/applesoft/applesoft.ex65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/monitor/apple2plus/monitor.ex65
|
||||
|
||||
|
||||
|
||||
# Language card in slot 0. When the DOS 3.3 System Master boots,
|
||||
# it will load Integer BASIC into the language card.
|
||||
slot 0 language
|
||||
|
||||
|
||||
|
||||
# Standard-output "card" in slot 1, so typing
|
||||
# PR#1 will start sending characters to standard output of the emulator
|
||||
slot 1 stdout
|
||||
import slot 1 rom 0 $(PREFIX)lib/epple2/cards/stdout.ex65
|
||||
|
||||
|
||||
|
||||
# Standard-input "card" in slot 2, so typing
|
||||
# IN#2 will start reading characters from standard input of the emulator
|
||||
slot 2 stdin
|
||||
import slot 2 rom 0 $(PREFIX)lib/epple2/cards/stdin.ex65
|
||||
|
||||
|
||||
|
||||
# Clock card in slot 4
|
||||
slot 4 clock
|
||||
import slot 4 rom 0 $(PREFIX)lib/epple2/cards/clock.ex65
|
||||
|
||||
|
||||
|
||||
# Disk ][ controller card in slot 5, with 13-sector ROMs.
|
||||
# This will read (DOS 3.1, 3.2, and 3.2.1) disks, which
|
||||
# have 13 sectors per track.
|
||||
slot 5 disk
|
||||
import slot 5 rom 0 $(PREFIX)lib/apple2/dos3x/13sector/controller/disk2.ex65
|
||||
# Insert the DOS 3.1 System Master disk into drive 1 of slot 5
|
||||
load slot 5 drive 1 $(PREFIX)lib/apple2/dos3x/13sector/disks/dos310/clean31sysmas_stock_rawdos.nib
|
||||
|
||||
|
||||
|
||||
# Disk ][ controller card in slot 6, with 16-sector ROMs.
|
||||
# This will read (DOS 3.3) disks, which have 16 sectors per track.
|
||||
slot 6 disk
|
||||
import slot 6 rom 0 $(PREFIX)lib/apple2/dos3x/16sector/controller/disk2.ex65
|
||||
# Insert the DOS 3.3 System Master disk (original version) into slot 6
|
||||
load slot 6 drive 1 $(PREFIX)lib/apple2/dos3x/16sector/disks/dos330/clean330sysmas.nib
|
||||
|
||||
|
||||
|
||||
# Firmware card with Integer BASIC and the old Monitor.
|
||||
# DOS will not use this firmware card, because it is not in slot 0.
|
||||
slot 7 firmware
|
||||
import slot 7 rombank 1000 $(PREFIX)lib/apple2/system/intbasic/intbasic.ex65
|
||||
import slot 7 rombank 2425 $(PREFIX)lib/apple2/system/other/other.ex65
|
||||
import slot 7 rombank 2800 $(PREFIX)lib/apple2/system/monitor/apple2/monitor.ex65
|
55
conf/epple2.conf.in
Normal file
55
conf/epple2.conf.in
Normal file
|
@ -0,0 +1,55 @@
|
|||
# epple2.conf
|
||||
# Copyright 2009, by Chris Mosher <chris@mosher.mine.nu>
|
||||
# GPLv3
|
||||
#
|
||||
# Configuration file for the Epple 2 emulator.
|
||||
#
|
||||
# This sample file is the default setup for the emulator.
|
||||
# It does not load any proprietary ROMs, only GPLv3 ROMs
|
||||
# written by the author of the emulator.
|
||||
#
|
||||
|
||||
|
||||
|
||||
# Demo system ROM for the emulator. This is only to allow the
|
||||
# emulator to do something useful when there are no real Apple ROM
|
||||
# images provided.
|
||||
#
|
||||
import motherboard rom 2C00 $(PREFIX)lib/epple2/system/epple2sys.ex65
|
||||
|
||||
# These are how to load the real (proprietary) Apple ROMs.
|
||||
# There ROMs are not distributed with the Epple 2 emulator.
|
||||
# These two lines are for an Apple ][ plus:
|
||||
#import motherboard rom 0000 $(PREFIX)lib/apple2/system/applesoft/applesoft.ex65
|
||||
#import motherboard rom 2800 $(PREFIX)lib/apple2/system/monitor/apple2plus/monitor.ex65
|
||||
# or instead, use these three lines are for an Apple ][:
|
||||
#import motherboard rom 1000 $(PREFIX)lib/apple2/system/intbasic/intbasic.ex65
|
||||
#import motherboard rom 2425 $(PREFIX)lib/apple2/system/other/other.ex65
|
||||
#import motherboard rom 2800 $(PREFIX)lib/apple2/system/monitor/apple2/monitor.ex65
|
||||
|
||||
slot 0 language
|
||||
|
||||
slot 1 stdout
|
||||
import slot 1 rom 0 $(PREFIX)lib/epple2/cards/stdout.ex65
|
||||
|
||||
slot 2 stdin
|
||||
import slot 2 rom 0 $(PREFIX)lib/epple2/cards/stdin.ex65
|
||||
|
||||
slot 4 clock
|
||||
import slot 4 rom 0 $(PREFIX)lib/epple2/cards/clock.ex65
|
||||
|
||||
#slot 5 disk
|
||||
#import slot 5 rom 0 $(PREFIX)lib/apple2/dos3x/13sector/controller/disk2.ex65
|
||||
#load slot 5 drive 1 $(PREFIX)lib/apple2/dos3x/13sector/disks/dos310/clean31sysmas_stock_rawdos.nib
|
||||
|
||||
#slot 6 disk
|
||||
#import slot 6 rom 0 $(PREFIX)lib/apple2/dos3x/16sector/controller/disk2.ex65
|
||||
#load slot 6 drive 1 $(PREFIX)lib/apple2/dos3x/16sector/disks/dos330/clean330sysmas.nib
|
||||
|
||||
#slot 7 firmware
|
||||
#import slot 7 rombank 1000 $(PREFIX)lib/apple2/system/intbasic/intbasic.ex65
|
||||
#import slot 7 rombank 2425 $(PREFIX)lib/apple2/system/other/other.ex65
|
||||
#import slot 7 rombank 2800 $(PREFIX)lib/apple2/system/monitor/apple2/monitor.ex65
|
||||
|
||||
#revision 0
|
||||
revision 1
|
21
conf/epple2.rev0bare.conf.in
Normal file
21
conf/epple2.rev0bare.conf.in
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Apple ][ with revision zero motherboard
|
||||
#
|
||||
# This sets up a revision zero motherboard, and loads
|
||||
# Integer BASIC and the old Monitor ROMs. This set up
|
||||
# has nothing in any slots; it's a minimalist Apple ][.
|
||||
#
|
||||
# With a revision zero motherboard, powering on the machine
|
||||
# doesn't start it running; you need to press RESET (Break)
|
||||
# to get it actually running.
|
||||
|
||||
|
||||
|
||||
# Load Integer BASIC and old Monitor ROMs
|
||||
import motherboard rom 1000 $(PREFIX)lib/apple2/system/intbasic/intbasic.ex65
|
||||
import motherboard rom 2425 $(PREFIX)lib/apple2/system/other/other.ex65
|
||||
import motherboard rom 2800 $(PREFIX)lib/apple2/system/monitor/apple2/monitor.ex65
|
||||
|
||||
|
||||
|
||||
# Use an original, revision zero, motherboard
|
||||
revision 0
|
50
configure.ac
Normal file
50
configure.ac
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Process this file with autoconf to produce a configure script.
|
||||
AC_INIT(src/apple2.cpp)
|
||||
AC_PREREQ(2.59)
|
||||
|
||||
AC_CONFIG_SRCDIR([config.h.in])
|
||||
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
AM_INIT_AUTOMAKE(epple2, 1.0)
|
||||
|
||||
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CXX
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_RANLIB
|
||||
AM_PROG_CC_C_O
|
||||
|
||||
# Checks for libraries.
|
||||
AC_CHECK_LIB([SDL],[SDL_Init],,[AC_MSG_ERROR([cannot find libsdl])])
|
||||
AC_CHECK_LIB([X11],[XOpenDisplay],,[AC_MSG_ERROR([cannot find X11])])
|
||||
|
||||
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDBOOL
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_TYPE_SIZE_T
|
||||
AC_CHECK_HEADERS([windows.h])
|
||||
AC_CHECK_HEADER([windows.h],[WINDOWS=true].[WINDOWS=])
|
||||
AM_CONDITIONAL([HAVE_WINDOWS],test "$WINDOWS")
|
||||
|
||||
# Checks for library functions.
|
||||
AC_HEADER_STDC
|
||||
AC_TYPE_SIGNAL
|
||||
AC_CHECK_FUNCS([memset sqrt])
|
||||
|
||||
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
|
||||
|
||||
|
||||
AC_CONFIG_FILES([Makefile src/Makefile conf/Makefile installer/Makefile])
|
||||
AC_OUTPUT
|
31
epple2.spec
Normal file
31
epple2.spec
Normal file
|
@ -0,0 +1,31 @@
|
|||
Summary: EPPLE ][, The Emulated Apple ][
|
||||
Name: epple2
|
||||
Version: 1.0
|
||||
Release: 1
|
||||
Source: %{name}-%{version}.tar.gz
|
||||
License: GPL
|
||||
Group: System/Emulators/Other
|
||||
|
||||
%description
|
||||
EPPLE ][ is an emulator of Apple ][ and Apple ][ plus computers.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
%build
|
||||
cd ../../VPATH
|
||||
if [ -x ./config.status ]
|
||||
then
|
||||
./config.status
|
||||
else
|
||||
../BUILD/%{name}-%{version}/configure --prefix=%{_prefix} --sysconfdir=%{_sysconfdir}
|
||||
fi
|
||||
make
|
||||
|
||||
%install
|
||||
cd ../../VPATH
|
||||
make install DESTDIR=%{buildroot}
|
||||
|
||||
%files
|
||||
%{_bindir}/%{name}
|
||||
%{_sysconfdir}/%{name}
|
17
installer/Makefile.am
Normal file
17
installer/Makefile.am
Normal file
|
@ -0,0 +1,17 @@
|
|||
EXTRA_DIST = epple2.wxs
|
||||
|
||||
if HAVE_WINDOWS
|
||||
|
||||
SUFFIXES = .wxs .wixobj .msi
|
||||
|
||||
all: epple2.msi
|
||||
|
||||
epple2.msi: epple2.wixobj ../src/epple2.exe
|
||||
strip -o epple2.exe ../src/epple2.exe
|
||||
light $< -out $@
|
||||
cp $@ $(basename $@)-$(VERSION)$(suffix $@)
|
||||
|
||||
epple2.wixobj: epple2.wxs
|
||||
candle $< -out $@ -dSDLDIR=/bin -dMINGWMDIR=/mingw/bin
|
||||
|
||||
endif
|
61
installer/epple2.wxs
Normal file
61
installer/epple2.wxs
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
|
||||
<Product Name="EPPLE ][" Id="d603c69f-4116-4b8e-910f-44f488a772a4" Language="1033" Codepage="1252" Version="1.0.0" Manufacturer="Chris Mosher">
|
||||
<Package Id="0ca046fe-0adb-4df3-9fab-048baa55b165" Description="Emulated Apple ][" InstallerVersion="100" Languages="1033" Compressed="yes" />
|
||||
<Media Id="1" Cabinet="Epple2.cab" EmbedCab="yes" DiskPrompt="Epple2.cab" />
|
||||
<Property Id="DiskPrompt" Value="Epple ][ Installation" />
|
||||
|
||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||
<Directory Id="ProgramFilesFolder" Name="PFiles">
|
||||
<Directory Id="INSTALLDIR" Name="Epple2">
|
||||
<Directory Id="bindot" Name=".">
|
||||
<Directory Id="bin" Name="bin">
|
||||
<Component Id="MainExecutable" Guid="d3f60e2b-92e2-4a41-b83a-a38591c2e6c3">
|
||||
<File Id="EPPLE2_EXE" Name="epple2.exe" DiskId="1" Source="epple2.exe" Vital="yes">
|
||||
<Shortcut Id="startmenuEpple2" Directory="ProgramMenuDir" Name="Epple2" WorkingDirectory="INSTALLDIR" />
|
||||
<Shortcut Id="desktopEpple2" Directory="DesktopFolder" Name="Epple2" WorkingDirectory="INSTALLDIR" />
|
||||
</File>
|
||||
<RemoveFolder Id="ProgramMenuDir" On="uninstall" />
|
||||
</Component>
|
||||
<Component Id="SDL" Guid="d8e283c0-9af6-4275-8d66-45ca2a0e51ce">
|
||||
<File Id="SDLDLL" Name="sdl.dll" DiskId="1" Source="$(var.SDLDIR)\SDL.dll" />
|
||||
</Component>
|
||||
|
||||
<Component Id="MINGWM" Guid="d8e283c0-9af6-4275-8d66-45ca2a0e51ce">
|
||||
<File Id="MINGWMDLL" Name="mingwm10.dll" DiskId="1" Source="$(var.MINGWMDIR)\mingwm10.dll" />
|
||||
</Component>
|
||||
</Directory>
|
||||
</Directory>
|
||||
|
||||
<Directory Id="etcdot" Name=".">
|
||||
<Directory Id="etc" Name="etc">
|
||||
<Directory Id="etc_epple2" Name="epple2">
|
||||
<Component Id="ConfigFiles" Guid="73057afd-e28b-48b1-b428-6e2bf029b74d">
|
||||
<File Id="Config" Name="epple2.cfg" LongName="epple2.conf" DiskId="1" Source="..\conf\epple2.conf" Vital="yes" />
|
||||
<File Id="Config_rev0bare" Name="epple2_1.cfg" LongName="epple2.rev0bare.conf" DiskId="1" Source="..\conf\epple2.rev0bare.conf" Vital="yes" />
|
||||
<File Id="Config_a2bare" Name="epple2_2.cfg" LongName="epple2.a2bare.conf" DiskId="1" Source="..\conf\epple2.a2bare.conf" Vital="yes" />
|
||||
<File Id="Config_a2dos31" Name="epple2_3.cfg" LongName="epple2.a2dos31.conf" DiskId="1" Source="..\conf\epple2.a2dos31.conf" Vital="yes" />
|
||||
<File Id="Config_a2dos33" Name="epple2_4.cfg" LongName="epple2.a2dos33.conf" DiskId="1" Source="..\conf\epple2.a2dos33.conf" Vital="yes" />
|
||||
<File Id="Config_a2loaded" Name="epple2_5.cfg" LongName="epple2.a2loaded.conf" DiskId="1" Source="..\conf\epple2.a2loaded.conf" Vital="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
</Directory>
|
||||
|
||||
<Directory Id="ProgramMenuFolder" Name="PMenu" LongName="Programs">
|
||||
<Directory Id="ProgramMenuDir" Name="Epple2" />
|
||||
</Directory>
|
||||
|
||||
<Directory Id="DesktopFolder" Name="Desktop" />
|
||||
</Directory>
|
||||
|
||||
<Feature Id="Complete" Level="1">
|
||||
<ComponentRef Id="MainExecutable" />
|
||||
<ComponentRef Id="ConfigFiles" />
|
||||
<ComponentRef Id="SDL" />
|
||||
<ComponentRef Id="MINGWM" />
|
||||
</Feature>
|
||||
</Product>
|
||||
</Wix>
|
32
src/Makefile.am
Normal file
32
src/Makefile.am
Normal file
|
@ -0,0 +1,32 @@
|
|||
METASOURCES=AUTO
|
||||
|
||||
|
||||
|
||||
bin_PROGRAMS=epple2
|
||||
|
||||
AM_CPPFLAGS=$(all_includes)
|
||||
epple2_LDFLAGS=$(all_libraries)
|
||||
|
||||
epple2_CPPFLAGS = $(AM_CPPFLAGS) -DETCDIR=\"$(sysconfdir)\"
|
||||
|
||||
epple2_SOURCES = a2colorsobserved.cpp addressbus.cpp analogtv.cpp apple2.cpp \
|
||||
applentsc.cpp card.cpp cassette.cpp clipboardhandler.cpp clockcard.cpp \
|
||||
configep2.cpp cpu.cpp diskbytes.cpp diskcontroller.cpp drive.cpp \
|
||||
emptyslot.cpp emulator.cpp firmwarecard.cpp gui.cpp hypermode.cpp \
|
||||
keyboard.cpp keyboardbuffermode.cpp languagecard.cpp lowpass_1_5_mhz.cpp \
|
||||
lowpass_3_58_mhz.cpp main.cpp memory.cpp paddlebuttonstates.cpp \
|
||||
paddles.cpp picturegenerator.cpp powerupreset.cpp raminitializer.cpp \
|
||||
screenimage.cpp slots.cpp speakerclicker.cpp standardin.cpp \
|
||||
standardinproducer.cpp standardout.cpp steppermotor.cpp textcharacters.cpp \
|
||||
timable.cpp video.cpp videoaddressing.cpp videomode.cpp \
|
||||
videostaticgenerator.cpp SDL_win32_main.c
|
||||
|
||||
noinst_HEADERS = a2colorsobserved.h addressbus.h analogtv.h apple2.h applentsc.h \
|
||||
card.h cassette.h clipboardhandler.h clockcard.h configep2.h cpu.h diskbytes.h \
|
||||
diskcontroller.h drive.h e2const.h emptyslot.h emulator.h firmwarecard.h font3x5.h gui.h \
|
||||
hypermode.h keyboardbuffermode.h keyboard.h languagecard.h lowpass_1_5_mhz.h \
|
||||
lowpass_3_58_mhz.h memory.h paddlebuttonstates.h paddles.h picturegenerator.h \
|
||||
powerupreset.h raminitializer.h screenimage.h slots.h speakerclicker.h \
|
||||
standardin.h standardinproducer.h standardout.h steppermotor.h \
|
||||
textcharacterimages.h textcharacters.h timable.h util.h \
|
||||
videoaddressing.h video.h videomode.h videostaticgenerator.h
|
392
src/SDL_win32_main.c
Normal file
392
src/SDL_win32_main.c
Normal file
|
@ -0,0 +1,392 @@
|
|||
/*
|
||||
SDL_main.c, placed in the public domain by Sam Lantinga 4/13/98
|
||||
|
||||
The WinMain function -- calls your program's main() function
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
// Chris Mosher added this:
|
||||
#define NO_STDIO_REDIRECT
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
# define DIR_SEPERATOR TEXT("\\")
|
||||
# undef _getcwd
|
||||
# define _getcwd(str,len) wcscpy(str,TEXT(""))
|
||||
# define setbuf(f,b)
|
||||
# define setvbuf(w,x,y,z)
|
||||
# define fopen _wfopen
|
||||
# define freopen _wfreopen
|
||||
# define remove(x) DeleteFile(x)
|
||||
#else
|
||||
# define DIR_SEPERATOR TEXT("/")
|
||||
# include <direct.h>
|
||||
#endif
|
||||
|
||||
/* Include the SDL main definition header */
|
||||
#include "SDL/SDL.h"
|
||||
#include "SDL/SDL_main.h"
|
||||
|
||||
#ifdef main
|
||||
# ifndef _WIN32_WCE_EMULATION
|
||||
# undef main
|
||||
# endif /* _WIN32_WCE_EMULATION */
|
||||
#endif /* main */
|
||||
|
||||
/* The standard output files */
|
||||
#define STDOUT_FILE TEXT("stdout.txt")
|
||||
#define STDERR_FILE TEXT("stderr.txt")
|
||||
|
||||
#ifndef NO_STDIO_REDIRECT
|
||||
# ifdef _WIN32_WCE
|
||||
static wchar_t stdoutPath[MAX_PATH];
|
||||
static wchar_t stderrPath[MAX_PATH];
|
||||
# else
|
||||
static char stdoutPath[MAX_PATH];
|
||||
static char stderrPath[MAX_PATH];
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32_WCE) && _WIN32_WCE < 300
|
||||
/* seems to be undefined in Win CE although in online help */
|
||||
#define isspace(a) (((CHAR)a == ' ') || ((CHAR)a == '\t'))
|
||||
#endif /* _WIN32_WCE < 300 */
|
||||
|
||||
static void UnEscapeQuotes( char *arg )
|
||||
{
|
||||
char *last = NULL;
|
||||
|
||||
while( *arg ) {
|
||||
if( *arg == '"' && *last == '\\' ) {
|
||||
char *c_curr = arg;
|
||||
char *c_last = last;
|
||||
|
||||
while( *c_curr ) {
|
||||
*c_last = *c_curr;
|
||||
c_last = c_curr;
|
||||
c_curr++;
|
||||
}
|
||||
*c_last = '\0';
|
||||
}
|
||||
last = arg;
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse a command line buffer into arguments */
|
||||
static int ParseCommandLine(char *cmdline, char **argv)
|
||||
{
|
||||
char *bufp;
|
||||
char *lastp = NULL;
|
||||
int argc, last_argc;
|
||||
|
||||
argc = last_argc = 0;
|
||||
for ( bufp = cmdline; *bufp; ) {
|
||||
/* Skip leading whitespace */
|
||||
while ( isspace(*bufp) ) {
|
||||
++bufp;
|
||||
}
|
||||
/* Skip over argument */
|
||||
if ( *bufp == '"' ) {
|
||||
++bufp;
|
||||
if ( *bufp ) {
|
||||
if ( argv ) {
|
||||
argv[argc] = bufp;
|
||||
}
|
||||
++argc;
|
||||
}
|
||||
/* Skip over word */
|
||||
while ( *bufp && ( *bufp != '"' || *lastp == '\\' ) ) {
|
||||
lastp = bufp;
|
||||
++bufp;
|
||||
}
|
||||
} else {
|
||||
if ( *bufp ) {
|
||||
if ( argv ) {
|
||||
argv[argc] = bufp;
|
||||
}
|
||||
++argc;
|
||||
}
|
||||
/* Skip over word */
|
||||
while ( *bufp && ! isspace(*bufp) ) {
|
||||
++bufp;
|
||||
}
|
||||
}
|
||||
if ( *bufp ) {
|
||||
if ( argv ) {
|
||||
*bufp = '\0';
|
||||
}
|
||||
++bufp;
|
||||
}
|
||||
|
||||
/* Strip out \ from \" sequences */
|
||||
if( argv && last_argc != argc ) {
|
||||
UnEscapeQuotes( argv[last_argc] );
|
||||
}
|
||||
last_argc = argc;
|
||||
}
|
||||
if ( argv ) {
|
||||
argv[argc] = NULL;
|
||||
}
|
||||
return(argc);
|
||||
}
|
||||
|
||||
/* Show an error message */
|
||||
static void ShowError(const char *title, const char *message)
|
||||
{
|
||||
/* If USE_MESSAGEBOX is defined, you need to link with user32.lib */
|
||||
#ifdef USE_MESSAGEBOX
|
||||
MessageBox(NULL, message, title, MB_ICONEXCLAMATION|MB_OK);
|
||||
#else
|
||||
fprintf(stderr, "%s: %s\n", title, message);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Pop up an out of memory message, returns to Windows */
|
||||
static BOOL OutOfMemory(void)
|
||||
{
|
||||
ShowError("Fatal Error", "Out of memory - aborting");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* SDL_Quit() shouldn't be used with atexit() directly because
|
||||
calling conventions may differ... */
|
||||
static void cleanup(void)
|
||||
{
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
/* Remove the output files if there was no output written */
|
||||
static void cleanup_output(void)
|
||||
{
|
||||
#ifndef NO_STDIO_REDIRECT
|
||||
FILE *file;
|
||||
int empty;
|
||||
#endif
|
||||
|
||||
/* Flush the output in case anything is queued */
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
|
||||
#ifndef NO_STDIO_REDIRECT
|
||||
/* See if the files have any output in them */
|
||||
if ( stdoutPath[0] ) {
|
||||
file = fopen(stdoutPath, TEXT("rb"));
|
||||
if ( file ) {
|
||||
empty = (fgetc(file) == EOF) ? 1 : 0;
|
||||
fclose(file);
|
||||
if ( empty ) {
|
||||
remove(stdoutPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( stderrPath[0] ) {
|
||||
file = fopen(stderrPath, TEXT("rb"));
|
||||
if ( file ) {
|
||||
empty = (fgetc(file) == EOF) ? 1 : 0;
|
||||
fclose(file);
|
||||
if ( empty ) {
|
||||
remove(stderrPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_WIN32_WCE)
|
||||
/* The VC++ compiler needs main defined */
|
||||
#define console_main main
|
||||
#endif
|
||||
|
||||
/* This is where execution begins [console apps] */
|
||||
int console_main(int argc, char *argv[])
|
||||
{
|
||||
size_t n;
|
||||
char *bufp, *appname;
|
||||
int status;
|
||||
|
||||
/* Get the class name from argv[0] */
|
||||
appname = argv[0];
|
||||
if ( (bufp=SDL_strrchr(argv[0], '\\')) != NULL ) {
|
||||
appname = bufp+1;
|
||||
} else
|
||||
if ( (bufp=SDL_strrchr(argv[0], '/')) != NULL ) {
|
||||
appname = bufp+1;
|
||||
}
|
||||
|
||||
if ( (bufp=SDL_strrchr(appname, '.')) == NULL )
|
||||
n = SDL_strlen(appname);
|
||||
else
|
||||
n = (bufp-appname);
|
||||
|
||||
bufp = SDL_stack_alloc(char, n+1);
|
||||
if ( bufp == NULL ) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
SDL_strlcpy(bufp, appname, n+1);
|
||||
appname = bufp;
|
||||
|
||||
/* Load SDL dynamic link library */
|
||||
if ( SDL_Init(SDL_INIT_NOPARACHUTE) < 0 ) {
|
||||
ShowError("WinMain() error", SDL_GetError());
|
||||
return(FALSE);
|
||||
}
|
||||
atexit(cleanup_output);
|
||||
atexit(cleanup);
|
||||
|
||||
/* Sam:
|
||||
We still need to pass in the application handle so that
|
||||
DirectInput will initialize properly when SDL_RegisterApp()
|
||||
is called later in the video initialization.
|
||||
*/
|
||||
SDL_SetModuleHandle(GetModuleHandle(NULL));
|
||||
|
||||
/* Run the application main() code */
|
||||
status = SDL_main(argc, argv);
|
||||
|
||||
/* Exit cleanly, calling atexit() functions */
|
||||
exit(status);
|
||||
|
||||
/* Hush little compiler, don't you cry... */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is where execution begins [windowed apps] */
|
||||
#ifdef _WIN32_WCE
|
||||
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int sw)
|
||||
#else
|
||||
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
|
||||
#endif
|
||||
{
|
||||
HINSTANCE handle;
|
||||
char **argv;
|
||||
int argc;
|
||||
char *cmdline;
|
||||
#ifdef _WIN32_WCE
|
||||
wchar_t *bufp;
|
||||
int nLen;
|
||||
#else
|
||||
char *bufp;
|
||||
size_t nLen;
|
||||
#endif
|
||||
#ifndef NO_STDIO_REDIRECT
|
||||
DWORD pathlen;
|
||||
#ifdef _WIN32_WCE
|
||||
wchar_t path[MAX_PATH];
|
||||
#else
|
||||
char path[MAX_PATH];
|
||||
#endif
|
||||
FILE *newfp;
|
||||
#endif
|
||||
|
||||
/* Start up DDHELP.EXE before opening any files, so DDHELP doesn't
|
||||
keep them open. This is a hack.. hopefully it will be fixed
|
||||
someday. DDHELP.EXE starts up the first time DDRAW.DLL is loaded.
|
||||
*/
|
||||
handle = LoadLibrary(TEXT("DDRAW.DLL"));
|
||||
if ( handle != NULL ) {
|
||||
FreeLibrary(handle);
|
||||
}
|
||||
|
||||
#ifndef NO_STDIO_REDIRECT
|
||||
pathlen = GetModuleFileName(NULL, path, SDL_arraysize(path));
|
||||
while ( pathlen > 0 && path[pathlen] != '\\' ) {
|
||||
--pathlen;
|
||||
}
|
||||
path[pathlen] = '\0';
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
wcsncpy( stdoutPath, path, SDL_arraysize(stdoutPath) );
|
||||
wcsncat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) );
|
||||
#else
|
||||
SDL_strlcpy( stdoutPath, path, SDL_arraysize(stdoutPath) );
|
||||
SDL_strlcat( stdoutPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) );
|
||||
#endif
|
||||
|
||||
/* Redirect standard input and standard output */
|
||||
newfp = freopen(stdoutPath, TEXT("w"), stdout);
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
if ( newfp == NULL ) { /* This happens on NT */
|
||||
#if !defined(stdout)
|
||||
stdout = fopen(stdoutPath, TEXT("w"));
|
||||
#else
|
||||
newfp = fopen(stdoutPath, TEXT("w"));
|
||||
if ( newfp ) {
|
||||
*stdout = *newfp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* _WIN32_WCE */
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
wcsncpy( stderrPath, path, SDL_arraysize(stdoutPath) );
|
||||
wcsncat( stderrPath, DIR_SEPERATOR STDOUT_FILE, SDL_arraysize(stdoutPath) );
|
||||
#else
|
||||
SDL_strlcpy( stderrPath, path, SDL_arraysize(stderrPath) );
|
||||
SDL_strlcat( stderrPath, DIR_SEPERATOR STDERR_FILE, SDL_arraysize(stderrPath) );
|
||||
#endif
|
||||
|
||||
newfp = freopen(stderrPath, TEXT("w"), stderr);
|
||||
#ifndef _WIN32_WCE
|
||||
if ( newfp == NULL ) { /* This happens on NT */
|
||||
#if !defined(stderr)
|
||||
stderr = fopen(stderrPath, TEXT("w"));
|
||||
#else
|
||||
newfp = fopen(stderrPath, TEXT("w"));
|
||||
if ( newfp ) {
|
||||
*stderr = *newfp;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif /* _WIN32_WCE */
|
||||
|
||||
setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* Line buffered */
|
||||
setbuf(stderr, NULL); /* No buffering */
|
||||
#endif /* !NO_STDIO_REDIRECT */
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
nLen = wcslen(szCmdLine)+128+1;
|
||||
bufp = SDL_stack_alloc(wchar_t, nLen*2);
|
||||
wcscpy (bufp, TEXT("\""));
|
||||
GetModuleFileName(NULL, bufp+1, 128-3);
|
||||
wcscpy (bufp+wcslen(bufp), TEXT("\" "));
|
||||
wcsncpy(bufp+wcslen(bufp), szCmdLine,nLen-wcslen(bufp));
|
||||
nLen = wcslen(bufp)+1;
|
||||
cmdline = SDL_stack_alloc(char, nLen);
|
||||
if ( cmdline == NULL ) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL);
|
||||
#else
|
||||
/* Grab the command line */
|
||||
bufp = GetCommandLine();
|
||||
nLen = SDL_strlen(bufp)+1;
|
||||
cmdline = SDL_stack_alloc(char, nLen);
|
||||
if ( cmdline == NULL ) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
SDL_strlcpy(cmdline, bufp, nLen);
|
||||
#endif
|
||||
|
||||
/* Parse it into argv and argc */
|
||||
argc = ParseCommandLine(cmdline, NULL);
|
||||
argv = SDL_stack_alloc(char*, argc+1);
|
||||
if ( argv == NULL ) {
|
||||
return OutOfMemory();
|
||||
}
|
||||
ParseCommandLine(cmdline, argv);
|
||||
|
||||
/* Run the main program (after a little SDL initialization) */
|
||||
console_main(argc, argv);
|
||||
|
||||
/* Hush little compiler, don't you cry... */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
93
src/a2colorsobserved.cpp
Normal file
93
src/a2colorsobserved.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "a2colorsobserved.h"
|
||||
|
||||
static unsigned char tobyt(float x)
|
||||
{
|
||||
x *= 256.0f;
|
||||
x += 0.0001f;
|
||||
int xi = (int)x;
|
||||
|
||||
if (xi > 255)
|
||||
xi = 255;
|
||||
|
||||
return (unsigned char)xi;
|
||||
}
|
||||
|
||||
// 0 <= h < 360 degrees; 0 <= s,v <= 1
|
||||
static int HSVtoRGB(const int h, const float s, const float v)
|
||||
{
|
||||
const float f = (h % 60) / 60.0;
|
||||
|
||||
float r, g, b;
|
||||
switch (h / 60)
|
||||
{
|
||||
case 0:
|
||||
r = v;
|
||||
g = v * (1 - s * (1 - f));
|
||||
b = v * (1 - s);
|
||||
break;
|
||||
case 1:
|
||||
r = v * (1 - s * f);
|
||||
g = v;
|
||||
b = v * (1 - s);
|
||||
break;
|
||||
case 2:
|
||||
r = v * (1 - s);
|
||||
g = v;
|
||||
b = v * (1 - s * (1 - f));
|
||||
break;
|
||||
case 3:
|
||||
r = v * (1 - s);
|
||||
g = v * (1 - s * f);
|
||||
b = v;
|
||||
break;
|
||||
case 4:
|
||||
r = v * (1 - s * (1 - f));
|
||||
g = v * (1 - s);
|
||||
b = v;
|
||||
break;
|
||||
case 5:
|
||||
r = v;
|
||||
g = v * (1 - s);
|
||||
b = v * (1 - s * f);
|
||||
break;
|
||||
}
|
||||
|
||||
return (tobyt(r) << 16) | (tobyt(g) << 8) | (tobyt(b));
|
||||
}
|
||||
|
||||
A2ColorsObserved::A2ColorsObserved():
|
||||
COLOR(0x10)
|
||||
{
|
||||
// const unsigned int clr[] = { 0x1, 0xB, 0x3, 0x2, 0x7, 0x6, 0x4, 0xE, 0xC, 0x8, 0xD, 0x9, 0x5, 0xA, 0xF, 0x0 };
|
||||
const unsigned int map[] = { 0xF, 0x0, 0x3, 0x2, 0x6, 0xC, 0x5, 0x4, 0x9, 0xB, 0xD, 0x1, 0x8, 0xA, 0x7, 0xE };
|
||||
const unsigned int hue[] = { 342, 342, 277, 233, 233, 213, 160, 160, 75, 33, 52, 24, 0, 0, 0, 0 };
|
||||
const unsigned int sat[] = { 100, 50, 75, 100, 50, 100, 100, 100, 100, 100, 100, 100, 0, 0, 0, 0 };
|
||||
const unsigned int val[] = { 67, 100, 100, 75, 100, 100, 33, 100, 75, 50, 100, 100, 50, 50, 100, 0 };
|
||||
|
||||
for (unsigned int i(0); i < COLOR.size(); ++i)
|
||||
{
|
||||
COLOR[i] = HSVtoRGB(hue[map[i]],sat[map[i]]/100.0f,val[map[i]]/100.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
A2ColorsObserved::~A2ColorsObserved()
|
||||
{
|
||||
}
|
55
src/a2colorsobserved.h
Normal file
55
src/a2colorsobserved.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef A2COLORSOBSERVED_H
|
||||
#define A2COLORSOBSERVED_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
class A2ColorsObserved
|
||||
{
|
||||
private:
|
||||
std::vector<unsigned int> COLOR;
|
||||
|
||||
public:
|
||||
A2ColorsObserved();
|
||||
~A2ColorsObserved();
|
||||
|
||||
const std::vector<unsigned int>& c() { return this->COLOR; }
|
||||
|
||||
enum
|
||||
{
|
||||
BLACK,
|
||||
DARK_MAGENTA,
|
||||
DARK_BLUE,
|
||||
HIRES_VIOLET,
|
||||
DARK_BLUE_GREEN,
|
||||
GREY,
|
||||
HIRES_BLUE,
|
||||
LIGHT_BLUE,
|
||||
DARK_BROWN,
|
||||
HIRES_ORANGE,
|
||||
GREY_ALTERNATE,
|
||||
LIGHT_MAGENTA,
|
||||
HIRES_GREEN,
|
||||
LIGHT_BROWN,
|
||||
LIGHT_BLUE_GREEN,
|
||||
WHITE,
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
229
src/addressbus.cpp
Normal file
229
src/addressbus.cpp
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "addressbus.h"
|
||||
#include "memory.h"
|
||||
#include "keyboard.h"
|
||||
#include "videomode.h"
|
||||
#include "paddles.h"
|
||||
#include "paddlebuttonstates.h"
|
||||
#include "speakerclicker.h"
|
||||
#include "cassette.h"
|
||||
#include "slots.h"
|
||||
|
||||
AddressBus::AddressBus(Memory& ram, Memory& rom, Keyboard& kbd, VideoMode& vid, Paddles& paddles, PaddleButtonStates& paddleButtonStates, SpeakerClicker& speaker, Cassette& cassette, Slots& slts):
|
||||
ram(ram), rom(rom), kbd(kbd), vid(vid), paddles(paddles), paddleButtonStates(paddleButtonStates), speaker(speaker), cassette(cassette), slts(slts)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AddressBus::~AddressBus()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned char AddressBus::read(const unsigned short address)
|
||||
{
|
||||
if ((address >> 14 == 3)) // >= $C000
|
||||
{
|
||||
if ((address >> 12) == 0xC)
|
||||
{
|
||||
// 11007sssxxxxxxxx
|
||||
const bool seventh = address & 0x0800;
|
||||
const int slot = (address >> 8) & 7;
|
||||
if (seventh)
|
||||
{
|
||||
this->data = this->slts.readSeventhRom(address & 0x07FF, this->data);
|
||||
}
|
||||
else if (slot == 0)
|
||||
{
|
||||
this->data = readSwitch(address & 0x00FF);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->data = this->slts.readRom(slot,address & 0x00FF, this->data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->data = this->slts.ioBankRom(address - 0xD000,this->data,false);
|
||||
if (!this->slts.inhibitMotherboardRom())
|
||||
{
|
||||
this->data = this->rom.read(address - 0xD000);
|
||||
}
|
||||
}
|
||||
}
|
||||
else // < $C000
|
||||
{
|
||||
this->data = this->ram.read(address);
|
||||
}
|
||||
|
||||
return this->data;
|
||||
}
|
||||
|
||||
void AddressBus::write(const unsigned short address, const unsigned char d)
|
||||
{
|
||||
this->data = d;
|
||||
|
||||
if ((address >> 14 == 3)) // >= $C000
|
||||
{
|
||||
if ((address >> 12) == 0xC)
|
||||
{
|
||||
// 11007sssxxxxxxxx
|
||||
const bool seventh = address & 0x0800;
|
||||
const int slot = (address >> 8) & 7;
|
||||
if (!seventh && slot == 0)
|
||||
{
|
||||
writeSwitch(address & 0x00FF);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->slts.ioBankRom(address - 0xD000,this->data,true);
|
||||
}
|
||||
}
|
||||
else // < $C000
|
||||
{
|
||||
this->ram.write(address,this->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned char AddressBus::readSwitch(unsigned short address)
|
||||
{
|
||||
if (address < 0x80)
|
||||
{
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
if (islot == 0x0)
|
||||
{
|
||||
this->data = this->kbd.get();
|
||||
}
|
||||
else if (islot == 0x1)
|
||||
{
|
||||
this->kbd.clear();
|
||||
}
|
||||
else if (islot == 0x2)
|
||||
{
|
||||
this->cassette.output();
|
||||
}
|
||||
else if (islot == 0x3)
|
||||
{
|
||||
this->speaker.click();
|
||||
}
|
||||
else if (islot == 0x4)
|
||||
{
|
||||
// ignore utility strobe
|
||||
}
|
||||
else if (islot == 0x5)
|
||||
{
|
||||
if (iswch < 0x8)
|
||||
{
|
||||
this->data = this->vid.io(address,this->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ignore annunciator outputs
|
||||
}
|
||||
}
|
||||
else if (islot == 0x6)
|
||||
{
|
||||
int sw2 = iswch & 0x7;
|
||||
if (sw2 == 0)
|
||||
{
|
||||
setD7(this->cassette.input());
|
||||
}
|
||||
else if (sw2 < 4)
|
||||
{
|
||||
setD7(this->paddleButtonStates.isDown(sw2-1));
|
||||
}
|
||||
else
|
||||
{
|
||||
sw2 &= 3;
|
||||
setD7(!this->paddles.isTimedOut(sw2));
|
||||
}
|
||||
}
|
||||
else if (islot == 0x7)
|
||||
{
|
||||
this->paddles.startTimers();
|
||||
setD7(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// slot I/O switches
|
||||
address &= 0x7F;
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
this->data = this->slts.io(islot,iswch,this->data,false);
|
||||
}
|
||||
|
||||
return this->data;
|
||||
}
|
||||
|
||||
void AddressBus::setD7(const bool set)
|
||||
{
|
||||
if (set)
|
||||
{
|
||||
this->data |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->data &= 0x7F;
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBus::writeSwitch(unsigned short address)
|
||||
{
|
||||
if (address < 0x80)
|
||||
{
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
|
||||
if (islot == 0x1)
|
||||
{
|
||||
this->kbd.clear();
|
||||
}
|
||||
else if (islot == 0x5)
|
||||
{
|
||||
if (iswch < 0x8)
|
||||
this->vid.io(address,this->data);
|
||||
}
|
||||
// ignore all other switch writes
|
||||
}
|
||||
else
|
||||
{
|
||||
// slot I/O switches
|
||||
address &= 0x7F;
|
||||
const int islot = (address >> 4) & 0xF;
|
||||
const int iswch = (address & 0xF);
|
||||
this->slts.io(islot,iswch,this->data,true);
|
||||
}
|
||||
}
|
62
src/addressbus.h
Normal file
62
src/addressbus.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef ADDRESSBUS_H
|
||||
#define ADDRESSBUS_H
|
||||
|
||||
class Memory;
|
||||
class Keyboard;
|
||||
class VideoMode;
|
||||
class Paddles;
|
||||
class PaddleButtonStates;
|
||||
class SpeakerClicker;
|
||||
class Cassette;
|
||||
class Slots;
|
||||
|
||||
class AddressBus
|
||||
{
|
||||
private:
|
||||
Memory& ram;
|
||||
Memory& rom;
|
||||
Keyboard& kbd;
|
||||
VideoMode& vid;
|
||||
Paddles& paddles;
|
||||
PaddleButtonStates& paddleButtonStates;
|
||||
SpeakerClicker& speaker;
|
||||
Cassette& cassette;
|
||||
Slots& slts;
|
||||
|
||||
unsigned char data; // this emulates the (floating) data bus
|
||||
|
||||
public:
|
||||
AddressBus(Memory& ram, Memory& rom, Keyboard& kbd, VideoMode& vid, Paddles& paddles, PaddleButtonStates& paddleButtonStates, SpeakerClicker& speaker, Cassette& cassette, Slots& slts);
|
||||
~AddressBus();
|
||||
|
||||
unsigned char read(const unsigned short address);
|
||||
void write(const unsigned short address, const unsigned char d);
|
||||
unsigned char readSwitch(unsigned short address);
|
||||
void setD7(const bool set);
|
||||
void writeSwitch(unsigned short address);
|
||||
enum { MOTHERBOARD_RAM_BAS = 0x00000 } ;
|
||||
enum { MOTHERBOARD_RAM_LIM = 0x0C000 } ;
|
||||
enum { MOTHERBOARD_RAM_SIZ = MOTHERBOARD_RAM_LIM-MOTHERBOARD_RAM_BAS };
|
||||
enum { MOTHERBOARD_ROM_BAS = 0x0D000 } ;
|
||||
enum { MOTHERBOARD_ROM_LIM = 0x10000 } ;
|
||||
enum { MOTHERBOARD_ROM_SIZ = MOTHERBOARD_ROM_LIM-MOTHERBOARD_ROM_BAS } ;
|
||||
};
|
||||
|
||||
#endif
|
611
src/analogtv.cpp
Normal file
611
src/analogtv.cpp
Normal file
|
@ -0,0 +1,611 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
This class was highly inspired by Trevor Blackwell's Analog TV
|
||||
module ("hack") of the XScreenSaver collection, therefore, portions
|
||||
Copyright (C) 2003, 2004, by Trevor Blackwell <tlb@tlb.org>
|
||||
(Thanks, Trevor!)
|
||||
For this class, I removed the "interference" type processing, and
|
||||
just took the raw color processing functionality. See the drawTVOld
|
||||
method definition in this file for the analog TV processing.
|
||||
I also added processing for the other ("new") TV, and various monitors.
|
||||
*/
|
||||
#include "analogtv.h"
|
||||
#include "screenimage.h"
|
||||
#include "applentsc.h"
|
||||
#include "lowpass_3_58_mhz.h"
|
||||
#include "lowpass_1_5_mhz.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
|
||||
AnalogTV::AnalogTV(ScreenImage& image):
|
||||
image(image),
|
||||
on(false),
|
||||
noise(false),
|
||||
bleed_down(false)
|
||||
{
|
||||
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_GREEN]);
|
||||
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_ORANGE]);
|
||||
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_VIOLET]);
|
||||
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_BLUE]);
|
||||
|
||||
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BROWN]);
|
||||
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_MAGENTA]);
|
||||
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BLUE]);
|
||||
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BLUE_GREEN]);
|
||||
|
||||
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BLUE_GREEN]);
|
||||
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BROWN]);
|
||||
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_MAGENTA]);
|
||||
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BLUE]);
|
||||
}
|
||||
|
||||
|
||||
AnalogTV::~AnalogTV()
|
||||
{
|
||||
}
|
||||
|
||||
void AnalogTV::powerOn(bool b)
|
||||
{
|
||||
this->on = b;
|
||||
this->image.notifyObservers();
|
||||
}
|
||||
|
||||
void AnalogTV::setType(DisplayType type)
|
||||
{
|
||||
this->type = type;
|
||||
}
|
||||
|
||||
void AnalogTV::cycleType()
|
||||
{
|
||||
this->type = (DisplayType)((((int)this->type)+1)%NUM_DISPLAY_TYPES);
|
||||
}
|
||||
|
||||
void AnalogTV::toggleBleedDown()
|
||||
{
|
||||
this->bleed_down = !this->bleed_down;
|
||||
this->image.blank();
|
||||
this->image.notifyObservers();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// void dump()
|
||||
// {
|
||||
// const int[] yiq = new int[AppleNTSC::H];
|
||||
// for (int row = 0; row < 192; ++row)
|
||||
// {
|
||||
// const CB cb = get_cb(row);
|
||||
// const IQ iq_factor = get_iq_factor(cb);
|
||||
// ntsc_to_yiq(row*AppleNTSC::H+350,AppleNTSC::H-2-350,iq_factor,yiq);
|
||||
// for (int col = 350; col < AppleNTSC::H-2; ++col)
|
||||
// {
|
||||
// const int sig = this->signal[row*AppleNTSC::H+col];
|
||||
// System.out.printf(" %+04d",sig);
|
||||
// const int yiqv = yiq[col-350];
|
||||
// int y = (yiqv&0xFF)-IQINTOFF;
|
||||
// int i = ((yiqv>>8)&0xFF)-IQINTOFF;
|
||||
// int q = ((yiqv>>16)&0xFF)-IQINTOFF;
|
||||
// System.out.printf("(%+04d,%+04d,%+04d)",y,i,q);
|
||||
//
|
||||
// const int rgb = yiq2rgb(yiqv);
|
||||
// const int r = (rgb >> 16) & 0xff;
|
||||
// const int g = (rgb >> 8) & 0xff;
|
||||
// const int b = (rgb ) & 0xff;
|
||||
// System.out.printf("[%06X:%03d,%03d,%03d]",rgb,r,g,b);
|
||||
// }
|
||||
// System.out.println();
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class IQ
|
||||
{
|
||||
public:
|
||||
double iq[4];
|
||||
IQ()
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
iq[i] = 0;
|
||||
}
|
||||
IQ(double aiq[])
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
iq[i] = aiq[i];
|
||||
}
|
||||
double get(int i) const { return this->iq[i]; }
|
||||
};
|
||||
|
||||
const IQ& AnalogTV::BLACK_AND_WHITE = IQ();
|
||||
|
||||
static const int CB_EXTRA(32);
|
||||
|
||||
class CB
|
||||
{
|
||||
public:
|
||||
std::vector<int> cb;
|
||||
|
||||
CB(const int acb[]):
|
||||
cb(AppleNTSC::CB_END-AppleNTSC::CB_START-CB_EXTRA)
|
||||
{
|
||||
for (std::vector<int>::size_type i(0); i < this->cb.size(); ++i)
|
||||
{
|
||||
this->cb[i] = acb[i];
|
||||
}
|
||||
}
|
||||
int get(const int i) const { return this->cb[i]; }
|
||||
int length() const { return this->cb.size(); }
|
||||
void getPhase(double phase[]) const
|
||||
{
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
phase[i & 3] = 0;
|
||||
}
|
||||
}
|
||||
{
|
||||
for (int i = 0; i < length(); ++i)
|
||||
{
|
||||
phase[i & 3] += this->cb[i];
|
||||
}
|
||||
}
|
||||
double tot = 0;
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
tot += phase[i] * phase[i];
|
||||
}
|
||||
}
|
||||
const double tsrt = sqrt(tot);
|
||||
if (tsrt < .0001)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
phase[i] /= tsrt;
|
||||
}
|
||||
}
|
||||
bool isColor() const
|
||||
{
|
||||
int tot = 0;
|
||||
for (int i = 0; i < length(); ++i)
|
||||
{
|
||||
const int icb = this->cb[i];
|
||||
if (icb < 0)
|
||||
tot += -icb;
|
||||
else
|
||||
tot += icb;
|
||||
}
|
||||
return 220 < tot && tot < 260;
|
||||
}
|
||||
|
||||
bool operator<(const CB& that) const
|
||||
{
|
||||
return this->cb < that.cb;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void AnalogTV::drawCurrent()
|
||||
{
|
||||
if (this->on)
|
||||
{
|
||||
switch (this->type)
|
||||
{
|
||||
case MONITOR_COLOR: drawMonitorColor(); break;
|
||||
case MONITOR_WHITE: drawMonitorWhite(); break;
|
||||
case MONITOR_GREEN: drawMonitorGreen(); break;
|
||||
case MONITOR_ORANGE: drawMonitorOrange(); break;
|
||||
case TV_OLD_COLOR: drawTVOld(); break;
|
||||
case TV_OLD_BW: drawTVOld(); break;
|
||||
case TV_NEW_COLOR: drawTVNew(); break;
|
||||
case TV_NEW_BW: drawTVNew(); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
drawBlank();
|
||||
}
|
||||
this->image.notifyObservers();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const int D_IP(AppleNTSC::H-2-350);
|
||||
|
||||
void AnalogTV::drawMonitorColor()
|
||||
{
|
||||
unsigned int *rgb = new unsigned int[AppleNTSC::H];
|
||||
int ip = 0;
|
||||
for (int row = 0; row < 192; ++row)
|
||||
{
|
||||
const CB cb = get_cb(row);
|
||||
const bool removeColor = (this->type == TV_NEW_BW || !cb.isColor());
|
||||
ntsc_to_rgb_monitor(row*AppleNTSC::H+350,AppleNTSC::H-350,rgb);
|
||||
for (int col = 350; col < AppleNTSC::H-2; ++col)
|
||||
{
|
||||
int rgbv = rgb[col-350];
|
||||
if (removeColor && rgbv != 0)
|
||||
{
|
||||
rgbv = 0xFFFFFF;
|
||||
}
|
||||
this->image.setElem(ip,rgbv);
|
||||
if (bleed_down)
|
||||
this->image.setElem(ip+D_IP,rgbv); // display same pixel on next row
|
||||
++ip;
|
||||
}
|
||||
ip += D_IP;
|
||||
}
|
||||
delete [] rgb;
|
||||
}
|
||||
|
||||
void AnalogTV::drawMonitorWhite()
|
||||
{
|
||||
drawMonitorMonochrome(colors.c()[A2ColorsObserved::WHITE]);
|
||||
}
|
||||
|
||||
void AnalogTV::drawMonitorGreen()
|
||||
{
|
||||
drawMonitorMonochrome(colors.c()[A2ColorsObserved::HIRES_GREEN]);
|
||||
}
|
||||
|
||||
void AnalogTV::drawMonitorOrange()
|
||||
{
|
||||
drawMonitorMonochrome(colors.c()[A2ColorsObserved::HIRES_ORANGE]);
|
||||
}
|
||||
|
||||
void AnalogTV::drawMonitorMonochrome(const unsigned int color)
|
||||
{
|
||||
int ip = 0;
|
||||
for (int row = 0; row < 192; ++row)
|
||||
{
|
||||
for (int col = 350; col < AppleNTSC::H-2; ++col)
|
||||
{
|
||||
const int is = row*AppleNTSC::H+col;
|
||||
const unsigned int rgb = this->signal[is] > 50 ? color : 0;
|
||||
this->image.setElem(ip,rgb);
|
||||
if (bleed_down)
|
||||
this->image.setElem(ip+D_IP,rgb);
|
||||
++ip;
|
||||
}
|
||||
ip += D_IP;
|
||||
}
|
||||
}
|
||||
|
||||
void AnalogTV::drawTVOld()
|
||||
{
|
||||
int *yiq = new int[AppleNTSC::H];
|
||||
int ip = 0;
|
||||
for (int row = 0; row < 192; ++row)
|
||||
{
|
||||
IQ iq_factor;
|
||||
if (this->type == TV_OLD_COLOR)
|
||||
{
|
||||
const CB cb = get_cb(row);
|
||||
iq_factor = get_iq_factor(cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
iq_factor = BLACK_AND_WHITE;
|
||||
}
|
||||
ntsc_to_yiq(row*AppleNTSC::H+350,AppleNTSC::H-350,iq_factor,yiq);
|
||||
for (int col = 350; col < AppleNTSC::H-2; ++col)
|
||||
{
|
||||
const int rgb = yiq2rgb(yiq[col-348]); // shift display left 1 pixel
|
||||
this->image.setElem(ip,rgb);
|
||||
if (bleed_down)
|
||||
this->image.setElem(ip+D_IP,rgb);
|
||||
++ip;
|
||||
}
|
||||
ip += D_IP;
|
||||
}
|
||||
delete [] yiq;
|
||||
}
|
||||
|
||||
void AnalogTV::drawTVNew()
|
||||
{
|
||||
unsigned int *rgb = new unsigned int[AppleNTSC::H];
|
||||
int ip = 0;
|
||||
for (int row = 0; row < 192; ++row)
|
||||
{
|
||||
const CB cb = get_cb(row);
|
||||
const bool removeColor = (this->type == TV_NEW_BW || !cb.isColor());
|
||||
ntsc_to_rgb_newtv(row*AppleNTSC::H+350,AppleNTSC::H-350,rgb);
|
||||
for (int col = 350; col < AppleNTSC::H-2; ++col)
|
||||
{
|
||||
int rgbv = rgb[col-350];
|
||||
if (removeColor)
|
||||
{
|
||||
rgbv = color2bw(rgbv);
|
||||
}
|
||||
this->image.setElem(ip,rgbv);
|
||||
if (bleed_down)
|
||||
this->image.setElem(ip+D_IP,rgbv);
|
||||
++ip;
|
||||
}
|
||||
ip += D_IP;
|
||||
}
|
||||
delete [] rgb;
|
||||
}
|
||||
|
||||
void AnalogTV::drawBlank()
|
||||
{
|
||||
this->image.blank();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void AnalogTV::ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned int rgb[])
|
||||
{
|
||||
int s0, s1, se;
|
||||
s0 = s1 = isignal;
|
||||
se = isignal+siglen;
|
||||
while (s1 < se)
|
||||
{
|
||||
// no signal (black)
|
||||
while (this->signal[s0] < 50 && s0<se) { rgb[s0-isignal] = 0; ++s0; }
|
||||
|
||||
// signal (white, grey, or color)
|
||||
s1 = s0;
|
||||
while (this->signal[s1] > 50 && s1<se) { ++s1; }
|
||||
const int slen = s1-s0;
|
||||
unsigned int c = 0;
|
||||
if (slen >= 4)
|
||||
{
|
||||
c = 0xFFFFFF;
|
||||
}
|
||||
else if (slen == 1)
|
||||
{
|
||||
if (this->signal[s0-2] > 50 && this->signal[s0+2] > 50)
|
||||
c = 0xFFFFFF;
|
||||
else
|
||||
c = loresdarkcolor[s0 % 4];
|
||||
}
|
||||
else if (slen == 2)
|
||||
{
|
||||
c = hirescolor[s0 % 4];
|
||||
}
|
||||
else if (slen == 3)
|
||||
{
|
||||
c = loreslightcolor[s0 % 4];
|
||||
}
|
||||
else
|
||||
{
|
||||
++s1;
|
||||
}
|
||||
|
||||
for (int i = s0; i < s1; ++i)
|
||||
rgb[i-isignal] = c;
|
||||
s0 = s1;
|
||||
}
|
||||
}
|
||||
|
||||
void AnalogTV::ntsc_to_rgb_newtv(const int isignal, const int siglen, unsigned int rgb[])
|
||||
{
|
||||
int sp, s0, s1, se;
|
||||
sp = s0 = s1 = isignal;
|
||||
se = isignal+siglen;
|
||||
unsigned int c = 0;
|
||||
while (s1 < se)
|
||||
{
|
||||
// no signal; black...
|
||||
sp = s0;
|
||||
while (this->signal[s0] < 50 && s0<se) { rgb[s0-isignal] = 0; ++s0; }
|
||||
// unless it's too short, then color it (but not white)
|
||||
if (c != 0xFFFFFF)
|
||||
{
|
||||
if (s0-sp < 4)
|
||||
{
|
||||
for (int i = sp; i < s0; ++i)
|
||||
rgb[i-isignal] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
rgb[sp-isignal] = c;
|
||||
}
|
||||
}
|
||||
|
||||
// signal (white, grey, or color)
|
||||
s1 = s0;
|
||||
while (this->signal[s1] > 50 && s1<se) { ++s1; }
|
||||
const int slen = s1-s0;
|
||||
if (slen >= 4)
|
||||
{
|
||||
c = 0xFFFFFF;
|
||||
}
|
||||
else if (slen == 1)
|
||||
{
|
||||
if (this->signal[s0-2] > 50 && this->signal[s0+2] > 50)
|
||||
c = 0x808080;
|
||||
else
|
||||
c = loresdarkcolor[s0 % 4];
|
||||
}
|
||||
else if (slen == 2)
|
||||
{
|
||||
c = hirescolor[s0 % 4];
|
||||
}
|
||||
else if (slen == 3)
|
||||
{
|
||||
c = loreslightcolor[s0 % 4];
|
||||
}
|
||||
else
|
||||
{
|
||||
++s1;
|
||||
}
|
||||
|
||||
for (int i = s0; i < s1; ++i)
|
||||
rgb[i-isignal] = c;
|
||||
s0 = s1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int *AnalogTV::rcb = new int[AppleNTSC::CB_END-AppleNTSC::CB_START-CB_EXTRA];
|
||||
CB AnalogTV::get_cb(int lineno)
|
||||
{
|
||||
const int isp = lineno * AppleNTSC::H;
|
||||
for (int i = AppleNTSC::CB_START + CB_EXTRA/2; i < AppleNTSC::CB_END - CB_EXTRA/2; ++i)
|
||||
{
|
||||
this->rcb[i-(AppleNTSC::CB_START + CB_EXTRA/2)] = this->signal[isp + i];
|
||||
}
|
||||
return CB(this->rcb);
|
||||
}
|
||||
|
||||
|
||||
std::map<CB,IQ> cacheCB;
|
||||
|
||||
const double AnalogTV::IQ_OFFSET_DEGREES = 33;
|
||||
const double AnalogTV::IQ_OFFSET_RADIANS = AnalogTV::IQ_OFFSET_DEGREES * 3.1415927 / 180;
|
||||
const double AnalogTV::TINT_I = -cos(AnalogTV::IQ_OFFSET_RADIANS);
|
||||
const double AnalogTV::TINT_Q = +sin(AnalogTV::IQ_OFFSET_RADIANS);
|
||||
|
||||
const double AnalogTV::COLOR_THRESH(1.4);
|
||||
|
||||
IQ AnalogTV::get_iq_factor(const CB& cb)
|
||||
{
|
||||
std::map<CB,IQ>::iterator hit = cacheCB.find(cb);
|
||||
if (hit != cacheCB.end())
|
||||
{
|
||||
return hit->second;
|
||||
}
|
||||
|
||||
double cb_phase[4];
|
||||
cb.getPhase(cb_phase);
|
||||
const double cb_i = cb_phase[2]-cb_phase[0];
|
||||
const double cb_q = cb_phase[3]-cb_phase[1];
|
||||
|
||||
if ((cb_i*cb_i) + (cb_q*cb_q) < COLOR_THRESH)
|
||||
{
|
||||
return BLACK_AND_WHITE;
|
||||
}
|
||||
|
||||
double iq_factor[4];
|
||||
|
||||
iq_factor[0] = cb_i * TINT_I + cb_q * TINT_Q;
|
||||
iq_factor[2] = -iq_factor[0];
|
||||
iq_factor[1] = cb_q * TINT_I - cb_i * TINT_Q;
|
||||
iq_factor[3] = -iq_factor[1];
|
||||
|
||||
const IQ iq(iq_factor);
|
||||
if (!this->noise)
|
||||
{
|
||||
cacheCB[cb] = iq;
|
||||
}
|
||||
return iq;
|
||||
}
|
||||
|
||||
const int AnalogTV::IQINTOFF(130);
|
||||
|
||||
void AnalogTV::ntsc_to_yiq(const int isignal, const int siglen, const IQ& iq_factor, int yiq[])
|
||||
{
|
||||
Lowpass_3_58_MHz filterY;
|
||||
Lowpass_1_5_MHz filterI;
|
||||
Lowpass_1_5_MHz filterQ;
|
||||
for (int off = 0; off < siglen; ++off)
|
||||
{
|
||||
const int sig = this->signal[isignal + off];
|
||||
const int y = filterY.next(sig); // + 40; // to show blacker-than-black levels
|
||||
int i;
|
||||
int q;
|
||||
if (y < -2)
|
||||
{
|
||||
i = 0;
|
||||
q = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = filterI.next((int)(sig * iq_factor.get(off & 3)));
|
||||
q = filterQ.next((int)(sig * iq_factor.get((off + 3) & 3)));
|
||||
}
|
||||
|
||||
yiq[off] = (((q+IQINTOFF)&0xff) << 16) | (((i+IQINTOFF)&0xff) << 8) | ((y+IQINTOFF)&0xff);
|
||||
}
|
||||
}
|
||||
|
||||
int inline AnalogTV::yiq2rgb(const int yiq)
|
||||
{
|
||||
double r = (((yiq)&0xFF)-IQINTOFF) + 0.956 * (((yiq>>8)&0xFF)-IQINTOFF) + 0.621 * (((yiq>>16)&0xFF)-IQINTOFF);
|
||||
double g = (((yiq)&0xFF)-IQINTOFF) - 0.272 * (((yiq>>8)&0xFF)-IQINTOFF) - 0.647 * (((yiq>>16)&0xFF)-IQINTOFF);
|
||||
double b = (((yiq)&0xFF)-IQINTOFF) - 1.105 * (((yiq>>8)&0xFF)-IQINTOFF) + 1.702 * (((yiq>>16)&0xFF)-IQINTOFF);
|
||||
|
||||
const int rgb =
|
||||
(calc_color(r) << 16)|
|
||||
(calc_color(g) << 8)|
|
||||
(calc_color(b) << 0);
|
||||
|
||||
return rgb;
|
||||
}
|
||||
|
||||
int inline AnalogTV::color2bw(const int rgb)
|
||||
{
|
||||
const int y = rgb2y(rgb);
|
||||
return y<<16 | y<<8 | y;
|
||||
}
|
||||
|
||||
int inline AnalogTV::rgb2y(const int rgb) // y in range 0-255
|
||||
{
|
||||
return (int)((0.299*((rgb>>16)&0xFF) + 0.587*((rgb>>8)&0xFF) + 0.114*((rgb)&0xFF))/1.04);
|
||||
}
|
||||
|
||||
int inline AnalogTV::calc_color(const double color)
|
||||
{
|
||||
int x = (int)(color * 0x100 / AppleNTSC::LEVEL_RANGE + .5);
|
||||
x = clamp(0,x,0x100);
|
||||
return x & 0xFF;
|
||||
}
|
||||
|
||||
int inline AnalogTV::clamp(int min, int x, int lim)
|
||||
{
|
||||
if (x < min)
|
||||
return min;
|
||||
if (lim <= x)
|
||||
return lim-1;
|
||||
return x;
|
||||
}
|
111
src/analogtv.h
Normal file
111
src/analogtv.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef ANALOGTV_H
|
||||
#define ANALOGTV_H
|
||||
|
||||
#include "analogtv.h"
|
||||
#include "applentsc.h"
|
||||
#include "a2colorsobserved.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
class ScreenImage;
|
||||
class IQ;
|
||||
class CB;
|
||||
|
||||
class AnalogTV
|
||||
{
|
||||
public:
|
||||
enum DisplayType
|
||||
{
|
||||
MONITOR_COLOR,
|
||||
MONITOR_WHITE,
|
||||
MONITOR_GREEN,
|
||||
MONITOR_ORANGE,
|
||||
TV_OLD_COLOR,
|
||||
TV_OLD_BW,
|
||||
TV_NEW_COLOR,
|
||||
TV_NEW_BW,
|
||||
|
||||
NUM_DISPLAY_TYPES
|
||||
};
|
||||
|
||||
private:
|
||||
ScreenImage& image;
|
||||
|
||||
bool on;
|
||||
bool noise;
|
||||
DisplayType type;
|
||||
bool bleed_down;
|
||||
|
||||
static int* rcb;
|
||||
|
||||
A2ColorsObserved colors;
|
||||
std::vector<unsigned int> hirescolor;
|
||||
std::vector<unsigned int> loreslightcolor;
|
||||
std::vector<unsigned int> loresdarkcolor;
|
||||
|
||||
static const int IQINTOFF;
|
||||
static const double IQ_OFFSET_DEGREES;
|
||||
static const double IQ_OFFSET_RADIANS;
|
||||
static const double TINT_I;
|
||||
static const double TINT_Q;
|
||||
static const double COLOR_THRESH;
|
||||
static const IQ& BLACK_AND_WHITE;
|
||||
|
||||
void drawMonitorColor();
|
||||
void drawMonitorWhite();
|
||||
void drawMonitorGreen();
|
||||
void drawMonitorOrange();
|
||||
void drawMonitorMonochrome(const unsigned int color);
|
||||
void drawTVOld();
|
||||
void drawTVNew();
|
||||
void drawBlank();
|
||||
void ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned int rgb[]);
|
||||
void ntsc_to_rgb_newtv(const int isignal, const int siglen, unsigned int rgb[]);
|
||||
CB get_cb(int lineno);
|
||||
IQ get_iq_factor(const CB& cb);
|
||||
void ntsc_to_yiq(const int isignal, const int siglen, const IQ& iq_factor, int yiq[]);
|
||||
static int yiq2rgb(const int yiq);
|
||||
static int color2bw(const int rgb);
|
||||
static int rgb2y(const int rgb); // ;y in range 0-255
|
||||
static int calc_color(const double color);
|
||||
static int clamp(int min, int x, int lim);
|
||||
|
||||
public:
|
||||
void drawCurrent();
|
||||
signed char* signal;
|
||||
|
||||
AnalogTV(ScreenImage& image);
|
||||
~AnalogTV();
|
||||
|
||||
bool isOn() const
|
||||
{
|
||||
return this->on;
|
||||
}
|
||||
|
||||
void powerOn(bool b);
|
||||
void toggleBleedDown();
|
||||
void restartSignal();
|
||||
void setType(DisplayType type);
|
||||
void cycleType();
|
||||
void setNoise(bool noise) { this->noise = noise; }
|
||||
};
|
||||
|
||||
#endif
|
91
src/apple2.cpp
Normal file
91
src/apple2.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "apple2.h"
|
||||
#include "slots.h"
|
||||
#include "videomode.h"
|
||||
#include "keyboard.h"
|
||||
#include "addressbus.h"
|
||||
#include "memory.h"
|
||||
#include "picturegenerator.h"
|
||||
#include "textcharacters.h"
|
||||
#include "video.h"
|
||||
#include "cpu.h"
|
||||
#include "paddles.h"
|
||||
#include "paddlebuttonstates.h"
|
||||
#include "speakerclicker.h"
|
||||
#include "analogtv.h"
|
||||
#include "powerupreset.h"
|
||||
#include "diskcontroller.h"
|
||||
#include "languagecard.h"
|
||||
#include "screenimage.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
Apple2::Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui):
|
||||
slts(gui),
|
||||
kbd(keypresses,fhyper,buffered),
|
||||
rom(AddressBus::MOTHERBOARD_ROM_SIZ),
|
||||
ram(AddressBus::MOTHERBOARD_RAM_SIZ),
|
||||
cassette(gui),
|
||||
addressBus(ram,rom,kbd,videoMode,paddles,paddleButtonStates,speaker,cassette,slts),
|
||||
picgen(tv,videoMode,this->revision),
|
||||
video(videoMode,addressBus,picgen,textRows),
|
||||
cpu(addressBus),
|
||||
powerUpReset(*this),
|
||||
revision(1)
|
||||
{
|
||||
}
|
||||
|
||||
Apple2::~Apple2()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Apple2::tick()
|
||||
{
|
||||
this->cpu.tick();
|
||||
this->video.tick();
|
||||
this->paddles.tick();
|
||||
this->speaker.tick();
|
||||
this->cassette.tick();
|
||||
|
||||
if (this->revision > 0)
|
||||
this->powerUpReset.tick();
|
||||
}
|
||||
|
||||
void Apple2::powerOn()
|
||||
{
|
||||
this->ram.powerOn();
|
||||
this->cpu.powerOn();
|
||||
this->videoMode.powerOn();
|
||||
this->video.powerOn();
|
||||
this->picgen.powerOn();
|
||||
this->powerUpReset.powerOn();
|
||||
}
|
||||
|
||||
void Apple2::powerOff()
|
||||
{
|
||||
this->ram.powerOff();
|
||||
}
|
||||
|
||||
void Apple2::reset()
|
||||
{
|
||||
this->cpu.reset();
|
||||
this->slts.reset();
|
||||
}
|
71
src/apple2.h
Normal file
71
src/apple2.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef APPLE2_H
|
||||
#define APPLE2_H
|
||||
|
||||
#include "timable.h"
|
||||
#include "slots.h"
|
||||
#include "videomode.h"
|
||||
#include "keyboard.h"
|
||||
#include "addressbus.h"
|
||||
#include "memory.h"
|
||||
#include "picturegenerator.h"
|
||||
#include "textcharacters.h"
|
||||
#include "video.h"
|
||||
#include "cpu.h"
|
||||
#include "paddles.h"
|
||||
#include "paddlebuttonstates.h"
|
||||
#include "speakerclicker.h"
|
||||
#include "analogtv.h"
|
||||
#include "powerupreset.h"
|
||||
#include "cassette.h"
|
||||
class Emulator;
|
||||
class ScreenImage;
|
||||
|
||||
class Apple2 : public Timable
|
||||
{
|
||||
Slots slts;
|
||||
VideoMode videoMode;
|
||||
Keyboard kbd;
|
||||
Paddles paddles;
|
||||
SpeakerClicker speaker;
|
||||
Memory rom;
|
||||
Memory ram;
|
||||
Cassette cassette;
|
||||
AddressBus addressBus;
|
||||
PictureGenerator picgen;
|
||||
TextCharacters textRows;
|
||||
Video video;
|
||||
CPU cpu;
|
||||
PowerUpReset powerUpReset;
|
||||
int revision;
|
||||
|
||||
public:
|
||||
Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui);
|
||||
~Apple2();
|
||||
|
||||
void powerOn();
|
||||
void powerOff();
|
||||
void reset();
|
||||
|
||||
virtual void tick();
|
||||
|
||||
friend class Emulator;
|
||||
};
|
||||
|
||||
#endif
|
18
src/applentsc.cpp
Normal file
18
src/applentsc.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "applentsc.h"
|
51
src/applentsc.h
Normal file
51
src/applentsc.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef APPLENTSC_H
|
||||
#define APPLENTSC_H
|
||||
|
||||
class AppleNTSC
|
||||
{
|
||||
private:
|
||||
AppleNTSC() {}
|
||||
|
||||
public:
|
||||
enum { V = 262, H = (25+40)*14+2 };
|
||||
enum { SIGNAL_LEN = V*H };
|
||||
|
||||
enum
|
||||
{
|
||||
FP_START = 0,
|
||||
SYNC_START = FP_START+126,
|
||||
BP_START = SYNC_START+112,
|
||||
CB_START = BP_START+0,
|
||||
CB_END = CB_START+56,
|
||||
SPIKE = CB_END+34,
|
||||
PIC_START = CB_END+56
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
WHITE_LEVEL = 100,
|
||||
BLANK_LEVEL = 0,
|
||||
SYNC_LEVEL = -40,
|
||||
CB_LEVEL = 20,
|
||||
LEVEL_RANGE = WHITE_LEVEL-SYNC_LEVEL
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
102
src/card.cpp
Normal file
102
src/card.cpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "card.h"
|
||||
#include "configep2.h"
|
||||
|
||||
Card::Card():
|
||||
rom(0x0100),
|
||||
seventhRom(0x0800)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Card::~Card()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Card::reset()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char Card::io(const unsigned short /*address*/, const unsigned char data, const bool /*writing*/)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char Card::readRom(const unsigned short address, const unsigned char data)
|
||||
{
|
||||
this->activeSeventhRom = true;
|
||||
return this->rom.read(address);
|
||||
}
|
||||
|
||||
void Card::readSeventhRom(const unsigned short address, unsigned char* const pb)
|
||||
{
|
||||
if (address == 0x7FF)
|
||||
{
|
||||
this->activeSeventhRom = false;
|
||||
}
|
||||
else if (this->activeSeventhRom && hasSeventhRom())
|
||||
{
|
||||
*pb = this->seventhRom.read(address);
|
||||
}
|
||||
}
|
||||
|
||||
void Card::loadRom(const unsigned short base, std::istream& in)
|
||||
{
|
||||
this->rom.load(base,in);
|
||||
}
|
||||
|
||||
void Card::loadSeventhRom(const unsigned short base, std::istream& in)
|
||||
{
|
||||
this->seventhRom.load(base,in);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Card::inhibitMotherboardRom()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Card::ioBankRom(const unsigned short /*addr*/, unsigned char* const /*pb*/, const bool /*write*/)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Card::loadBankRom(const unsigned short /*base*/, std::istream& /*in*/)
|
||||
{
|
||||
throw ConfigException("This card has no $D000 ROM");
|
||||
}
|
||||
|
||||
std::string Card::getName()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Card::isDirty()
|
||||
{
|
||||
return false;
|
||||
}
|
51
src/card.h
Normal file
51
src/card.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CARD_H
|
||||
#define CARD_H
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
#include <istream>
|
||||
#include <string>
|
||||
|
||||
class Card
|
||||
{
|
||||
private:
|
||||
bool activeSeventhRom;
|
||||
protected:
|
||||
Memory rom;
|
||||
Memory seventhRom;
|
||||
|
||||
public:
|
||||
Card();
|
||||
virtual ~Card();
|
||||
virtual void reset();
|
||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||
virtual unsigned char readRom(const unsigned short address, const unsigned char data);
|
||||
virtual bool hasSeventhRom() { return false; }
|
||||
virtual void readSeventhRom(const unsigned short address, unsigned char* const pb);
|
||||
virtual void loadRom(const unsigned short base, std::istream& in);
|
||||
virtual void loadSeventhRom(const unsigned short base, std::istream& in);
|
||||
virtual bool inhibitMotherboardRom();
|
||||
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
|
||||
virtual void loadBankRom(const unsigned short base, std::istream& in);
|
||||
virtual bool isDirty();
|
||||
virtual std::string getName();
|
||||
};
|
||||
|
||||
#endif
|
209
src/cassette.cpp
Normal file
209
src/cassette.cpp
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
cassette tape image file format
|
||||
-------------------------------
|
||||
Each byte represents one half cycle, in 10-microsoecond units.
|
||||
For example, consider the following values in the file (decimal):
|
||||
|
||||
65 65 65 65 65 20 25 50 50 25 25 25 25 50 50
|
||||
|
||||
This represents the following half-cycles (in microseconds)
|
||||
650 650 650 650 650 200 250 500 500 250 250 250 250 500 500
|
||||
which has the following meaning:
|
||||
|
||||
|--------HEADER-----|--sync-|-1-bit-|-0-bit-|-0-bit-|-1-bit-|
|
||||
| | | | | | |
|
||||
|650 650 650 650 650|200 250|500 500|250 250|250 250|500 500|
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "cassette.h"
|
||||
|
||||
Cassette::Cassette(ScreenImage& gui):
|
||||
gui(gui), t(0), prevT(0), markT(0), positive(false)
|
||||
{
|
||||
unload();
|
||||
}
|
||||
|
||||
|
||||
Cassette::~Cassette()
|
||||
{
|
||||
}
|
||||
|
||||
void Cassette::tick()
|
||||
{
|
||||
++this->t;
|
||||
// TODO: check for roll-over of tick-count in Cassette???
|
||||
// if (this->t == 0)
|
||||
}
|
||||
|
||||
void Cassette::output()
|
||||
{
|
||||
if (isWriteProtected() || !isLoaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (this->half_cycles.size() <= this->pos)
|
||||
{
|
||||
this->half_cycles.push_back(getHalfCycleTime());
|
||||
this->pos = this->half_cycles.size();
|
||||
this->gui.setCassettePos(this->pos,this->half_cycles.size());
|
||||
this->modified = true;
|
||||
this->gui.setCassetteDirty(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO should we allow overwriting of cassestte tape data?
|
||||
// If so, need to watch out because while reading Apple will
|
||||
// be calling Cassette::output, too.
|
||||
}
|
||||
|
||||
this->prevT = this->t;
|
||||
}
|
||||
|
||||
unsigned char Cassette::getHalfCycleTime() // in 10-microsecond units
|
||||
{
|
||||
const unsigned int delta_cycles(this->t-this->prevT);
|
||||
if (delta_cycles < 225)
|
||||
return 20;
|
||||
if (delta_cycles < 375)
|
||||
return 25;
|
||||
if (delta_cycles < 575)
|
||||
return 50;
|
||||
return 65;
|
||||
}
|
||||
|
||||
bool Cassette::input()
|
||||
{
|
||||
if (!isLoaded())
|
||||
{
|
||||
// no tape loaded
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this->markT <= this->t) // we've hit our mark
|
||||
{
|
||||
this->positive = !this->positive;
|
||||
if (this->pos < this->half_cycles.size())
|
||||
{
|
||||
// set our next mark to be at the end of next half-cycle read from tape
|
||||
this->markT = this->t+this->half_cycles[this->pos++]*10;
|
||||
this->gui.setCassettePos(this->pos,this->half_cycles.size());
|
||||
}
|
||||
}
|
||||
|
||||
return this->positive;
|
||||
}
|
||||
|
||||
void Cassette::rewind()
|
||||
{
|
||||
this->pos = 0;
|
||||
this->gui.setCassettePos(this->pos,this->half_cycles.size());
|
||||
}
|
||||
|
||||
bool Cassette::newFile(const std::string& filePath)
|
||||
{
|
||||
std::ifstream in(filePath.c_str(),std::ios::binary|std::ios::in);
|
||||
if (in.is_open())
|
||||
{
|
||||
in.close();
|
||||
std::cerr << "Error creating file; file already exists: " << filePath << std::endl;
|
||||
return false;
|
||||
}
|
||||
std::ofstream out(filePath.c_str(),std::ios::binary|std::ios::out);
|
||||
out.close();
|
||||
return load(filePath);
|
||||
}
|
||||
|
||||
bool Cassette::load(const std::string& filePath)
|
||||
{
|
||||
// TODO better I/O error handling during cassette loading and saving
|
||||
std::ifstream in(filePath.c_str(),std::ios::binary|std::ios::in|std::ios::ate);
|
||||
if (!in.is_open())
|
||||
{
|
||||
std::cerr << "Error loading " << filePath << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (isLoaded())
|
||||
{
|
||||
unload();
|
||||
}
|
||||
|
||||
const std::ifstream::pos_type size = in.tellg();
|
||||
if (size > 0)
|
||||
{
|
||||
this->half_cycles.resize(size);
|
||||
in.seekg(0,std::ios::beg);
|
||||
in.read((char*)&this->half_cycles[0],size);
|
||||
// std::cerr << "Read " << size << " bytes from " << filePath << std::endl;
|
||||
}
|
||||
in.close();
|
||||
|
||||
this->filePath = filePath;
|
||||
|
||||
checkForWriteProtection();
|
||||
|
||||
this->loaded = true;
|
||||
this->modified = false;
|
||||
|
||||
this->gui.setCassetteFile(filePath);
|
||||
this->gui.setCassetteDirty(false);
|
||||
this->gui.setCassettePos(this->pos,size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cassette::checkForWriteProtection()
|
||||
{
|
||||
std::ofstream outf(filePath.c_str(),std::ios::binary|std::ios::app);
|
||||
this->writable = outf.is_open();
|
||||
outf.close();
|
||||
}
|
||||
|
||||
void Cassette::save()
|
||||
{
|
||||
if (isWriteProtected() || !isLoaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::ofstream out(filePath.c_str(),std::ios::binary);
|
||||
out.write((char*)&this->half_cycles[0],this->half_cycles.size());
|
||||
out.flush();
|
||||
out.close();
|
||||
|
||||
this->modified = false;
|
||||
this->gui.setCassetteDirty(false);
|
||||
}
|
||||
|
||||
void Cassette::unload()
|
||||
{
|
||||
this->pos = 0;
|
||||
this->writable = true;
|
||||
this->loaded = false;
|
||||
this->filePath = "";
|
||||
this->modified = false;
|
||||
this->half_cycles.clear();
|
||||
this->gui.setCassetteFile("");
|
||||
this->gui.setCassetteDirty(false);
|
||||
this->gui.setCassettePos(this->pos,this->half_cycles.size());
|
||||
}
|
83
src/cassette.h
Normal file
83
src/cassette.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CASSETTE_H
|
||||
#define CASSETTE_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "screenimage.h"
|
||||
|
||||
class Cassette
|
||||
{
|
||||
private:
|
||||
unsigned int t;
|
||||
unsigned int prevT;
|
||||
|
||||
unsigned int markT;
|
||||
bool positive;
|
||||
|
||||
std::vector<unsigned char> half_cycles;
|
||||
|
||||
std::string fileName;
|
||||
std::string filePath;
|
||||
bool writable;
|
||||
bool loaded;
|
||||
unsigned int pos;
|
||||
bool modified;
|
||||
|
||||
ScreenImage& gui;
|
||||
|
||||
void checkForWriteProtection();
|
||||
|
||||
unsigned char getHalfCycleTime(); // in 10-microsecond units
|
||||
|
||||
public:
|
||||
Cassette(ScreenImage& gui);
|
||||
~Cassette();
|
||||
|
||||
void tick();
|
||||
void output();
|
||||
bool input();
|
||||
void rewind();
|
||||
bool newFile(const std::string& filePath);
|
||||
bool load(const std::string& filePath);
|
||||
std::string getFileName()
|
||||
{
|
||||
return this->fileName;
|
||||
}
|
||||
|
||||
bool isLoaded()
|
||||
{
|
||||
return this->loaded;
|
||||
}
|
||||
|
||||
void save();
|
||||
void unload();
|
||||
bool isWriteProtected()
|
||||
{
|
||||
return !this->writable;
|
||||
}
|
||||
|
||||
bool isModified()
|
||||
{
|
||||
return this->modified;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
230
src/clipboardhandler.cpp
Normal file
230
src/clipboardhandler.cpp
Normal file
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "clipboardhandler.h"
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL/SDL_syswm.h>
|
||||
#include <limits.h>
|
||||
|
||||
// taken from: http://www.libsdl.org/projects/scrap (original author: Sam Lantinga)
|
||||
|
||||
|
||||
/* Determine what type of clipboard we are using */
|
||||
#if defined(__WIN32__) || defined(__CYGWIN__)
|
||||
#define WIN_SCRAP
|
||||
#elif defined(__unix__)
|
||||
#define X11_SCRAP
|
||||
#else
|
||||
#error Unknown window manager for clipboard handling
|
||||
#endif /* scrap type */
|
||||
|
||||
|
||||
|
||||
/* System dependent variables */
|
||||
#if defined(X11_SCRAP)
|
||||
static Display *SDL_Display;
|
||||
static Window SDL_Window;
|
||||
static void (*Lock_Display)();
|
||||
static void (*Unlock_Display)();
|
||||
#elif defined(WIN_SCRAP)
|
||||
static HWND SDL_Window;
|
||||
#endif /* scrap type */
|
||||
static bool initialized(false);
|
||||
static bool have(false);
|
||||
|
||||
|
||||
#ifdef X11_SCRAP
|
||||
static int clipboard_filter(const SDL_Event *event)
|
||||
{
|
||||
/* Post all non-window manager specific events */
|
||||
if ( event->type != SDL_SYSWMEVENT ) {
|
||||
return(1);
|
||||
}
|
||||
|
||||
/* Handle window-manager specific clipboard events */
|
||||
switch (event->syswm.msg->event.xevent.type) {
|
||||
/* Copy the selection from XA_CUT_BUFFER0 to the requested property */
|
||||
case SelectionRequest: {
|
||||
XSelectionRequestEvent *req;
|
||||
XEvent sevent;
|
||||
int seln_format;
|
||||
unsigned long nbytes;
|
||||
unsigned long overflow;
|
||||
unsigned char *seln_data;
|
||||
|
||||
req = &event->syswm.msg->event.xevent.xselectionrequest;
|
||||
sevent.xselection.type = SelectionNotify;
|
||||
sevent.xselection.display = req->display;
|
||||
sevent.xselection.selection = req->selection;
|
||||
sevent.xselection.target = None;
|
||||
sevent.xselection.property = None;
|
||||
sevent.xselection.requestor = req->requestor;
|
||||
sevent.xselection.time = req->time;
|
||||
if ( XGetWindowProperty(SDL_Display, DefaultRootWindow(SDL_Display),
|
||||
XA_CUT_BUFFER0, 0, INT_MAX/4, False, req->target,
|
||||
&sevent.xselection.target, &seln_format,
|
||||
&nbytes, &overflow, &seln_data) == Success )
|
||||
{
|
||||
if ( sevent.xselection.target == req->target )
|
||||
{
|
||||
if ( sevent.xselection.target == XA_STRING )
|
||||
{
|
||||
if ( seln_data[nbytes-1] == '\0' )
|
||||
--nbytes;
|
||||
}
|
||||
XChangeProperty(SDL_Display, req->requestor, req->property,
|
||||
sevent.xselection.target, seln_format, PropModeReplace,
|
||||
seln_data, nbytes);
|
||||
sevent.xselection.property = req->property;
|
||||
}
|
||||
XFree(seln_data);
|
||||
}
|
||||
XSendEvent(SDL_Display,req->requestor,False,0,&sevent);
|
||||
XSync(SDL_Display, False);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Post the event for X11 clipboard reading above */
|
||||
return(1);
|
||||
}
|
||||
#endif /* X11_SCRAP */
|
||||
|
||||
|
||||
|
||||
|
||||
ClipboardHandler::ClipboardHandler()
|
||||
{
|
||||
if (initialized)
|
||||
return;
|
||||
initialized = true;
|
||||
|
||||
SDL_SetError("SDL is not running on known window manager");
|
||||
|
||||
/* Grab the window manager specific information */
|
||||
SDL_SysWMinfo info;
|
||||
SDL_VERSION(&info.version);
|
||||
if (SDL_GetWMInfo(&info))
|
||||
{
|
||||
/* Save the information for later use */
|
||||
#if defined(X11_SCRAP)
|
||||
if (info.subsystem == SDL_SYSWM_X11)
|
||||
{
|
||||
SDL_Display = info.info.x11.display;
|
||||
SDL_Window = info.info.x11.window;
|
||||
Lock_Display = info.info.x11.lock_func;
|
||||
Unlock_Display = info.info.x11.unlock_func;
|
||||
|
||||
/* Enable the special window hook events */
|
||||
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
|
||||
SDL_SetEventFilter(clipboard_filter);
|
||||
|
||||
have = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_SetError("SDL is not running on X11");
|
||||
}
|
||||
#elif defined(WIN_SCRAP)
|
||||
SDL_Window = info.window;
|
||||
have = true;
|
||||
#endif /* scrap type */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ClipboardHandler::~ClipboardHandler()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
std::string ClipboardHandler::getText()
|
||||
{
|
||||
std::string ret;
|
||||
if (!have)
|
||||
return ret;
|
||||
|
||||
#if defined(X11_SCRAP)
|
||||
const Atom format(XA_STRING);
|
||||
|
||||
Atom selection;
|
||||
Lock_Display();
|
||||
Window owner = XGetSelectionOwner(SDL_Display, XA_PRIMARY);
|
||||
Unlock_Display();
|
||||
if (owner == None || owner == SDL_Window)
|
||||
{
|
||||
owner = DefaultRootWindow(SDL_Display);
|
||||
selection = XA_CUT_BUFFER0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int selection_response = 0;
|
||||
SDL_Event event;
|
||||
|
||||
owner = SDL_Window;
|
||||
Lock_Display();
|
||||
selection = XInternAtom(SDL_Display, "SDL_SELECTION", False);
|
||||
XConvertSelection(SDL_Display, XA_PRIMARY, format, selection, owner, CurrentTime);
|
||||
Unlock_Display();
|
||||
while (!selection_response)
|
||||
{
|
||||
SDL_WaitEvent(&event);
|
||||
if (event.type == SDL_SYSWMEVENT)
|
||||
{
|
||||
XEvent xevent = event.syswm.msg->event.xevent;
|
||||
|
||||
if (xevent.type == SelectionNotify && xevent.xselection.requestor == owner)
|
||||
selection_response = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Lock_Display();
|
||||
Atom seln_type;
|
||||
int seln_format;
|
||||
unsigned long nbytes;
|
||||
unsigned long overflow;
|
||||
char *src;
|
||||
if (XGetWindowProperty(SDL_Display, owner, selection, 0, INT_MAX/4, False, format, &seln_type, &seln_format, &nbytes, &overflow, (unsigned char **)&src) == Success)
|
||||
{
|
||||
if (seln_type == format)
|
||||
{
|
||||
ret.assign(src,nbytes);
|
||||
}
|
||||
XFree(src);
|
||||
}
|
||||
Unlock_Display();
|
||||
#elif defined(WIN_SCRAP)
|
||||
const UINT format(CF_TEXT);
|
||||
if (IsClipboardFormatAvailable(format) && OpenClipboard(SDL_Window))
|
||||
{
|
||||
const HANDLE hMem = GetClipboardData(format);
|
||||
if (hMem)
|
||||
{
|
||||
char *src = (char*)GlobalLock(hMem);
|
||||
ret.assign(src);
|
||||
GlobalUnlock(hMem);
|
||||
}
|
||||
CloseClipboard();
|
||||
}
|
||||
#endif /* scrap type */
|
||||
|
||||
return ret;
|
||||
}
|
33
src/clipboardhandler.h
Normal file
33
src/clipboardhandler.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CLIPBOARDHANDLER_H
|
||||
#define CLIPBOARDHANDLER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
class ClipboardHandler
|
||||
{
|
||||
public:
|
||||
ClipboardHandler();
|
||||
~ClipboardHandler();
|
||||
|
||||
std::string getText();
|
||||
};
|
||||
|
||||
#endif
|
70
src/clockcard.cpp
Normal file
70
src/clockcard.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "clockcard.h"
|
||||
#include <ctime>
|
||||
|
||||
ClockCard::ClockCard():
|
||||
latch(0),
|
||||
pos(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ClockCard::~ClockCard()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char ClockCard::io(const unsigned short address, const unsigned char data, const bool writing)
|
||||
{
|
||||
const int sw = address & 0x0F;
|
||||
if (sw == 0)
|
||||
{
|
||||
if (!(this->latch & 0x80))
|
||||
{
|
||||
if (this->pos == 0)
|
||||
{
|
||||
getTime();
|
||||
}
|
||||
char c = this->time[this->pos];
|
||||
this->latch = (unsigned char)(c | 0x80);
|
||||
++this->pos;
|
||||
if (this->pos >= this->timelen)
|
||||
{
|
||||
this->pos = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sw == 1)
|
||||
{
|
||||
this->latch &= 0x7F;
|
||||
}
|
||||
return this->latch;
|
||||
}
|
||||
|
||||
#define TIMEFORMAT "%m,0%w,%d,%H,%M,%S,000,%Y,%Z,D\r"
|
||||
|
||||
void ClockCard::getTime()
|
||||
{
|
||||
time_t now;
|
||||
::time(&now);
|
||||
struct tm* nowtm = ::localtime(&now);
|
||||
this->timelen = ::strftime(this->time,sizeof(this->time),TIMEFORMAT,nowtm);
|
||||
this->time[this->timelen-2] = nowtm->tm_isdst>0 ? '1' : '0';
|
||||
}
|
42
src/clockcard.h
Normal file
42
src/clockcard.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CLOCKCARD_H
|
||||
#define CLOCKCARD_H
|
||||
|
||||
#include "card.h"
|
||||
#include <string>
|
||||
|
||||
class ClockCard : public Card
|
||||
{
|
||||
private:
|
||||
unsigned char latch;
|
||||
unsigned int pos;
|
||||
char time[64];
|
||||
size_t timelen;
|
||||
|
||||
void getTime();
|
||||
|
||||
public:
|
||||
ClockCard();
|
||||
~ClockCard();
|
||||
|
||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||
virtual std::string getName() { return "clock"; }
|
||||
};
|
||||
|
||||
#endif
|
425
src/configep2.cpp
Normal file
425
src/configep2.cpp
Normal file
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "configep2.h"
|
||||
|
||||
#include "memory.h"
|
||||
#include "slots.h"
|
||||
#include "diskcontroller.h"
|
||||
#include "languagecard.h"
|
||||
#include "firmwarecard.h"
|
||||
#include "standardout.h"
|
||||
#include "standardin.h"
|
||||
#include "clockcard.h"
|
||||
#include "cassette.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
unsigned char Config::disk_mask(0);
|
||||
|
||||
Config::Config(const std::string& file_path):
|
||||
file_path(file_path)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Config::~Config()
|
||||
{
|
||||
}
|
||||
|
||||
static void strip_comment(std::string& str)
|
||||
{
|
||||
const size_t comment = str.find('#');
|
||||
if (comment < std::string::npos)
|
||||
{
|
||||
str.erase(comment);
|
||||
}
|
||||
}
|
||||
|
||||
static void trim(std::string& str)
|
||||
{
|
||||
{
|
||||
const size_t p = str.find_first_not_of(" \t");
|
||||
if (p < std::string::npos)
|
||||
{
|
||||
str.erase(0,p);
|
||||
}
|
||||
}
|
||||
{
|
||||
const size_t p = str.find_last_not_of(" \t");
|
||||
if (p+1 < std::string::npos)
|
||||
{
|
||||
str.erase(p+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Config::parse(Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, Cassette& cassette)
|
||||
{
|
||||
std::ifstream* pConfig;
|
||||
|
||||
std::string path(this->file_path);
|
||||
|
||||
if (!path.empty())
|
||||
{
|
||||
pConfig = new std::ifstream(path.c_str());
|
||||
if (!pConfig->is_open())
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Cannot open config file " << this->file_path.c_str();
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
}
|
||||
if (path.empty())
|
||||
{
|
||||
/*
|
||||
On Windows, the default directory will be
|
||||
C:\Program Files\Epple2 if they start the
|
||||
program from the Start Menu; therefore
|
||||
etc/epple2/epple2.conf would be
|
||||
C:\Program Files\epple2\etc\epple2\epple2.conf
|
||||
On Linux... the current directory could be
|
||||
anything, so this probably won't find it (unless
|
||||
the current directory is /).
|
||||
*/
|
||||
path = "etc/epple2/epple2.conf";
|
||||
pConfig = new std::ifstream(path.c_str());
|
||||
if (!pConfig->is_open())
|
||||
path.clear();
|
||||
}
|
||||
if (path.empty())
|
||||
{
|
||||
/*
|
||||
This is primarily for Linux. If configured for
|
||||
a PREFIX of "/usr/local", then this would be
|
||||
/usr/local/etc/epple2/epple2.conf
|
||||
*/
|
||||
path = ETCDIR "/epple2/epple2.conf";
|
||||
pConfig = new std::ifstream(path.c_str());
|
||||
if (!pConfig->is_open())
|
||||
path.clear();
|
||||
}
|
||||
if (path.empty())
|
||||
{
|
||||
/*
|
||||
Last effort to find it (most likely will
|
||||
only work on Linux).
|
||||
*/
|
||||
path = "/etc/epple2/epple2.conf";
|
||||
pConfig = new std::ifstream(path.c_str());
|
||||
if (!pConfig->is_open())
|
||||
path.clear();
|
||||
}
|
||||
if (path.empty())
|
||||
{
|
||||
std::cerr << "Cannot open config file /etc/epple2/epple2.conf" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
std::getline(*pConfig,line);
|
||||
while (!pConfig->eof())
|
||||
{
|
||||
strip_comment(line);
|
||||
trim(line);
|
||||
if (!line.empty())
|
||||
{
|
||||
parseLine(line,ram,rom,slts,revision,gui,cassette);
|
||||
}
|
||||
std::getline(*pConfig,line);
|
||||
}
|
||||
pConfig->close();
|
||||
delete pConfig;
|
||||
|
||||
// TODO: make sure there is no more than ONE stdin and/or ONE stdout card
|
||||
}
|
||||
void Config::parseLine(const std::string& line, Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, Cassette& cassette)
|
||||
{
|
||||
try
|
||||
{
|
||||
tryParseLine(line,ram,rom,slts,revision,gui,cassette);
|
||||
}
|
||||
catch (const ConfigException& err)
|
||||
{
|
||||
std::cerr << err.msg.c_str() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Config::tryParseLine(const std::string& line, Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, Cassette& cassette)
|
||||
{
|
||||
std::istringstream tok(line);
|
||||
|
||||
std::string cmd;
|
||||
tok >> cmd;
|
||||
if (cmd == "slot")
|
||||
{
|
||||
int slot;
|
||||
std::string sCardType;
|
||||
tok >> slot >> sCardType;
|
||||
|
||||
insertCard(sCardType,slot,slts,gui);
|
||||
}
|
||||
else if (cmd == "import")
|
||||
{
|
||||
std::string sm;
|
||||
tok >> sm;
|
||||
|
||||
int slot(-1);
|
||||
if (sm == "slot")
|
||||
{
|
||||
tok >> slot;
|
||||
}
|
||||
else if (sm != "motherboard")
|
||||
{
|
||||
throw ConfigException("error at \""+sm+"\"; expected \"slot #\" or \"motherboard\"");
|
||||
}
|
||||
|
||||
std::string romtype;
|
||||
tok >> romtype;
|
||||
|
||||
unsigned short base(0);
|
||||
tok >> std::hex >> base;
|
||||
|
||||
std::string file;
|
||||
std::getline(tok,file);
|
||||
trim(file);
|
||||
std::ifstream memfile(file.c_str(),std::ios::binary);
|
||||
if (!memfile.is_open())
|
||||
{
|
||||
throw ConfigException("cannot open file "+file);
|
||||
}
|
||||
|
||||
if (slot < 0) // motherboard
|
||||
{
|
||||
if (romtype == "rom")
|
||||
{
|
||||
rom.load(base,memfile);
|
||||
}
|
||||
else if (romtype == "ram")
|
||||
{
|
||||
ram.load(base,memfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ConfigException("error at \""+romtype+"\"; expected rom or ram");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (8 <= slot)
|
||||
{
|
||||
throw ConfigException("invalid slot number");
|
||||
}
|
||||
Card* card = slts.get(slot);
|
||||
if (romtype == "rom")
|
||||
card->loadRom(base,memfile);
|
||||
else if (romtype == "rom7")
|
||||
card->loadSeventhRom(base,memfile);
|
||||
else if (romtype == "rombank")
|
||||
card->loadBankRom(base,memfile);
|
||||
else
|
||||
throw ConfigException("error at \""+romtype+"\"; expected rom, rom7, or rombank");
|
||||
}
|
||||
memfile.close();
|
||||
}
|
||||
else if (cmd == "load" || cmd == "save" || cmd == "unload")
|
||||
{
|
||||
std::string slotk;
|
||||
tok >> slotk;
|
||||
if (slotk != "slot")
|
||||
{
|
||||
throw ConfigException("error at \""+slotk+"\"; expected \"slot\"");
|
||||
}
|
||||
|
||||
int slot(-1);
|
||||
tok >> slot;
|
||||
|
||||
std::string drivek;
|
||||
tok >> drivek;
|
||||
if (drivek != "drive")
|
||||
{
|
||||
throw ConfigException("error at \""+drivek+"\"; expected \"drive\"");
|
||||
}
|
||||
|
||||
int drive(-1);
|
||||
tok >> drive;
|
||||
|
||||
if (cmd == "load")
|
||||
{
|
||||
std::string fnib;
|
||||
std::getline(tok,fnib);
|
||||
trim(fnib);
|
||||
loadDisk(slts,slot,drive,fnib);
|
||||
}
|
||||
else if (cmd == "unload")
|
||||
{
|
||||
unloadDisk(slts,slot,drive);
|
||||
}
|
||||
else if (cmd == "save")
|
||||
{
|
||||
saveDisk(slts,slot,drive);
|
||||
}
|
||||
}
|
||||
else if (cmd == "revision")
|
||||
{
|
||||
tok >> std::hex >> revision;
|
||||
}
|
||||
else if (cmd == "cassette")
|
||||
{
|
||||
std::string cas;
|
||||
tok >> cas;
|
||||
|
||||
if (cas == "rewind")
|
||||
{
|
||||
cassette.rewind();
|
||||
}
|
||||
else if (cas == "new")
|
||||
{
|
||||
std::string fcas;
|
||||
std::getline(tok,fcas);
|
||||
trim(fcas);
|
||||
cassette.newFile(fcas);
|
||||
}
|
||||
else if (cas == "load")
|
||||
{
|
||||
std::string fcas;
|
||||
std::getline(tok,fcas);
|
||||
trim(fcas);
|
||||
cassette.load(fcas);
|
||||
}
|
||||
else if (cas == "unload")
|
||||
{
|
||||
cassette.unload();
|
||||
}
|
||||
else if (cas == "save")
|
||||
{
|
||||
cassette.save();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ConfigException("error: unknown cassette command: "+cas);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ConfigException("Invalid command: "+cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void Config::loadDisk(Slots& slts, int slot, int drive, const std::string& fnib)
|
||||
{
|
||||
if (drive < 1 || 2 < drive)
|
||||
{
|
||||
throw ConfigException("Invalid drive; must be 1 or 2");
|
||||
}
|
||||
|
||||
// TODO if file doesn't exist, name still gets displayed, and there's no error message
|
||||
Card* card = slts.get(slot);
|
||||
if (!(disk_mask & (1 << slot)))
|
||||
{
|
||||
std::cerr << "Slot " << slot << " doesn't have a disk controller card" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
DiskController* controller = (DiskController*)card;
|
||||
controller->loadDisk(drive-1,fnib);
|
||||
}
|
||||
|
||||
void Config::unloadDisk(Slots& slts, int slot, int drive)
|
||||
{
|
||||
if (drive < 1 || 2 < drive)
|
||||
{
|
||||
throw ConfigException("Invalid drive; must be 1 or 2");
|
||||
}
|
||||
|
||||
Card* card = slts.get(slot);
|
||||
if (!(disk_mask & (1 << slot)))
|
||||
{
|
||||
std::cerr << "Slot " << slot << " doesn't have a disk controller card" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
DiskController* controller = (DiskController*)card;
|
||||
controller->unloadDisk(drive-1);
|
||||
}
|
||||
|
||||
void Config::saveDisk(Slots& slts, int slot, int drive)
|
||||
{
|
||||
if (drive < 1 || 2 < drive)
|
||||
{
|
||||
throw ConfigException("Invalid drive; must be 1 or 2");
|
||||
}
|
||||
Card* card = slts.get(slot);
|
||||
DiskController* controller = (DiskController*)card;
|
||||
controller->saveDisk(drive-1);
|
||||
}
|
||||
|
||||
void Config::insertCard(const std::string& cardType, int slot, Slots& slts, ScreenImage& gui)
|
||||
{
|
||||
if (slot < 0 || 8 <= slot)
|
||||
{
|
||||
throw ConfigException("Invalid slot number");
|
||||
}
|
||||
|
||||
Card* card;
|
||||
|
||||
disk_mask &= ~(1 << slot);
|
||||
|
||||
if (cardType == "language")
|
||||
{
|
||||
card = new LanguageCard(gui,slot);
|
||||
}
|
||||
else if (cardType == "firmware")
|
||||
{
|
||||
card = new FirmwareCard(gui,slot);
|
||||
}
|
||||
else if (cardType == "disk")
|
||||
{
|
||||
card = new DiskController(gui,slot);
|
||||
disk_mask |= (1 << slot);
|
||||
}
|
||||
else if (cardType == "clock")
|
||||
{
|
||||
card = new ClockCard();
|
||||
}
|
||||
else if (cardType == "stdout")
|
||||
{
|
||||
card = new StandardOut();
|
||||
}
|
||||
else if (cardType == "stdin")
|
||||
{
|
||||
card = new StandardIn();
|
||||
}
|
||||
else if (cardType == "empty")
|
||||
{
|
||||
card = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ConfigException("Invalid card type: "+cardType);
|
||||
}
|
||||
|
||||
if (card)
|
||||
slts.set(slot,card);
|
||||
else
|
||||
slts.remove(slot);
|
||||
}
|
54
src/configep2.h
Normal file
54
src/configep2.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#include <string>
|
||||
class Memory;
|
||||
class Slots;
|
||||
class ScreenImage;
|
||||
class Cassette;
|
||||
|
||||
class ConfigException
|
||||
{
|
||||
public:
|
||||
const std::string msg;
|
||||
ConfigException(const std::string& msg) : msg(msg) {}
|
||||
};
|
||||
|
||||
class Config
|
||||
{
|
||||
private:
|
||||
const std::string& file_path;
|
||||
static unsigned char disk_mask;
|
||||
|
||||
static void loadDisk(Slots& slts, int slot, int drive, const std::string& fnib);
|
||||
static void unloadDisk(Slots& slts, int slot, int drive);
|
||||
static void saveDisk(Slots& slts, int slot, int drive);
|
||||
static void insertCard(const std::string& cardType, int slot, Slots& slts, ScreenImage& gui);
|
||||
static void tryParseLine(const std::string& line, Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, Cassette& cassette);
|
||||
|
||||
public:
|
||||
Config(const std::string& file_path);
|
||||
~Config();
|
||||
|
||||
void parse(Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, Cassette& cassette);
|
||||
static void parseLine(const std::string& line, Memory& ram, Memory& rom, Slots& slts, int& revision, ScreenImage& gui, Cassette& cassette);
|
||||
};
|
||||
|
||||
#endif
|
2118
src/cpu.cpp
Normal file
2118
src/cpu.cpp
Normal file
File diff suppressed because it is too large
Load Diff
217
src/cpu.h
Normal file
217
src/cpu.h
Normal file
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef CPU_H
|
||||
#define CPU_H
|
||||
|
||||
class AddressBus;
|
||||
|
||||
class CPU
|
||||
{
|
||||
private:
|
||||
enum { MEMORY_LIM = 1 << 0x10 };
|
||||
enum { IRQ_VECTOR = MEMORY_LIM-2 }; // or BRK
|
||||
enum { RESET_VECTOR = IRQ_VECTOR-2 }; // or power-on
|
||||
enum { NMI_VECTOR = RESET_VECTOR-2 };
|
||||
|
||||
unsigned char adl;
|
||||
unsigned char adh;
|
||||
unsigned char bal;
|
||||
unsigned char bah;
|
||||
unsigned char ial;
|
||||
unsigned char iah;
|
||||
unsigned char idx;
|
||||
signed char offset;
|
||||
bool branch;
|
||||
signed char sc;
|
||||
bool wc;
|
||||
|
||||
bool pendingIRQ;
|
||||
bool pendingNMI;
|
||||
bool pendingReset;
|
||||
|
||||
bool started;
|
||||
|
||||
unsigned char a;
|
||||
unsigned char x;
|
||||
unsigned char y;
|
||||
|
||||
unsigned char s;
|
||||
|
||||
//p = NVMBDIZC
|
||||
enum { PMASK_C = 1<<0 };
|
||||
enum { PMASK_Z = 1<<1 };
|
||||
enum { PMASK_I = 1<<2 };
|
||||
enum { PMASK_D = 1<<3 };
|
||||
enum { PMASK_B = 1<<4 };
|
||||
enum { PMASK_M = 1<<5 };
|
||||
enum { PMASK_V = 1<<6 };
|
||||
enum { PMASK_N = 1<<7 };
|
||||
unsigned char p;
|
||||
|
||||
unsigned short pc;
|
||||
|
||||
AddressBus& addressBus;
|
||||
|
||||
unsigned short address;
|
||||
unsigned char data;
|
||||
|
||||
unsigned short opcode;
|
||||
|
||||
signed char t;
|
||||
|
||||
|
||||
static void (CPU::*addr[])();
|
||||
static void (CPU::*exec[])();
|
||||
|
||||
void firstCycle();
|
||||
int getInterruptAddress();
|
||||
int getInterruptPseudoOpCode();
|
||||
void subsequentCycle();
|
||||
|
||||
void read();
|
||||
void write();
|
||||
void execute();
|
||||
void done();
|
||||
|
||||
unsigned char pch();
|
||||
unsigned char pcl();
|
||||
unsigned short sp();
|
||||
unsigned short push();
|
||||
unsigned short pull();
|
||||
unsigned char getIndex();
|
||||
unsigned short ad();
|
||||
unsigned short ia();
|
||||
unsigned short ba();
|
||||
unsigned short combine(const unsigned char lo, const unsigned char hi);
|
||||
void setP(const unsigned char mask, const unsigned char val);
|
||||
void setStatusRegisterNZ(const unsigned char val);
|
||||
unsigned char shiftLeft(unsigned char byt);
|
||||
unsigned char shiftRight(unsigned char byt);
|
||||
unsigned char rotateLeft(unsigned char byt);
|
||||
unsigned char rotateRight(unsigned char byt);
|
||||
void compare(const unsigned char r);
|
||||
|
||||
void addr_SINGLE();
|
||||
void addr_INTERNAL_IMMEDIATE();
|
||||
void addr_INTERNAL_ZERO_PAGE();
|
||||
void addr_INTERNAL_ABSOLUTE();
|
||||
void addr_INTERNAL_INDIRECT_X();
|
||||
void addr_INTERNAL_ABSOLUTE_XY();
|
||||
void addr_INTERNAL_ZERO_PAGE_XY();
|
||||
void addr_INTERNAL_INDIRECT_Y();
|
||||
void addr_STORE_ZERO_PAGE();
|
||||
void addr_STORE_ABSOLUTE();
|
||||
void addr_STORE_INDIRECT_X();
|
||||
void addr_STORE_ABSOLUTE_XY();
|
||||
void addr_STORE_ZERO_PAGE_XY();
|
||||
void addr_STORE_INDIRECT_Y();
|
||||
void addr_RMW_ZERO_PAGE();
|
||||
void addr_RMW_ABSOLUTE();
|
||||
void addr_RMW_ZERO_PAGE_X();
|
||||
void addr_RMW_ABSOLUTE_X();
|
||||
void addr_MISC_PUSH();
|
||||
void addr_MISC_PULL();
|
||||
void addr_MISC_JSR();
|
||||
void addr_MISC_BREAK();
|
||||
void addr_MISC_RTI();
|
||||
void addr_JMP_ABSOLUTE();
|
||||
void addr_JMP_INDIRECT();
|
||||
void addr_RTS();
|
||||
void addr_BRANCH();
|
||||
void addr_NMI();
|
||||
void addr_RESET();
|
||||
void addr_IRQ();
|
||||
|
||||
void LDA();
|
||||
void LDX();
|
||||
void LDY();
|
||||
void STA();
|
||||
void STX();
|
||||
void STY();
|
||||
void CMP();
|
||||
void CPX();
|
||||
void CPY();
|
||||
void AND();
|
||||
void ORA();
|
||||
void EOR();
|
||||
void ASL();
|
||||
void ASL_A();
|
||||
void LSR();
|
||||
void LSR_A();
|
||||
void ROL();
|
||||
void ROL_A();
|
||||
void ROR();
|
||||
void ROR_A();
|
||||
void ADC();
|
||||
void SBC();
|
||||
void INC();
|
||||
void DEC();
|
||||
void INX();
|
||||
void INY();
|
||||
void DEX();
|
||||
void DEY();
|
||||
void BIT();
|
||||
void PHA();
|
||||
void PHP();
|
||||
void PLA();
|
||||
void PLP();
|
||||
void BRK();
|
||||
void RTI();
|
||||
void JMP();
|
||||
void RTS();
|
||||
void JSR();
|
||||
void BNE();
|
||||
void BEQ();
|
||||
void BVC();
|
||||
void BVS();
|
||||
void BCC();
|
||||
void BCS();
|
||||
void BPL();
|
||||
void BMI();
|
||||
void TAX();
|
||||
void TXA();
|
||||
void TAY();
|
||||
void TYA();
|
||||
void TXS();
|
||||
void TSX();
|
||||
void CLC();
|
||||
void SEC();
|
||||
void CLI();
|
||||
void SEI();
|
||||
void CLV();
|
||||
void CLD();
|
||||
void SED();
|
||||
void NOP();
|
||||
void Unoff();
|
||||
void Unoff1();
|
||||
void Unoff2();
|
||||
void Unoff3();
|
||||
void Hang();
|
||||
|
||||
public:
|
||||
CPU(AddressBus& addressBus);
|
||||
~CPU();
|
||||
|
||||
void powerOn();
|
||||
void reset();
|
||||
void IRQ();
|
||||
void NMI();
|
||||
void tick();
|
||||
};
|
||||
|
||||
#endif
|
131
src/diskbytes.cpp
Normal file
131
src/diskbytes.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "diskbytes.h"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <fstream>
|
||||
|
||||
DiskBytes::DiskBytes()
|
||||
{
|
||||
unload();
|
||||
}
|
||||
|
||||
DiskBytes::~DiskBytes()
|
||||
{
|
||||
}
|
||||
|
||||
bool DiskBytes::load(const std::string& filePath)
|
||||
{
|
||||
|
||||
|
||||
// TODO better I/O error handling during disk loading and saving
|
||||
std::ifstream in(filePath.c_str(),std::ios::binary|std::ios::in);
|
||||
if (!in.is_open())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (isLoaded())
|
||||
{
|
||||
unload();
|
||||
}
|
||||
for (int t(0); t < TRACKS_PER_DISK; ++t)
|
||||
{
|
||||
this->bytes[t].resize(BYTES_PER_TRACK);
|
||||
in.read((char*)&this->bytes[t][0],BYTES_PER_TRACK);
|
||||
}
|
||||
in.close();
|
||||
|
||||
this->filePath = filePath;
|
||||
|
||||
checkForWriteProtection();
|
||||
|
||||
this->loaded = true;
|
||||
this->modified = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DiskBytes::checkForWriteProtection()
|
||||
{
|
||||
std::ofstream outf(filePath.c_str(),std::ios::binary|std::ios::app);
|
||||
this->writable = outf.is_open();
|
||||
outf.close();
|
||||
}
|
||||
|
||||
void DiskBytes::save()
|
||||
{
|
||||
if (isWriteProtected() || !isLoaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::ofstream out(filePath.c_str(),std::ios::binary);
|
||||
for (int t(0); t < TRACKS_PER_DISK; ++t)
|
||||
out.write((char*)&this->bytes[t][0],BYTES_PER_TRACK);
|
||||
out.flush();
|
||||
out.close();
|
||||
|
||||
this->modified = false;
|
||||
}
|
||||
|
||||
void DiskBytes::unload()
|
||||
{
|
||||
this->byt = 0;
|
||||
this->writable = true;
|
||||
this->loaded = false;
|
||||
this->filePath = "";
|
||||
this->modified = false;
|
||||
}
|
||||
|
||||
unsigned char DiskBytes::get(const int track)
|
||||
{
|
||||
if (!isLoaded())
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
const unsigned char ret = this->bytes[track][this->byt];
|
||||
nextByte();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DiskBytes::put(const unsigned char track, const unsigned char value)
|
||||
{
|
||||
if (TRACKS_PER_DISK <= track)
|
||||
{
|
||||
throw 0;
|
||||
}
|
||||
if (isWriteProtected() || !isLoaded())
|
||||
{
|
||||
return;
|
||||
}
|
||||
this->bytes[track][this->byt] = value;
|
||||
this->modified = true;
|
||||
nextByte();
|
||||
}
|
||||
|
||||
void inline DiskBytes::nextByte()
|
||||
{
|
||||
// emulates circular disk track
|
||||
++this->byt;
|
||||
if (this->byt >= BYTES_PER_TRACK)
|
||||
{
|
||||
this->byt = 0;
|
||||
}
|
||||
}
|
72
src/diskbytes.h
Normal file
72
src/diskbytes.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef DISKBYTES_H
|
||||
#define DISKBYTES_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class DiskBytes
|
||||
{
|
||||
private:
|
||||
enum { TRACKS_PER_DISK = 0x23 };
|
||||
enum { BYTES_PER_TRACK = 0x1A00 };
|
||||
|
||||
std::vector<unsigned char> bytes[TRACKS_PER_DISK];
|
||||
|
||||
std::string fileName;
|
||||
std::string filePath;
|
||||
bool writable;
|
||||
bool loaded;
|
||||
unsigned int byt; // represents rotational position of disk
|
||||
bool modified;
|
||||
|
||||
void nextByte();
|
||||
void checkForWriteProtection();
|
||||
|
||||
public:
|
||||
DiskBytes();
|
||||
~DiskBytes();
|
||||
|
||||
bool load(const std::string& filePath);
|
||||
std::string getFileName()
|
||||
{
|
||||
return this->fileName;
|
||||
}
|
||||
|
||||
bool isLoaded()
|
||||
{
|
||||
return this->loaded;
|
||||
}
|
||||
|
||||
void save();
|
||||
void unload();
|
||||
unsigned char get(const int track);
|
||||
void put(const unsigned char track, const unsigned char value);
|
||||
bool isWriteProtected()
|
||||
{
|
||||
return !this->writable;
|
||||
}
|
||||
|
||||
bool isModified()
|
||||
{
|
||||
return this->modified;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
82
src/diskcontroller.cpp
Normal file
82
src/diskcontroller.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "diskcontroller.h"
|
||||
|
||||
DiskController::DiskController(ScreenImage& gui, int slot):
|
||||
gui(gui),
|
||||
slot(slot),
|
||||
drive1(diskBytes1,arm1),
|
||||
drive2(diskBytes2,arm2),
|
||||
currentDrive(&this->drive1)
|
||||
{
|
||||
}
|
||||
|
||||
DiskController::~DiskController()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned char DiskController::io(const unsigned short addr, const unsigned char d, const bool writing)
|
||||
{
|
||||
unsigned char data(d);
|
||||
const unsigned char q = (addr & 0x000E) >> 1;
|
||||
const bool on = (addr & 0x0001);
|
||||
|
||||
switch (q)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
this->currentDrive->setMagnet(q,on);
|
||||
this->gui.setTrack(this->slot,getCurrentDriveNumber(),getTrack());
|
||||
break;
|
||||
case 4:
|
||||
this->motorOn = on;
|
||||
this->gui.setIO(this->slot,getCurrentDriveNumber(),on);
|
||||
break;
|
||||
case 5:
|
||||
this->gui.clearCurrentDrive(this->slot,getCurrentDriveNumber());
|
||||
this->currentDrive = (on ? &this->drive2 : &this->drive1);
|
||||
this->gui.setCurrentDrive(this->slot,getCurrentDriveNumber(),getTrack(),this->motorOn);
|
||||
break;
|
||||
case 6:
|
||||
if (on && this->write && writing)
|
||||
{
|
||||
set(data);
|
||||
this->gui.setIO(this->slot,getCurrentDriveNumber(),this->motorOn);
|
||||
this->gui.setDirty(this->slot,getCurrentDriveNumber(),true);
|
||||
}
|
||||
else if (!(on || this->write))
|
||||
{
|
||||
data = get();
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
this->write = on;
|
||||
if (this->currentDrive->isWriteProtected())
|
||||
{
|
||||
data |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
data &= 0x7F;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return data;
|
||||
}
|
166
src/diskcontroller.h
Normal file
166
src/diskcontroller.h
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "card.h"
|
||||
#include "drive.h"
|
||||
#include "screenimage.h"
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
class DiskController : public Card
|
||||
{
|
||||
private:
|
||||
ScreenImage& gui;
|
||||
int slot;
|
||||
DiskBytes diskBytes1;
|
||||
StepperMotor arm1;
|
||||
Drive drive1;
|
||||
|
||||
DiskBytes diskBytes2;
|
||||
StepperMotor arm2;
|
||||
Drive drive2;
|
||||
|
||||
Drive* currentDrive;
|
||||
|
||||
bool write;
|
||||
bool motorOn;
|
||||
|
||||
|
||||
// TODO for a rev. 0 motherboard, the disk controller will auto reset the CPU
|
||||
|
||||
void set(unsigned char data)
|
||||
{
|
||||
if (!this->motorOn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this->currentDrive->set(data);
|
||||
}
|
||||
|
||||
unsigned char get() const
|
||||
{
|
||||
if (!this->motorOn)
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
return this->currentDrive->get();
|
||||
}
|
||||
|
||||
Drive& getDrive(const unsigned char drive)
|
||||
{
|
||||
return (drive == 0) ? this->drive1 : this->drive2;
|
||||
}
|
||||
|
||||
Drive& getOtherDrive()
|
||||
{
|
||||
return (this->currentDrive == &this->drive1) ? this->drive2 : this->drive1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public:
|
||||
DiskController(ScreenImage& gui, int slot);
|
||||
~DiskController();
|
||||
|
||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||
|
||||
void reset()
|
||||
{
|
||||
this->gui.setIO(this->slot,getCurrentDriveNumber(),false);
|
||||
this->gui.clearCurrentDrive(this->slot,getCurrentDriveNumber());
|
||||
|
||||
this->currentDrive = &this->drive1;
|
||||
this->motorOn = false;
|
||||
|
||||
this->gui.setCurrentDrive(this->slot,getCurrentDriveNumber(),getTrack(),false);
|
||||
}
|
||||
|
||||
void loadDisk(unsigned char drive, const std::string& fnib)
|
||||
{
|
||||
if (!this->getDrive(drive).loadDisk(fnib))
|
||||
{
|
||||
return;
|
||||
}
|
||||
this->gui.setDiskFile(this->slot,drive,fnib);
|
||||
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
|
||||
}
|
||||
|
||||
void unloadDisk(unsigned char drive)
|
||||
{
|
||||
this->getDrive(drive).unloadDisk();
|
||||
this->gui.setDiskFile(this->slot,drive,"");
|
||||
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
|
||||
}
|
||||
|
||||
void saveDisk(unsigned char drive)
|
||||
{
|
||||
this->getDrive(drive).saveDisk();
|
||||
this->gui.setDirty(this->slot,getCurrentDriveNumber(),false);
|
||||
}
|
||||
|
||||
bool isMotorOn()
|
||||
{
|
||||
return this->motorOn;
|
||||
}
|
||||
|
||||
const DiskBytes& getDiskBytes(unsigned char disk)
|
||||
{
|
||||
return this->getDrive(disk).getDiskBytes();
|
||||
}
|
||||
|
||||
unsigned char getTrack()
|
||||
{
|
||||
return this->currentDrive->getTrack();
|
||||
}
|
||||
|
||||
bool isWriting()
|
||||
{
|
||||
return this->write;
|
||||
}
|
||||
|
||||
bool isModified()
|
||||
{
|
||||
return this->currentDrive->isModified();
|
||||
}
|
||||
|
||||
bool isModifiedOther()
|
||||
{
|
||||
return getOtherDrive().isModified();
|
||||
}
|
||||
|
||||
bool isWriteProtected()
|
||||
{
|
||||
return this->currentDrive->isWriteProtected();
|
||||
}
|
||||
|
||||
bool isDirty()
|
||||
{
|
||||
return isModified() || isModifiedOther();
|
||||
}
|
||||
|
||||
unsigned char getCurrentDriveNumber()
|
||||
{
|
||||
return this->currentDrive == &this->drive1 ? 0 : 1;
|
||||
}
|
||||
|
||||
unsigned char getOtherDriveNumber()
|
||||
{
|
||||
return 1-getCurrentDriveNumber();
|
||||
}
|
||||
|
||||
virtual std::string getName() { return "disk][ drive 1 drive 2 "; }
|
||||
};
|
18
src/drive.cpp
Normal file
18
src/drive.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "drive.h"
|
104
src/drive.h
Normal file
104
src/drive.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef DRIVE_H
|
||||
#define DRIVE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "diskbytes.h"
|
||||
#include "steppermotor.h"
|
||||
|
||||
class Drive
|
||||
{
|
||||
private:
|
||||
enum { TRACKS_PER_DISK = 0x23 };
|
||||
|
||||
DiskBytes& disk;
|
||||
StepperMotor& arm;
|
||||
|
||||
public:
|
||||
Drive(DiskBytes& disk, StepperMotor& arm):
|
||||
disk(disk),
|
||||
arm(arm)
|
||||
{
|
||||
}
|
||||
|
||||
~Drive() {}
|
||||
|
||||
bool loadDisk(const std::string& fnib)
|
||||
{
|
||||
return this->disk.load(fnib);
|
||||
}
|
||||
|
||||
void unloadDisk()
|
||||
{
|
||||
this->disk.unload();
|
||||
}
|
||||
bool isLoaded()
|
||||
{
|
||||
return this->disk.isLoaded();
|
||||
}
|
||||
|
||||
void saveDisk()
|
||||
{
|
||||
this->disk.save();
|
||||
}
|
||||
|
||||
bool isWriteProtected() const
|
||||
{
|
||||
return this->disk.isWriteProtected();
|
||||
}
|
||||
|
||||
bool isModified() const
|
||||
{
|
||||
return this->disk.isModified();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setMagnet(unsigned char q, bool on)
|
||||
{
|
||||
this->arm.setMagnet(q,on);
|
||||
}
|
||||
|
||||
int getTrack() const
|
||||
{
|
||||
return this->arm.getTrack();
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned char get() const
|
||||
{
|
||||
return this->disk.get(this->arm.getTrack());
|
||||
}
|
||||
|
||||
void set(unsigned char value)
|
||||
{
|
||||
this->disk.put(this->arm.getTrack(),value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const DiskBytes& getDiskBytes()
|
||||
{
|
||||
return this->disk;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
169
src/e2const.h
Normal file
169
src/e2const.h
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef E2CONST_H
|
||||
#define E2CONST_H
|
||||
|
||||
class E2Const
|
||||
{
|
||||
public:
|
||||
/*
|
||||
The NTSC standard defines the field rate as 60 fields per second. The number 60
|
||||
is based on the USA AC current frequency of 60 Hz. This, in turn, was based on the
|
||||
clock standard (60 seconds per minute and 60 minutes per hour).
|
||||
*/
|
||||
static const int NTSC_FIELD_HZ = 60;
|
||||
|
||||
/*
|
||||
The NTSC standard defines 525 lines per frame, which was chosen to be a multiple
|
||||
of a small number of standard tubes at the time, to produce a rate between RCA's
|
||||
recommended 441 (used by NBC) and Philco's suggested 600-800 lines.
|
||||
*/
|
||||
static const int NTSC_LINES_PER_FRAME = 3*5*5*7;
|
||||
|
||||
/*
|
||||
When color was added to the NTSC signal, studies by General Electric showed that
|
||||
minimum interference was achieved using a subcarrier frequency 455 times the field
|
||||
rate, which can also be obtained using standard tubes.
|
||||
*/
|
||||
static const int NTSC_COLOR_MULTIPLE = 5*7*13;
|
||||
|
||||
/*
|
||||
Adding color to NTSC also required slowing down the frame rate, by dropping one
|
||||
field after every 1000.
|
||||
*/
|
||||
static const int NTSC_COLOR_DROP_FIELD = 1000;
|
||||
|
||||
/*
|
||||
Calculate the color sub-channel rate, times 4.
|
||||
This will be the (approximate) Hz of the "14M"
|
||||
crystal oscillator in the Apple ][.
|
||||
14318181.818181818... Hz rounds to 14318182 Hz
|
||||
U.A.II, p.3-2
|
||||
*/
|
||||
static const int CRYSTAL_HZ = (int)(1.0F*NTSC_FIELD_HZ * NTSC_LINES_PER_FRAME * NTSC_COLOR_MULTIPLE * NTSC_COLOR_DROP_FIELD / (NTSC_COLOR_DROP_FIELD+1));
|
||||
|
||||
/*
|
||||
U.A.II, p. 3-3
|
||||
Normal 6502 cycle == 14 crystal periods
|
||||
Long 6502 cycle == 16 crystal periods
|
||||
*/
|
||||
static const int CRYSTAL_CYCLES_PER_CPU_CYCLE = 14;
|
||||
static const int EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE = 2;
|
||||
|
||||
/*
|
||||
65 bytes per row (64 normal CPU cycles plus one long CPU cycle)
|
||||
*/
|
||||
static const int BYTES_PER_ROW = (int)((NTSC_COLOR_DROP_FIELD+1)*1.0F*CRYSTAL_HZ/(NTSC_FIELD_HZ/2*NTSC_COLOR_DROP_FIELD*NTSC_LINES_PER_FRAME*CRYSTAL_CYCLES_PER_CPU_CYCLE));
|
||||
static const int HORIZ_CYCLES = BYTES_PER_ROW;
|
||||
|
||||
/*
|
||||
U.A.II, p. 3-2, "composite frequency... 1.0205 MHz"
|
||||
Actually 1020484 Hz.
|
||||
*/
|
||||
static const int AVG_CPU_HZ = (int)((1.0F*CRYSTAL_HZ*HORIZ_CYCLES)/(CRYSTAL_CYCLES_PER_CPU_CYCLE*HORIZ_CYCLES+EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE));
|
||||
|
||||
/*
|
||||
A normal NTSC field is 262.5 lines (half of a full frame's 525 lines).
|
||||
The Apple rounds this down to 262 lines.
|
||||
*/
|
||||
static const int NTSC_WHOLE_LINES_PER_FIELD = NTSC_LINES_PER_FRAME/2;
|
||||
|
||||
static const int BYTES_PER_FIELD = BYTES_PER_ROW*NTSC_WHOLE_LINES_PER_FIELD;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// exactly 1 million
|
||||
static const int MEGA = 1000000;
|
||||
|
||||
static const int VISIBLE_BITS_PER_BYTE = 7;
|
||||
static const int VISIBLE_LINES_PER_CHARACTER = 8;
|
||||
|
||||
/*
|
||||
* 1000+1 seconds 2 fields 1 frame 1000000 microseconds 63 50
|
||||
* total horizontal line period = -------------- * -------- * ------------- * -------------------- = ( -- + -- ) microseconds per line
|
||||
* 60*1000 fields 1 frame 3*5*5*7 lines 1 second 90
|
||||
*
|
||||
* 10 81
|
||||
* horizontal blanking period = (1.5+4.7+.6+2.5+1.6) = 10.9 microseconds per line = ( -- + -- ) microseconds per line
|
||||
* 90
|
||||
*
|
||||
* visible line period = total horizontal line period minus horizontal blanking period =
|
||||
*
|
||||
* 52 59
|
||||
* -- + -- microseconds per line
|
||||
* 90
|
||||
*
|
||||
*
|
||||
* To avoid the over-scan area, the Apple ][ uses only the middle 75% of the visible line, or 4739/120 microseconds
|
||||
*
|
||||
* Apple ][ uses half the clock rate, or 315/44 MHz, to oscillate the video signal.
|
||||
*
|
||||
* The result is 315/44 MHz * 4739/120 microseconds/line, rounded down, = 282 full pixel spots across the screen.
|
||||
* The Apple ][ displays 7 bits per byte hi-res or lo-res, (or 7 pixel-wide characters for text mode), so that
|
||||
* gives 282/7, which rounds down to 40 bytes per line.
|
||||
*/
|
||||
static const int VISIBLE_BYTES_PER_ROW = (int)((((1.0F*(NTSC_COLOR_DROP_FIELD+1)/(NTSC_FIELD_HZ*NTSC_COLOR_DROP_FIELD)*2/NTSC_LINES_PER_FRAME*MEGA)-(1.5+4.7+.6+2.5+1.6)) * 3/4) * (CRYSTAL_HZ/2)) / MEGA / VISIBLE_BITS_PER_BYTE;
|
||||
|
||||
/*
|
||||
* NTSC total lines per frame (525) minus unusable lines (19 plus 20) = 486 usable lines
|
||||
* To avoid the over-scan area, use the middle 80% of the vertical lines, giving 388 (rounded down) clearly visible lines
|
||||
* Apple ][ uses only half the vertical resolution because it doesn't interlace, giving 194.
|
||||
* Text characters are 8 pixels tall, so 194/8 rounded down gives 24 text lines.
|
||||
* Multiply by 8 to give 192 lines total.
|
||||
*/
|
||||
static const int VISIBLE_ROWS_PER_FIELD = (NTSC_LINES_PER_FRAME-(20+19)) * 8/10 / 2 /VISIBLE_LINES_PER_CHARACTER*VISIBLE_LINES_PER_CHARACTER;
|
||||
|
||||
static const int BLANKED_BYTES_PER_ROW = BYTES_PER_ROW-VISIBLE_BYTES_PER_ROW;
|
||||
static const int VISIBLE_BYTES_PER_FIELD = BYTES_PER_ROW*VISIBLE_ROWS_PER_FIELD;
|
||||
static const int SCANNABLE_ROWS = 0x100;
|
||||
static const int SCANNABLE_BYTES = SCANNABLE_ROWS*BYTES_PER_ROW;
|
||||
static const int RESET_ROWS = NTSC_WHOLE_LINES_PER_FIELD-SCANNABLE_ROWS;
|
||||
static const int RESET_BYTES = RESET_ROWS*BYTES_PER_ROW;
|
||||
|
||||
|
||||
|
||||
static const int MIXED_TEXT_LINES = 4;
|
||||
static const int ROWS_PER_TEXT_LINE = 8;
|
||||
static const int MIXED_TEXT_CYCLE = (VISIBLE_ROWS_PER_FIELD-MIXED_TEXT_LINES*ROWS_PER_TEXT_LINE)*BYTES_PER_ROW;
|
||||
|
||||
|
||||
static int test()
|
||||
{
|
||||
if (NTSC_FIELD_HZ!=60) return NTSC_FIELD_HZ;
|
||||
if (NTSC_LINES_PER_FRAME!=525) return NTSC_LINES_PER_FRAME;
|
||||
if (NTSC_COLOR_MULTIPLE!=455) return NTSC_COLOR_MULTIPLE;
|
||||
if (NTSC_COLOR_DROP_FIELD!=1000) return NTSC_COLOR_DROP_FIELD;
|
||||
if (CRYSTAL_HZ!=14318182) return CRYSTAL_HZ;
|
||||
if (BYTES_PER_ROW!=65) return BYTES_PER_ROW;
|
||||
if (AVG_CPU_HZ!=1020484) return AVG_CPU_HZ;
|
||||
if (BYTES_PER_FIELD!=17030) return BYTES_PER_FIELD;
|
||||
if (VISIBLE_BYTES_PER_ROW!=40) return VISIBLE_BYTES_PER_ROW;
|
||||
if (VISIBLE_ROWS_PER_FIELD!=192) return VISIBLE_ROWS_PER_FIELD;
|
||||
if (RESET_BYTES!=390) return RESET_BYTES;
|
||||
if (BLANKED_BYTES_PER_ROW!=25) return BLANKED_BYTES_PER_ROW;
|
||||
if (VISIBLE_BYTES_PER_FIELD!=12480) return VISIBLE_BYTES_PER_FIELD;
|
||||
if (SCANNABLE_BYTES!=16640) return SCANNABLE_BYTES;
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
18
src/emptyslot.cpp
Normal file
18
src/emptyslot.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "emptyslot.h"
|
36
src/emptyslot.h
Normal file
36
src/emptyslot.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef EMPTYSLOT_H
|
||||
#define EMPTYSLOT_H
|
||||
|
||||
#include "card.h"
|
||||
|
||||
class EmptySlot : public Card
|
||||
{
|
||||
public:
|
||||
EmptySlot() {}
|
||||
virtual ~EmptySlot() {}
|
||||
|
||||
virtual std::string getName() { return "empty"; }
|
||||
|
||||
// empty slots have no ROMs, so just return data (for floating bus emulation)
|
||||
virtual unsigned char readRom(const unsigned short address, const unsigned char data) { return data; }
|
||||
virtual void readSeventhRom(const unsigned short address, unsigned char* const pb) { }
|
||||
};
|
||||
|
||||
#endif
|
461
src/emulator.cpp
Normal file
461
src/emulator.cpp
Normal file
|
@ -0,0 +1,461 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "emulator.h"
|
||||
#include "configep2.h"
|
||||
#include "e2const.h"
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
#include <ctime>
|
||||
|
||||
Emulator::Emulator():
|
||||
display(screenImage),
|
||||
videoStatic(display),
|
||||
apple2(keypresses,paddleButtonStates,display,fhyper,buffered,screenImage),
|
||||
timable(0), // No ticked object (NULL pointer)
|
||||
quit(false),
|
||||
repeat(false),
|
||||
keysDown(0),
|
||||
command(false),
|
||||
pendingCommandExit(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Emulator::~Emulator()
|
||||
{
|
||||
}
|
||||
|
||||
void Emulator::toggleComputerPower()
|
||||
{
|
||||
if (this->timable==&this->videoStatic)
|
||||
powerOnComputer();
|
||||
else
|
||||
powerOffComputer();
|
||||
}
|
||||
|
||||
void Emulator::powerOnComputer()
|
||||
{
|
||||
this->apple2.powerOn();
|
||||
this->screenImage.drawPower(true);
|
||||
this->display.setNoise(false);
|
||||
|
||||
// The apple2 becomes the ticked object
|
||||
this->timable = &this->apple2;
|
||||
}
|
||||
|
||||
void Emulator::powerOffComputer()
|
||||
{
|
||||
// TODO Need to ask user if OK to lose any unsaved changes to disks
|
||||
this->apple2.powerOff();
|
||||
this->screenImage.drawPower(false);
|
||||
this->display.setNoise(true);
|
||||
this->videoStatic.powerOn();
|
||||
|
||||
// The video static becomes the ticked object
|
||||
this->timable = &this->videoStatic;
|
||||
}
|
||||
|
||||
void Emulator::config(Config& cfg)
|
||||
{
|
||||
cfg.parse(this->apple2.ram,this->apple2.rom,this->apple2.slts,this->apple2.revision,this->screenImage,this->apple2.cassette);
|
||||
}
|
||||
|
||||
void Emulator::init()
|
||||
{
|
||||
powerOffComputer();
|
||||
this->display.setType(AnalogTV::MONITOR_COLOR);
|
||||
this->display.powerOn(true);
|
||||
}
|
||||
|
||||
// How many emulation ticks between asking SDL if there is any new input
|
||||
// from the user or other GUI events.
|
||||
// This is also how often we shall update the estimate of the emulator's
|
||||
// actual speed performance
|
||||
// When the CPU is the object being ticked (each tick is a CPU cycle), then
|
||||
// this is 20.04378892 Hz in emulated seconds time
|
||||
#define CHECK_EVERY_CYCLE 51024
|
||||
#define CHECK_CYCLES_K 51024000
|
||||
#define EXPECTED_MS 50
|
||||
|
||||
// U.A.2 p. 7-13: REPT key repeats at 10Hz.
|
||||
static const int CYCLES_PER_REPT(E2Const::AVG_CPU_HZ/10);
|
||||
|
||||
|
||||
// The core of this Apple
|
||||
int Emulator::run()
|
||||
{
|
||||
int skip = CHECK_EVERY_CYCLE;
|
||||
Uint32 prev_ms = SDL_GetTicks();
|
||||
// While the user still wants to run this emulation...
|
||||
while (!this->quit)
|
||||
{
|
||||
// (Obligatory protection against NULL object pointer)
|
||||
if (this->timable)
|
||||
{
|
||||
this->timable->tick();
|
||||
// If the Apple ][ keyboard repeat is on (the REPT key is
|
||||
// down)...
|
||||
if (this->repeat)
|
||||
{
|
||||
// Count our way down to when the timer for the REPT key
|
||||
// fires off: 10Hz in terms of how many CPU cycles have gone
|
||||
// by
|
||||
--this->rept;
|
||||
// If it's time for the REPT key timer to fire (at long
|
||||
// last)...
|
||||
if (this->rept <= 0)
|
||||
{
|
||||
// ...reload the timer for the next firing 1/10 second from
|
||||
// now ( *reset* the timer )
|
||||
this->rept = CYCLES_PER_REPT;
|
||||
// If any other keys are actually being held down...
|
||||
if (this->keysDown > 0)
|
||||
{
|
||||
// ...REPEAT the most recent one that was pressed
|
||||
this->keypresses.push(this->lastKeyDown);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// People who have too many press releases should be referred to as
|
||||
// keyboards
|
||||
|
||||
--skip;
|
||||
// If skip has been decremented to zero...
|
||||
if (!skip)
|
||||
{
|
||||
// ...then it's time to drain away any piled-up user interaction
|
||||
// events that SDL has stored up for us
|
||||
// Reload the skip quantity
|
||||
skip = CHECK_EVERY_CYCLE;
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
// If SDL is going away...
|
||||
case SDL_QUIT:
|
||||
this->quit = true;
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
// If we're collecting a command line for changing any
|
||||
// of the configurables of the emulator...
|
||||
if (this->command)
|
||||
cmdKey(event.key);
|
||||
else
|
||||
// ...else we're collecting keypresses for the keyboard
|
||||
// emulation (and thus the Apple ][ emulation itself)
|
||||
dispatchKeypress(event.key);
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
// If we're collecting a command line for changing any
|
||||
// of the configurables of the emulator...
|
||||
if (this->command)
|
||||
{
|
||||
if (this->pendingCommandExit)
|
||||
{
|
||||
this->command = false;
|
||||
this->pendingCommandExit = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...else we're collecting keypresses for the keyboard
|
||||
// emulation (and thus the Apple ][ emulation itself)
|
||||
dispatchKeyUp(event.key);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If we're trying to run as slow as a real Apple ][...
|
||||
if (!this->fhyper.isHyper())
|
||||
{
|
||||
const int delta_ms = EXPECTED_MS-(SDL_GetTicks()-prev_ms);
|
||||
if (0 < delta_ms && delta_ms <= EXPECTED_MS)
|
||||
{
|
||||
SDL_Delay(delta_ms);
|
||||
}
|
||||
|
||||
}
|
||||
// Display the current estimate of the emulator's actual speed
|
||||
// performance
|
||||
this->screenImage.displayHz(CHECK_CYCLES_K/(SDL_GetTicks()-prev_ms));
|
||||
prev_ms = SDL_GetTicks();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Emulator::dispatchKeyUp(const SDL_KeyboardEvent& keyEvent)
|
||||
{
|
||||
unsigned char key = (unsigned char)(keyEvent.keysym.unicode & 0x7F);
|
||||
SDLKey sym = keyEvent.keysym.sym;
|
||||
SDLMod mod = keyEvent.keysym.mod;
|
||||
unsigned char scancode = keyEvent.keysym.scancode;
|
||||
// printf("key UP: %d sym: %d mod: %04X scn: %d\n",key,sym,mod,scancode);
|
||||
|
||||
if ((sym < 0x7F || sym == SDLK_LEFT || sym == SDLK_RIGHT) &&
|
||||
!(sym == SDLK_TAB || sym == SDLK_BACKQUOTE || sym == '[' || sym == '\\' || sym == SDLK_DELETE) &&
|
||||
!(sym == ']' && mod&KMOD_SHIFT))
|
||||
{
|
||||
--this->keysDown;
|
||||
}
|
||||
// ...else if this is the emulated REPT key on the Apple keyboard...
|
||||
else if (sym == SDLK_F10)
|
||||
{
|
||||
// ...stop repeating. The key has been released
|
||||
this->repeat = false;
|
||||
this->rept = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Take real-world keystrokes from SDL and filter them to emulate the
|
||||
// Apple ][ or Apple ][ plus keyboard
|
||||
void Emulator::dispatchKeypress(const SDL_KeyboardEvent& keyEvent)
|
||||
{
|
||||
unsigned char key = (unsigned char)(keyEvent.keysym.unicode & 0x7F);
|
||||
SDLKey sym = keyEvent.keysym.sym;
|
||||
SDLMod mod = keyEvent.keysym.mod;
|
||||
unsigned char scancode = keyEvent.keysym.scancode;
|
||||
|
||||
// printf("key DN: %d sym: %d mod: %04X scn: %d\n",key,sym,mod,scancode);
|
||||
|
||||
if ((sym < 0x7F || sym == SDLK_LEFT || sym == SDLK_RIGHT) &&
|
||||
!(sym == SDLK_TAB || sym == SDLK_BACKQUOTE || sym == '[' || sym == '\\' || sym == SDLK_DELETE) &&
|
||||
!(sym == ']' && mod&KMOD_SHIFT))
|
||||
{
|
||||
++this->keysDown;
|
||||
}
|
||||
|
||||
if (sym == SDLK_LEFT)
|
||||
{
|
||||
key = 8;
|
||||
}
|
||||
else if (sym == SDLK_RIGHT)
|
||||
{
|
||||
key = 21;
|
||||
}
|
||||
else if (sym == SDLK_PAUSE)
|
||||
{
|
||||
this->apple2.reset();
|
||||
return;
|
||||
}
|
||||
else if (sym == SDLK_INSERT)
|
||||
{
|
||||
// Feed input from the clipboard to the Apple keyboard
|
||||
std::string s = this->clip.getText();
|
||||
for (unsigned int i = 0; i < s.length(); ++i)
|
||||
{
|
||||
key = s[i];
|
||||
// TODO fix pasting line-endings
|
||||
if (key == '\n')
|
||||
key = '\r';
|
||||
if ('a' <= key && key <= 'z')
|
||||
{
|
||||
key -= 32;
|
||||
}
|
||||
this->keypresses.push(key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// ...else if this is the emulated REPT key on the Apple keyboard...
|
||||
else if (sym == SDLK_F10)
|
||||
{
|
||||
// ...start auto-repeat
|
||||
this->repeat = true;
|
||||
this->rept = CYCLES_PER_REPT;
|
||||
return;
|
||||
}
|
||||
// ...else if the user wants to run at full speed instead of emulating
|
||||
// the Apple's speed...
|
||||
else if (sym == SDLK_F11)
|
||||
{
|
||||
this->fhyper.toggleHyper();
|
||||
this->screenImage.toggleHyperLabel();
|
||||
return;
|
||||
}
|
||||
else if (sym == SDLK_F12)
|
||||
{
|
||||
this->buffered.toggleBuffered();
|
||||
this->screenImage.toggleKdbBufferLabel();
|
||||
return;
|
||||
}
|
||||
// ...else if the user has hit the rocker switch on the back of the Apple...
|
||||
else if (sym == SDLK_F1)
|
||||
{
|
||||
toggleComputerPower();
|
||||
return;
|
||||
}
|
||||
// ...else if the user wants to look at a different video display medium...
|
||||
else if (sym == SDLK_F2)
|
||||
{
|
||||
this->display.cycleType();
|
||||
this->screenImage.cycleDisplayLabel();
|
||||
return;
|
||||
}
|
||||
// ...else if the user wants to switch to/from full screen and an
|
||||
// individual application window...
|
||||
else if (sym == SDLK_F3)
|
||||
{
|
||||
this->screenImage.toggleFullScreen();
|
||||
this->screenImage.drawPower(this->timable==&this->apple2);
|
||||
return;
|
||||
}
|
||||
// ...else if the user wants to switch between the interlaced extension
|
||||
// of the display and the non-interlaced historically correct display...
|
||||
else if (sym == SDLK_F4)
|
||||
{
|
||||
this->display.toggleBleedDown();
|
||||
this->screenImage.toggleFillLinesLabel();
|
||||
return;
|
||||
}
|
||||
// ...else initiate command line entry at the bottom of the emulator window
|
||||
else if (sym == SDLK_F5)
|
||||
{
|
||||
this->command = true;
|
||||
this->screenImage.enterCommandMode();
|
||||
}
|
||||
// ...else exit the entire emulation
|
||||
else if (sym == SDLK_END)
|
||||
{
|
||||
this->quit = true;
|
||||
return;
|
||||
}
|
||||
// ...else save a screen shot
|
||||
else if (sym == SDLK_PRINT)
|
||||
{
|
||||
this->screenImage.saveBMP();
|
||||
}
|
||||
|
||||
// The unmodified Apple ][ hardware keyboard only generates upper-case
|
||||
if ('a' <= key && key <= 'z')
|
||||
{
|
||||
key -= 32;
|
||||
}
|
||||
|
||||
if ((mod&KMOD_SHIFT) && (mod&KMOD_CTRL) && sym == '2')
|
||||
{
|
||||
// Ctrl-Shift-2 == Ctrl-@ == NUL == ASCII: 0
|
||||
key = 0;
|
||||
}
|
||||
else if ((mod&KMOD_SHIFT) && (mod&KMOD_CTRL) && sym == ' ')
|
||||
{
|
||||
// Ctrl-Shift-Space is the same as Space
|
||||
key = ' ';
|
||||
}
|
||||
else if ((mod&KMOD_CTRL) && !(mod&KMOD_SHIFT) && SDLK_KP0 <= sym && sym <= SDLK_KP9)
|
||||
{
|
||||
// Control-only numeric keypad keys are converted to regular digit keys
|
||||
key = sym-SDLK_KP0+'0';
|
||||
}
|
||||
else if ((mod&KMOD_CTRL) && !(mod&KMOD_SHIFT) && (('0' <= sym && sym <= '9') || sym == '/' || sym == ' '))
|
||||
{
|
||||
// Control-only upon 0-9, / and space leaves them unchanged, the
|
||||
// same as unmodified
|
||||
key = sym;
|
||||
}
|
||||
else if (sym == ']')
|
||||
{
|
||||
if (mod&KMOD_SHIFT)
|
||||
{
|
||||
// ignore '}' (shift ']')
|
||||
return;
|
||||
}
|
||||
if (mod&KMOD_CTRL)
|
||||
{
|
||||
// Ctrl-] == ASCII: $1D
|
||||
key = 29;
|
||||
}
|
||||
}
|
||||
// ...else if this is one of the keys that can't be typed on an Apple ][
|
||||
// keyboard...
|
||||
else if (key == 0 || sym == SDLK_TAB || sym == SDLK_BACKQUOTE || sym == '[' || sym == '\\' || sym == SDLK_DELETE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// printf(" sending to apple as ascii------------------------------>%02X (%02X)\n",key,key|0x80);
|
||||
this->keypresses.push(key);
|
||||
this->lastKeyDown = key;
|
||||
}
|
||||
|
||||
// Collect and edit a command line typed at the bottom of the emulator
|
||||
// window
|
||||
void Emulator::cmdKey(const SDL_KeyboardEvent& keyEvent)
|
||||
{
|
||||
unsigned char key = (unsigned char)(keyEvent.keysym.unicode & 0x7F);
|
||||
SDLKey sym = keyEvent.keysym.sym;
|
||||
if (sym == SDLK_RETURN)
|
||||
{
|
||||
processCommand();
|
||||
}
|
||||
else if (sym == SDLK_ESCAPE)
|
||||
{
|
||||
cmdline.erase(cmdline.begin(),cmdline.end());
|
||||
processCommand();
|
||||
}
|
||||
else if (sym == SDLK_BACKSPACE)
|
||||
{
|
||||
if (cmdline.length())
|
||||
{
|
||||
cmdline.erase(cmdline.end()-1);
|
||||
this->screenImage.backspaceCommand();
|
||||
}
|
||||
}
|
||||
else if (sym == SDLK_INSERT)
|
||||
{
|
||||
std::string s = this->clip.getText();
|
||||
for (unsigned int i = 0; i < s.length(); ++i)
|
||||
{
|
||||
key = s[i];
|
||||
if (key == '\n' || key == '\r')
|
||||
{
|
||||
processCommand();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdline += key;
|
||||
this->screenImage.addkeyCommand(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (key)
|
||||
{
|
||||
cmdline += key;
|
||||
this->screenImage.addkeyCommand(key);
|
||||
}
|
||||
}
|
||||
|
||||
// Process a command line typed at the bottom of the emulator window
|
||||
void Emulator::processCommand()
|
||||
{
|
||||
this->screenImage.exitCommandMode();
|
||||
this->pendingCommandExit = true;
|
||||
|
||||
if (cmdline.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Config::parseLine(cmdline,this->apple2.ram,this->apple2.rom,this->apple2.slts,this->apple2.revision,this->screenImage,this->apple2.cassette);
|
||||
cmdline.erase(cmdline.begin(),cmdline.end());
|
||||
}
|
80
src/emulator.h
Normal file
80
src/emulator.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef EMULATOR_H
|
||||
#define EMULATOR_H
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "paddlebuttonstates.h"
|
||||
#include "apple2.h"
|
||||
#include "videostaticgenerator.h"
|
||||
#include "screenimage.h"
|
||||
#include "analogtv.h"
|
||||
#include "keyboardbuffermode.h"
|
||||
#include "hypermode.h"
|
||||
#include "clipboardhandler.h"
|
||||
|
||||
class Timable;
|
||||
class Config;
|
||||
struct SDL_KeyboardEvent;
|
||||
|
||||
class Emulator
|
||||
{
|
||||
PaddleButtonStates paddleButtonStates;
|
||||
KeypressQueue keypresses;
|
||||
|
||||
HyperMode fhyper;
|
||||
KeyboardBufferMode buffered;
|
||||
ScreenImage screenImage;
|
||||
AnalogTV display;
|
||||
VideoStaticGenerator videoStatic;
|
||||
Apple2 apple2;
|
||||
ClipboardHandler clip;
|
||||
|
||||
Timable* timable;
|
||||
|
||||
bool quit;
|
||||
bool repeat;
|
||||
int keysDown;
|
||||
int rept;
|
||||
unsigned char lastKeyDown;
|
||||
bool command;
|
||||
bool pendingCommandExit;
|
||||
std::string cmdline;
|
||||
|
||||
void dispatchKeypress(const SDL_KeyboardEvent& keyEvent);
|
||||
void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent);
|
||||
void cmdKey(const SDL_KeyboardEvent& keyEvent);
|
||||
void processCommand();
|
||||
|
||||
public:
|
||||
Emulator();
|
||||
virtual ~Emulator();
|
||||
|
||||
void config(Config& cfg);
|
||||
|
||||
virtual void init();
|
||||
|
||||
void powerOnComputer();
|
||||
void powerOffComputer();
|
||||
void toggleComputerPower();
|
||||
void cycleDisplayType();
|
||||
|
||||
virtual int run();
|
||||
};
|
||||
|
||||
#endif
|
60
src/firmwarecard.cpp
Normal file
60
src/firmwarecard.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "firmwarecard.h"
|
||||
#include "memory.h"
|
||||
|
||||
FirmwareCard::FirmwareCard(ScreenImage& gui, int slot):
|
||||
gui(gui),
|
||||
slot(slot),
|
||||
inhibitBankRom(false),
|
||||
inhibitF8Rom(false),
|
||||
inhibit(false),
|
||||
bankRom(0x10000-0xD000)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FirmwareCard::~FirmwareCard()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void FirmwareCard::ioBankRom(const unsigned short addr, unsigned char* const pb, const bool)
|
||||
{
|
||||
this->inhibit = false;
|
||||
if (addr < 0x2800)
|
||||
{
|
||||
if (this->inhibitBankRom)
|
||||
{
|
||||
*pb = this->bankRom.read(addr);
|
||||
this->inhibit = true;
|
||||
}
|
||||
}
|
||||
else if (0x2800 <= addr && addr < 0x3000)
|
||||
{
|
||||
if (this->inhibitF8Rom)
|
||||
{
|
||||
*pb = this->bankRom.read(addr);
|
||||
this->inhibit = true;
|
||||
}
|
||||
}
|
||||
}
|
73
src/firmwarecard.h
Normal file
73
src/firmwarecard.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef FIRMWARECARD_H
|
||||
#define FIRMWARECARD_H
|
||||
|
||||
#include "card.h"
|
||||
#include "memory.h"
|
||||
#include "screenimage.h"
|
||||
|
||||
class FirmwareCard : public Card
|
||||
{
|
||||
private:
|
||||
ScreenImage& gui;
|
||||
int slot;
|
||||
bool inhibitBankRom;
|
||||
bool inhibitF8Rom;
|
||||
bool inhibit;
|
||||
Memory bankRom;
|
||||
|
||||
public:
|
||||
FirmwareCard(ScreenImage& gui, int slot);
|
||||
~FirmwareCard();
|
||||
|
||||
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
|
||||
|
||||
virtual void reset()
|
||||
{
|
||||
this->inhibitBankRom = false;
|
||||
this->inhibitF8Rom = false;
|
||||
this->gui.setFirmCard(this->slot,this->inhibitBankRom,this->inhibitF8Rom);
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing)
|
||||
{
|
||||
this->inhibitBankRom = !(address & 1);
|
||||
this->inhibitF8Rom = (address & 2);
|
||||
this->gui.setFirmCard(this->slot,this->inhibitBankRom,this->inhibitF8Rom);
|
||||
return data;
|
||||
}
|
||||
|
||||
virtual void loadBankRom(const unsigned short base, std::istream& in)
|
||||
{
|
||||
this->bankRom.load(base,in);
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual bool inhibitMotherboardRom()
|
||||
{
|
||||
return this->inhibit;
|
||||
}
|
||||
|
||||
virtual std::string getName() { return "firmware "; }
|
||||
};
|
||||
|
||||
#endif
|
693
src/font3x5.h
Normal file
693
src/font3x5.h
Normal file
|
@ -0,0 +1,693 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define FONTW 4
|
||||
#define FONTH 6
|
||||
|
||||
static const char* font3x5 =
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"----"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
|
||||
"-@-@"
|
||||
"@@@@"
|
||||
"@-@-"
|
||||
"@@@@"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"-@@@"
|
||||
"@@--"
|
||||
"-@@-"
|
||||
"-@-@"
|
||||
"@@@-"
|
||||
"-@--"
|
||||
|
||||
"@-@-"
|
||||
"--@-"
|
||||
"-@--"
|
||||
"@---"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"@@-@"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"-@--"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
|
||||
"--@-"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"--@-"
|
||||
"----"
|
||||
|
||||
"@---"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"@---"
|
||||
"----"
|
||||
|
||||
"@--@"
|
||||
"-@@-"
|
||||
"@@@@"
|
||||
"-@@-"
|
||||
"@--@"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"-@--"
|
||||
"@@@-"
|
||||
"-@--"
|
||||
"----"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"-@--"
|
||||
"@---"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@@@-"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"--@-"
|
||||
"--@-"
|
||||
"-@--"
|
||||
"@---"
|
||||
"@---"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"@@@-"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"@@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"@@--"
|
||||
"--@-"
|
||||
"-@--"
|
||||
"@---"
|
||||
"@@@-"
|
||||
"----"
|
||||
|
||||
"@@--"
|
||||
"--@-"
|
||||
"@@--"
|
||||
"--@-"
|
||||
"@@--"
|
||||
"----"
|
||||
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@@@-"
|
||||
"--@-"
|
||||
"--@-"
|
||||
"----"
|
||||
|
||||
"@@@-"
|
||||
"@---"
|
||||
"@@--"
|
||||
"--@-"
|
||||
"@@--"
|
||||
"----"
|
||||
|
||||
"-@@-"
|
||||
"@---"
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"@@@-"
|
||||
"--@-"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"-@@-"
|
||||
"--@-"
|
||||
"@@--"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"-@--"
|
||||
"----"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"-@--"
|
||||
"----"
|
||||
"-@--"
|
||||
"@---"
|
||||
|
||||
"--@-"
|
||||
"-@--"
|
||||
"@---"
|
||||
"-@--"
|
||||
"--@-"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"@@@-"
|
||||
"----"
|
||||
"@@@-"
|
||||
"----"
|
||||
"----"
|
||||
|
||||
"@---"
|
||||
"-@--"
|
||||
"--@-"
|
||||
"-@--"
|
||||
"@---"
|
||||
"----"
|
||||
|
||||
"@@--"
|
||||
"--@-"
|
||||
"-@--"
|
||||
"----"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"-@@-"
|
||||
"@-@@"
|
||||
"@-@@"
|
||||
"@---"
|
||||
"-@@-"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"@@@-"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@@--"
|
||||
"----"
|
||||
|
||||
"-@@-"
|
||||
"@---"
|
||||
"@---"
|
||||
"@---"
|
||||
"-@@-"
|
||||
"----"
|
||||
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@@--"
|
||||
"----"
|
||||
|
||||
"@@@-"
|
||||
"@---"
|
||||
"@@@-"
|
||||
"@---"
|
||||
"@@@-"
|
||||
"----"
|
||||
|
||||
"@@@-"
|
||||
"@---"
|
||||
"@@--"
|
||||
"@---"
|
||||
"@---"
|
||||
"----"
|
||||
|
||||
"-@@-"
|
||||
"@---"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"-@@-"
|
||||
"----"
|
||||
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@@@-"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"--@-"
|
||||
"--@-"
|
||||
"--@-"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"@---"
|
||||
"@---"
|
||||
"@---"
|
||||
"@---"
|
||||
"@@@-"
|
||||
"----"
|
||||
|
||||
"@-@-"
|
||||
"@@@-"
|
||||
"@@@-"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@@--"
|
||||
"@---"
|
||||
"@---"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@@@-"
|
||||
"-@@-"
|
||||
"----"
|
||||
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"-@@-"
|
||||
"@---"
|
||||
"-@--"
|
||||
"--@-"
|
||||
"@@--"
|
||||
"----"
|
||||
|
||||
"@@@-"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@@@-"
|
||||
"----"
|
||||
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"@@@-"
|
||||
"@@@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"@@@-"
|
||||
"--@-"
|
||||
"-@--"
|
||||
"@---"
|
||||
"@@@-"
|
||||
"----"
|
||||
|
||||
"-@@-"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@@-"
|
||||
"----"
|
||||
|
||||
"@---"
|
||||
"@---"
|
||||
"-@--"
|
||||
"--@-"
|
||||
"--@-"
|
||||
"----"
|
||||
|
||||
"@@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"@@--"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"@@@-"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"--@-"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"-@@-"
|
||||
"@-@-"
|
||||
"-@@-"
|
||||
"----"
|
||||
|
||||
"@---"
|
||||
"@---"
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@@--"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"-@@-"
|
||||
"@---"
|
||||
"-@@-"
|
||||
"----"
|
||||
|
||||
"--@-"
|
||||
"--@-"
|
||||
"-@@-"
|
||||
"@-@-"
|
||||
"-@@-"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@@@-"
|
||||
"@@--"
|
||||
"-@@-"
|
||||
"----"
|
||||
|
||||
"--@-"
|
||||
"-@--"
|
||||
"@@@-"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"-@@-"
|
||||
"@-@-"
|
||||
"-@@-"
|
||||
"@@--"
|
||||
|
||||
"@---"
|
||||
"@---"
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"----"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"----"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"@---"
|
||||
|
||||
"@---"
|
||||
"@---"
|
||||
"@-@-"
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@@@-"
|
||||
"@@@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@@--"
|
||||
"@-@-"
|
||||
"@@--"
|
||||
"@---"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"-@@-"
|
||||
"@-@-"
|
||||
"-@@-"
|
||||
"--@-"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@@@-"
|
||||
"@---"
|
||||
"@---"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"-@@-"
|
||||
"-@--"
|
||||
"@@--"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"-@--"
|
||||
"@@@-"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"-@@-"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@-@-"
|
||||
"@@@-"
|
||||
"@@@-"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"@-@-"
|
||||
"----"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@-@-"
|
||||
"@-@-"
|
||||
"-@--"
|
||||
"@---"
|
||||
|
||||
"----"
|
||||
"----"
|
||||
"@@--"
|
||||
"-@--"
|
||||
"-@@-"
|
||||
"----"
|
||||
|
||||
"--@-"
|
||||
"-@--"
|
||||
"@@--"
|
||||
"-@--"
|
||||
"--@-"
|
||||
"----"
|
||||
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
"-@--"
|
||||
|
||||
"@---"
|
||||
"-@--"
|
||||
"-@@-"
|
||||
"-@--"
|
||||
"@---"
|
||||
"----"
|
||||
|
||||
"-@-@"
|
||||
"@-@-"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
"----"
|
||||
|
||||
"@@@@"
|
||||
"@@@@"
|
||||
"@@@@"
|
||||
"@@@@"
|
||||
"@@@@"
|
||||
"@@@@"
|
||||
;
|
50
src/gui.cpp
Normal file
50
src/gui.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gui.h"
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
// Create, initialize, and cable together the UI objects to serve this
|
||||
// program
|
||||
GUI::GUI()
|
||||
{
|
||||
const int result = SDL_Init(SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
throw GUI::NotInitException();
|
||||
}
|
||||
|
||||
SDL_EnableUNICODE(1);
|
||||
SDL_ShowCursor(0);
|
||||
SDL_EnableKeyRepeat(0,0);
|
||||
}
|
||||
|
||||
GUI::~GUI()
|
||||
{
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
GUI::NotInitException::NotInitException() :
|
||||
runtime_error("Unable to initialize SDL")
|
||||
{
|
||||
SDL_GetError();
|
||||
}
|
38
src/gui.h
Normal file
38
src/gui.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef GUI_H
|
||||
#define GUI_H
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
class GUI
|
||||
{
|
||||
public:
|
||||
GUI();
|
||||
~GUI();
|
||||
|
||||
class NotInitException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
NotInitException();
|
||||
virtual ~NotInitException() throw () {}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
18
src/hypermode.cpp
Normal file
18
src/hypermode.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "hypermode.h"
|
45
src/hypermode.h
Normal file
45
src/hypermode.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef HYPERMODE_H
|
||||
#define HYPERMODE_H
|
||||
|
||||
class HyperMode
|
||||
{
|
||||
private:
|
||||
bool fhyper;
|
||||
|
||||
public:
|
||||
HyperMode(): fhyper(false) { }
|
||||
~HyperMode() { }
|
||||
bool isHyper()
|
||||
{
|
||||
return this->fhyper;
|
||||
}
|
||||
|
||||
void setHyper(bool isHyper)
|
||||
{
|
||||
this->fhyper = isHyper;
|
||||
}
|
||||
|
||||
void toggleHyper()
|
||||
{
|
||||
this->fhyper = !this->fhyper;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
73
src/keyboard.cpp
Normal file
73
src/keyboard.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "keyboard.h"
|
||||
#include "hypermode.h"
|
||||
#include "keyboardbuffermode.h"
|
||||
|
||||
Keyboard::Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered):
|
||||
keys(q),
|
||||
fhyper(fhyper),
|
||||
buffered(buffered),
|
||||
cGet(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Keyboard::clear()
|
||||
{
|
||||
this->latch &= 0x7F;
|
||||
}
|
||||
|
||||
unsigned char Keyboard::get()
|
||||
{
|
||||
waitIfTooFast();
|
||||
if (!this->buffered.isBuffered() || !(this->latch & 0x80))
|
||||
{
|
||||
if (!this->keys.empty())
|
||||
{
|
||||
this->latch = this->keys.front() | 0x80;
|
||||
this->keys.pop();
|
||||
}
|
||||
}
|
||||
return this->latch;
|
||||
}
|
||||
|
||||
void Keyboard::waitIfTooFast()
|
||||
{
|
||||
if (this->fhyper.isHyper())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
++this->cGet;
|
||||
if (!this->cGet)
|
||||
{
|
||||
if (SDL_GetTicks() - this->lastGet <= 1000)
|
||||
{
|
||||
/*
|
||||
* Check every 256 gets to see if they are
|
||||
* happening too fast (within one second).
|
||||
* If so, it means we are probably just
|
||||
* looping waiting for a keypress, so
|
||||
* wait a millisecond (or so) just to
|
||||
* prevent us from using 100% of CPU time.
|
||||
*/
|
||||
SDL_Delay(1);
|
||||
}
|
||||
}
|
||||
this->lastGet = SDL_GetTicks();
|
||||
}
|
48
src/keyboard.h
Normal file
48
src/keyboard.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef KEYBOARD_H
|
||||
#define KEYBOARD_H
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
#include <queue>
|
||||
|
||||
typedef std::queue<unsigned char> KeypressQueue;
|
||||
|
||||
class HyperMode;
|
||||
class KeyboardBufferMode;
|
||||
|
||||
class Keyboard
|
||||
{
|
||||
private:
|
||||
KeypressQueue& keys;
|
||||
HyperMode& fhyper;
|
||||
KeyboardBufferMode& buffered;
|
||||
|
||||
unsigned char latch;
|
||||
unsigned char cGet;
|
||||
Uint32 lastGet;
|
||||
|
||||
void waitIfTooFast();
|
||||
|
||||
public:
|
||||
Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered);
|
||||
void clear();
|
||||
unsigned char get();
|
||||
};
|
||||
|
||||
#endif
|
18
src/keyboardbuffermode.cpp
Normal file
18
src/keyboardbuffermode.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "keyboardbuffermode.h"
|
46
src/keyboardbuffermode.h
Normal file
46
src/keyboardbuffermode.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef KEYBOARDBUFFERMODE_H
|
||||
#define KEYBOARDBUFFERMODE_H
|
||||
|
||||
class KeyboardBufferMode
|
||||
{
|
||||
private:
|
||||
bool buffered;
|
||||
|
||||
public:
|
||||
KeyboardBufferMode(): buffered(true) { }
|
||||
~KeyboardBufferMode() { }
|
||||
|
||||
bool isBuffered()
|
||||
{
|
||||
return this->buffered;
|
||||
}
|
||||
|
||||
void setBuffered(bool buffered)
|
||||
{
|
||||
this->buffered = buffered;
|
||||
}
|
||||
|
||||
void toggleBuffered()
|
||||
{
|
||||
this->buffered = !this->buffered;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
95
src/languagecard.cpp
Normal file
95
src/languagecard.cpp
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "languagecard.h"
|
||||
#include "screenimage.h"
|
||||
|
||||
LanguageCard::LanguageCard(ScreenImage& gui, int slot):
|
||||
gui(gui),
|
||||
slot(slot),
|
||||
inhibit(false),
|
||||
ramTop(0x10000-0xE000),
|
||||
bank(1),
|
||||
readEnable(false),
|
||||
writeEnable(true),
|
||||
writeCount(0)
|
||||
{
|
||||
this->ramBank.push_back(new Memory(0xE000-0xD000));
|
||||
this->ramBank.push_back(new Memory(0xE000-0xD000));
|
||||
}
|
||||
|
||||
LanguageCard::~LanguageCard()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unsigned char LanguageCard::io(const unsigned short address, const unsigned char data, const bool writing)
|
||||
{
|
||||
if ((address & 1) && !writing)
|
||||
{
|
||||
++this->writeCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->writeCount = 0;
|
||||
}
|
||||
if (this->writeCount > 1)
|
||||
{
|
||||
this->writeEnable = true;
|
||||
}
|
||||
if (!(address & 1))
|
||||
{
|
||||
this->writeEnable = false;
|
||||
}
|
||||
|
||||
const int r = address & 3;
|
||||
this->readEnable = (r==0 || r==3);
|
||||
|
||||
this->bank = !(address & 8);
|
||||
|
||||
this->gui.setLangCard(this->slot,this->readEnable,this->writeEnable,this->bank);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void LanguageCard::ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write)
|
||||
{
|
||||
this->inhibit = false;
|
||||
if (this->readEnable && !write)
|
||||
{
|
||||
if (addr < 0x1000)
|
||||
{
|
||||
*pb = this->ramBank[this->bank]->read(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pb = this->ramTop.read(addr-0x1000);
|
||||
}
|
||||
this->inhibit = true;
|
||||
}
|
||||
else if (this->writeEnable && write)
|
||||
{
|
||||
if (addr < 0x1000)
|
||||
{
|
||||
this->ramBank[this->bank]->write(addr,*pb);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->ramTop.write(addr-0x1000,*pb);
|
||||
}
|
||||
}
|
||||
}
|
51
src/languagecard.h
Normal file
51
src/languagecard.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef LANGUAGECARD_H
|
||||
#define LANGUAGECARD_H
|
||||
|
||||
#include "card.h"
|
||||
#include "memory.h"
|
||||
#include <vector>
|
||||
|
||||
class ScreenImage;
|
||||
|
||||
class LanguageCard : public Card
|
||||
{
|
||||
private:
|
||||
ScreenImage& gui;
|
||||
int slot;
|
||||
bool inhibit;
|
||||
std::vector<Memory*> ramBank;
|
||||
Memory ramTop;
|
||||
unsigned char bank;
|
||||
bool readEnable;
|
||||
bool writeEnable;
|
||||
unsigned char writeCount;
|
||||
|
||||
public:
|
||||
LanguageCard(ScreenImage& gui, int slot);
|
||||
~LanguageCard();
|
||||
|
||||
virtual void reset() { /* does nothing */ }
|
||||
virtual bool inhibitMotherboardRom() { return this->inhibit; }
|
||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
|
||||
virtual std::string getName() { return "language W B2"; }
|
||||
};
|
||||
|
||||
#endif
|
18
src/lowpass_1_5_mhz.cpp
Normal file
18
src/lowpass_1_5_mhz.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "lowpass_1_5_mhz.h"
|
51
src/lowpass_1_5_mhz.h
Normal file
51
src/lowpass_1_5_mhz.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef LOWPASS_1_5_MHZ_H
|
||||
#define LOWPASS_1_5_MHZ_H
|
||||
|
||||
/*
|
||||
Generated by the utility at http://www-users.cs.york.ac.uk/~fisher/mkfilter
|
||||
then hand modified by Chris Mosher.
|
||||
*/
|
||||
class Lowpass_1_5_MHz
|
||||
{
|
||||
public:
|
||||
Lowpass_1_5_MHz()
|
||||
{
|
||||
x[0] = x[1] = x[2] = 0;
|
||||
y[0] = y[1] = y[2] = y[3] = y[4] = 0;
|
||||
}
|
||||
~Lowpass_1_5_MHz() { }
|
||||
|
||||
int x[3];
|
||||
int y[5];
|
||||
|
||||
int next(const int v)
|
||||
{
|
||||
x[0] = x[1]; x[1] = x[2];
|
||||
x[2] = v >> 3;
|
||||
|
||||
y[0] = y[1]; y[1] = y[2]; y[2] = y[3]; y[3] = y[4];
|
||||
y[4] = x[0]+x[2]+(y[1]>>2)-y[2]+y[3]+(y[3]>>1);
|
||||
|
||||
return y[4];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
18
src/lowpass_3_58_mhz.cpp
Normal file
18
src/lowpass_3_58_mhz.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "lowpass_3_58_mhz.h"
|
50
src/lowpass_3_58_mhz.h
Normal file
50
src/lowpass_3_58_mhz.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef LOWPASS_3_58_MHZ_H
|
||||
#define LOWPASS_3_58_MHZ_H
|
||||
|
||||
/*
|
||||
Generated by the utility at http://www-users.cs.york.ac.uk/~fisher/mkfilter
|
||||
then hand modified by Chris Mosher.
|
||||
*/
|
||||
class Lowpass_3_58_MHz
|
||||
{
|
||||
int x[5];
|
||||
int y[5];
|
||||
|
||||
public:
|
||||
Lowpass_3_58_MHz()
|
||||
{
|
||||
x[0] = x[1] = x[2] = x[3] = x[4] = 0;
|
||||
y[0] = y[1] = y[2] = y[3] = y[4] = 0;
|
||||
}
|
||||
~Lowpass_3_58_MHz() { }
|
||||
|
||||
int next(const int v)
|
||||
{
|
||||
x[0] = x[1]; x[1] = x[2]; x[2] = x[3]; x[3] = x[4];
|
||||
x[4] = v/6;
|
||||
|
||||
y[0] = y[1]; y[1] = y[2]; y[2] = y[3]; y[3] = y[4];
|
||||
y[4] = x[0]+x[4]+((x[1]+x[2]+x[3])<<1)-(y[3]>>2);
|
||||
|
||||
return y[4];
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
68
src/main.cpp
Normal file
68
src/main.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "emulator.h"
|
||||
#include "configep2.h"
|
||||
#include "gui.h"
|
||||
#include "e2const.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static int run(const std::string& config_file)
|
||||
{
|
||||
GUI gui;
|
||||
|
||||
std::auto_ptr<Emulator> emu(new Emulator());
|
||||
|
||||
Config cfg(config_file);
|
||||
emu->config(cfg);
|
||||
|
||||
emu->init();
|
||||
|
||||
return emu->run();
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc > 2)
|
||||
{
|
||||
throw std::runtime_error("usage: epple2 [config-file]" );
|
||||
}
|
||||
|
||||
int x = E2Const::test();
|
||||
if (x != -1)
|
||||
{
|
||||
std::cerr << x << std::endl;
|
||||
throw std::runtime_error("bad constant in e2const.h" );
|
||||
}
|
||||
|
||||
std::string config_file;
|
||||
if (argc > 1)
|
||||
{
|
||||
config_file = argv[1];
|
||||
}
|
||||
|
||||
return run(config_file);
|
||||
}
|
50
src/memory.cpp
Normal file
50
src/memory.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "memory.h"
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <istream>
|
||||
#include "raminitializer.h"
|
||||
|
||||
const int Memory::CLEAR_VALUE(0);
|
||||
|
||||
Memory::Memory(const size_t n):
|
||||
bytes(n)
|
||||
{
|
||||
}
|
||||
|
||||
void Memory::clear()
|
||||
{
|
||||
std::fill(this->bytes.begin(),this->bytes.end(),CLEAR_VALUE);
|
||||
}
|
||||
|
||||
void Memory::powerOn()
|
||||
{
|
||||
RAMInitializer initRam(*this);
|
||||
initRam.init();
|
||||
}
|
||||
|
||||
void Memory::powerOff()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void Memory::load(const unsigned short base, std::istream& in)
|
||||
{
|
||||
in.read((char*)&this->bytes[base],this->bytes.size()-base);
|
||||
}
|
53
src/memory.h
Normal file
53
src/memory.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef MEMORY_H
|
||||
#define MEMORY_H
|
||||
|
||||
#include <vector>
|
||||
#include <istream>
|
||||
|
||||
class Memory
|
||||
{
|
||||
private:
|
||||
std::vector<unsigned char> bytes;
|
||||
static const int CLEAR_VALUE;
|
||||
|
||||
public:
|
||||
Memory(const size_t n);
|
||||
size_t size() const
|
||||
{
|
||||
return this->bytes.size();
|
||||
}
|
||||
|
||||
unsigned char read(const unsigned short address) const
|
||||
{
|
||||
return this->bytes[address];
|
||||
}
|
||||
|
||||
void write(const unsigned short address, const unsigned char data)
|
||||
{
|
||||
this->bytes[address] = data;
|
||||
}
|
||||
|
||||
void clear();
|
||||
void powerOn();
|
||||
void powerOff();
|
||||
void load(const unsigned short base, std::istream& in);
|
||||
};
|
||||
|
||||
#endif
|
44
src/paddlebuttonstates.cpp
Normal file
44
src/paddlebuttonstates.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "paddlebuttonstates.h"
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
const int PaddleButtonStates::PADDLE_COUNT(3);
|
||||
|
||||
PaddleButtonStates::PaddleButtonStates()
|
||||
{
|
||||
}
|
||||
|
||||
PaddleButtonStates::~PaddleButtonStates()
|
||||
{
|
||||
}
|
||||
|
||||
bool PaddleButtonStates::isDown(const int paddle)
|
||||
{
|
||||
if (paddle < 0 || PADDLE_COUNT <= paddle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
unsigned char btn = SDL_GetMouseState(0,0);
|
||||
if (paddle==0)
|
||||
return btn&SDL_BUTTON_LMASK;
|
||||
if (paddle==1)
|
||||
return btn&SDL_BUTTON_RMASK;
|
||||
return btn&SDL_BUTTON_MMASK;
|
||||
}
|
33
src/paddlebuttonstates.h
Normal file
33
src/paddlebuttonstates.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PADDLEBUTTONSTATES_H
|
||||
#define PADDLEBUTTONSTATES_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
class PaddleButtonStates
|
||||
{
|
||||
static const int PADDLE_COUNT;
|
||||
|
||||
public:
|
||||
PaddleButtonStates();
|
||||
~PaddleButtonStates();
|
||||
bool isDown(const int paddle);
|
||||
};
|
||||
|
||||
#endif
|
93
src/paddles.cpp
Normal file
93
src/paddles.cpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "e2const.h"
|
||||
#include "paddles.h"
|
||||
#include <SDL/SDL.h>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
|
||||
|
||||
Paddles::Paddles():
|
||||
rTick(PADDLE_COUNT)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Paddles::~Paddles()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Paddles::tick()
|
||||
{
|
||||
for (int paddle = 0; paddle < PADDLE_COUNT; ++paddle)
|
||||
{
|
||||
if (this->rTick[paddle] > 0)
|
||||
--this->rTick[paddle];
|
||||
}
|
||||
}
|
||||
|
||||
void Paddles::startTimers()
|
||||
{
|
||||
try
|
||||
{
|
||||
tryStartPaddleTimers();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Warning: cannot start paddle timers; mouse will not function as paddles." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Paddles::tryStartPaddleTimers()
|
||||
{
|
||||
int x, y;
|
||||
SDL_GetMouseState(&x,&y);
|
||||
|
||||
double pMin = 0;
|
||||
double pMax = 500;
|
||||
x = (int)((x-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5);
|
||||
y = (int)((y-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5);
|
||||
|
||||
if (isTimedOut(0))
|
||||
this->rTick[0] = x;
|
||||
if (isTimedOut(1))
|
||||
this->rTick[1] = y;
|
||||
|
||||
/*
|
||||
Here we emulate having 4700 ohm across pins 7 and 1
|
||||
of the game controller, and a 47Kohm resistor acros
|
||||
pins 11 and 1, to give cheap real-time clocks at
|
||||
paddles 2 and 3. Paddle 2 is the 100 microsecond reference,
|
||||
and paddle 3 is the 1 millisecond reference. This is
|
||||
described in U.A.2, p. 7-33.
|
||||
*/
|
||||
if (isTimedOut(2))
|
||||
this->rTick[2] = E2Const::AVG_CPU_HZ/10000; // was 90, but why?
|
||||
if (isTimedOut(3))
|
||||
this->rTick[3] = E2Const::AVG_CPU_HZ/1000;
|
||||
}
|
||||
|
||||
bool Paddles::isTimedOut(const int paddle)
|
||||
{
|
||||
if (paddle < 0 || PADDLE_COUNT <= paddle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return this->rTick[paddle] <= 0;
|
||||
}
|
41
src/paddles.h
Normal file
41
src/paddles.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PADDLES_H
|
||||
#define PADDLES_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Paddles
|
||||
{
|
||||
private:
|
||||
std::vector<int> rTick;
|
||||
|
||||
enum { PADDLE_COUNT = 4 };
|
||||
enum { PADDLE_CYCLES = 2805 }; // TODO: document where PADDLE_CYCLES==2805 came from
|
||||
|
||||
void tryStartPaddleTimers();
|
||||
|
||||
public:
|
||||
Paddles();
|
||||
~Paddles();
|
||||
void tick();
|
||||
void startTimers();
|
||||
bool isTimedOut(const int paddle);
|
||||
};
|
||||
|
||||
#endif
|
327
src/picturegenerator.cpp
Normal file
327
src/picturegenerator.cpp
Normal file
|
@ -0,0 +1,327 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "picturegenerator.h"
|
||||
#include "analogtv.h"
|
||||
#include "videomode.h"
|
||||
#include "applentsc.h"
|
||||
#include "e2const.h"
|
||||
|
||||
PictureGenerator::PictureGenerator(AnalogTV& display, VideoMode& mode, const int& revision):
|
||||
display(display), mode(mode), itestsig(testsig), itestsiglim(testsig+AppleNTSC::SIGNAL_LEN),
|
||||
VISIBLE_X_OFFSET(E2Const::BYTES_PER_ROW-E2Const::VISIBLE_BYTES_PER_ROW),
|
||||
revision(revision)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PictureGenerator::~PictureGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void PictureGenerator::powerOn()
|
||||
{
|
||||
this->hpos = 0;
|
||||
this->line = 0;
|
||||
this->display.signal = this->testsig;
|
||||
this->itestsig = this->testsig;
|
||||
}
|
||||
|
||||
void inline PictureGenerator::shiftLoRes()
|
||||
{
|
||||
/*
|
||||
* For byte ABCDEFGH in register, perform
|
||||
* the following 4-bit end-around shifts:
|
||||
*
|
||||
* +---<----+ +---<----+
|
||||
* | | | |
|
||||
* +->ABCD->+ +->EFGH->+
|
||||
*
|
||||
* Therefore:
|
||||
*
|
||||
* ABCDEFGH --> DABCHEFG
|
||||
*/
|
||||
|
||||
unsigned char rot_bits = this->latchGraphics & 0x11;
|
||||
// 000D000H
|
||||
rot_bits <<= 3;
|
||||
// D000H000
|
||||
|
||||
this->latchGraphics &= 0xEE;
|
||||
// ABC0EFG0
|
||||
this->latchGraphics >>= 1;
|
||||
// 0ABC0EFG
|
||||
this->latchGraphics |= rot_bits;
|
||||
// DABCHEFG
|
||||
}
|
||||
|
||||
void inline PictureGenerator::shiftHiRes()
|
||||
{
|
||||
/*
|
||||
* For byte ABCDEFGH in register, perform
|
||||
* the following shift:
|
||||
*
|
||||
* +---<----+
|
||||
* | |
|
||||
* +->ABCD->+--->EFGH->
|
||||
*
|
||||
* Therefore:
|
||||
*
|
||||
* ABCDEFGH --> DABCDEFG
|
||||
*/
|
||||
|
||||
unsigned char rot_bits = this->latchGraphics & 0x10;
|
||||
// 000D0000
|
||||
rot_bits <<= 3;
|
||||
// D0000000
|
||||
|
||||
this->latchGraphics >>= 1;
|
||||
// 0ABCDEFG
|
||||
this->latchGraphics |= rot_bits;
|
||||
// DABCDEFG
|
||||
}
|
||||
|
||||
void inline PictureGenerator::shiftText()
|
||||
{
|
||||
this->latchText >>= 1;
|
||||
}
|
||||
|
||||
bool inline PictureGenerator::getTextBit()
|
||||
{
|
||||
return this->latchText & 1;
|
||||
}
|
||||
|
||||
bool inline PictureGenerator::getHiResBit()
|
||||
{
|
||||
return this->latchGraphics & 1;
|
||||
}
|
||||
|
||||
bool inline PictureGenerator::getLoResBit(const bool odd, const bool vc)
|
||||
{
|
||||
const int nibble = (this->latchGraphics >> (vc ? 4 : 0)) & 0x0F;
|
||||
return (nibble >> (odd ? 2 : 0)) & 1;
|
||||
}
|
||||
|
||||
void inline PictureGenerator::loadGraphics(const unsigned char value)
|
||||
{
|
||||
this->latchGraphics = value;
|
||||
this->d7 = this->latchGraphics & 0x80;
|
||||
}
|
||||
|
||||
void inline PictureGenerator::loadText(const int value)
|
||||
{
|
||||
this->latchText = value;
|
||||
}
|
||||
|
||||
// TODO can we hand-optimize the main picture generator algorithm any more?
|
||||
// Note that the innermost loop (which calls writeVideoSignal) has to execute
|
||||
// at 14MHz, in order to maintain authentic Apple ][ speed.
|
||||
void PictureGenerator::tick(const int t, const unsigned char rowToPlot)
|
||||
{
|
||||
const bool isText(this->mode.isDisplayingText(t));
|
||||
const bool isHiRes(this->mode.isHiRes());
|
||||
|
||||
signed char* is = this->itestsig;
|
||||
|
||||
if (isText)
|
||||
loadText(rowToPlot);
|
||||
else
|
||||
loadGraphics(rowToPlot);
|
||||
|
||||
if (t==0)
|
||||
{
|
||||
this->line = 0;
|
||||
}
|
||||
|
||||
int cycles = E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE;
|
||||
if (this->hpos == E2Const::HORIZ_CYCLES-1)
|
||||
{
|
||||
cycles += E2Const::EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE;
|
||||
}
|
||||
|
||||
// hi-res half-pixel shift:
|
||||
const bool shift = !isText && isHiRes && this->d7 && this->line < E2Const::VISIBLE_ROWS_PER_FIELD && !(this->hpos < VISIBLE_X_OFFSET) && this->revision > 0;
|
||||
const bool showLastHiRes = shift && this->lasthires;
|
||||
|
||||
int xtra(0);
|
||||
if (shift)
|
||||
{
|
||||
--cycles;
|
||||
++xtra;
|
||||
}
|
||||
const int firstBlankedCycle(E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE-xtra);
|
||||
|
||||
int hcycle(this->hpos*E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE);
|
||||
const bool lineVis(this->line < E2Const::VISIBLE_ROWS_PER_FIELD);
|
||||
const bool hVis(this->hpos >= VISIBLE_X_OFFSET);
|
||||
for (int cycle(0); cycle < cycles-1; ++cycle)
|
||||
{
|
||||
const bool bit = shiftLatch(t,cycle,isText,isHiRes);
|
||||
is = writeVideoSignal(shift,showLastHiRes,firstBlankedCycle,cycle,hcycle,bit,lineVis,hVis,is);
|
||||
++hcycle;
|
||||
}
|
||||
// optimization: pull the last iteration of the loop out, so we don't getHiResBit every time
|
||||
{
|
||||
this->lasthires = getHiResBit(); // save it for the next plotted byte, just in case we need it
|
||||
const int cycle = cycles-1;
|
||||
const bool bit = shiftLatch(t,cycle,isText,isHiRes);
|
||||
is = writeVideoSignal(shift,showLastHiRes,firstBlankedCycle,cycle,hcycle,bit,lineVis,hVis,is);
|
||||
}
|
||||
|
||||
this->itestsig = is;
|
||||
|
||||
++this->hpos;
|
||||
if (this->hpos >= E2Const::HORIZ_CYCLES)
|
||||
{
|
||||
this->hpos = 0;
|
||||
++this->line;
|
||||
if (this->itestsig >= this->itestsiglim)
|
||||
{
|
||||
this->itestsig = this->testsig;
|
||||
this->display.drawCurrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool inline PictureGenerator::shiftLatch(const int t, const int cycle, const bool isText, const bool isHiRes)
|
||||
{
|
||||
bool bit;
|
||||
if (isText)
|
||||
{
|
||||
bit = getTextBit();
|
||||
if (cycle & 1) // @ 7MHz
|
||||
{
|
||||
shiftText();
|
||||
}
|
||||
}
|
||||
else if (isHiRes)
|
||||
{
|
||||
bit = getHiResBit();
|
||||
if (cycle & 1) // @ 7MHz
|
||||
{
|
||||
shiftHiRes();
|
||||
}
|
||||
}
|
||||
else // LO-RES
|
||||
{
|
||||
const int y = t / E2Const::BYTES_PER_ROW;
|
||||
bit = getLoResBit((t & 1) == (this->line & 1), y & 4);
|
||||
shiftLoRes();
|
||||
}
|
||||
return bit;
|
||||
}
|
||||
|
||||
inline signed char* PictureGenerator::writeVideoSignal(const bool shift, const bool showLastHiRes, const int firstBlankedCycle, const int cycle, const int hcycle, const bool bit, const bool lineVis, const bool hVis, signed char* is)
|
||||
{
|
||||
if (shift && !cycle)
|
||||
{
|
||||
*is++ = showLastHiRes ? AppleNTSC::WHITE_LEVEL : AppleNTSC::BLANK_LEVEL;
|
||||
}
|
||||
|
||||
signed char sig;
|
||||
if (lineVis)
|
||||
{
|
||||
if (hVis)
|
||||
{
|
||||
if (bit && cycle < firstBlankedCycle)
|
||||
{
|
||||
sig = AppleNTSC::WHITE_LEVEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
sig = AppleNTSC::BLANK_LEVEL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig = hbl(hcycle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sig = vbl(hcycle);
|
||||
}
|
||||
*is++ = sig;
|
||||
return is;
|
||||
}
|
||||
|
||||
// TODO Just to be extremely accurate, fix picture signal values during HBL and VBL
|
||||
// (note that they vary by motherboard revision... there is a whole section in U.A.2)
|
||||
signed char inline PictureGenerator::vbl(const int hcycle)
|
||||
{
|
||||
signed char sig;
|
||||
if (224 <= this->line && this->line < 240) // VSYNC // TODO symbolize constants
|
||||
{
|
||||
sig = AppleNTSC::SYNC_LEVEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AppleNTSC::SYNC_START <= hcycle && hcycle < AppleNTSC::BP_START)
|
||||
{
|
||||
sig = AppleNTSC::SYNC_LEVEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
sig = AppleNTSC::BLANK_LEVEL;
|
||||
}
|
||||
}
|
||||
return sig;
|
||||
}
|
||||
|
||||
|
||||
// Set up the color burst signal.
|
||||
// TODO confirm that color burst signal phase is correct
|
||||
// Note, I believe this is the correct phase. The only other
|
||||
// possible configuration would be +10,-10,-10,+10. Can anyone confirm
|
||||
// that 0,-20,0,+20 gives the correct phase? By eye, it seems
|
||||
// +10,-10,-10,+10 makes brown look too green, but 0,-20,0,+20
|
||||
// makes hi-res blue look too light.
|
||||
// Note that this color burst signal only affects "old TV" mode;
|
||||
// the other color modes use A2ColorsObserved.
|
||||
const signed char PictureGenerator::lutCB[] =
|
||||
{
|
||||
0,
|
||||
-AppleNTSC::CB_LEVEL,
|
||||
0,
|
||||
+AppleNTSC::CB_LEVEL,
|
||||
};
|
||||
|
||||
signed char inline PictureGenerator::hbl(const int hcycle)
|
||||
{
|
||||
signed char cb;
|
||||
if (AppleNTSC::CB_START <= hcycle && hcycle < AppleNTSC::CB_END)
|
||||
{
|
||||
if (this->mode.isText() && this->revision > 0)
|
||||
{
|
||||
cb = AppleNTSC::BLANK_LEVEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
cb = lutCB[(hcycle-AppleNTSC::CB_START)%4];
|
||||
}
|
||||
}
|
||||
else if (AppleNTSC::SYNC_START <= hcycle && hcycle < AppleNTSC::BP_START)
|
||||
{
|
||||
cb = AppleNTSC::SYNC_LEVEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
cb = AppleNTSC::BLANK_LEVEL;
|
||||
}
|
||||
return cb;
|
||||
}
|
68
src/picturegenerator.h
Normal file
68
src/picturegenerator.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef PICTUREGENERATOR_H
|
||||
#define PICTUREGENERATOR_H
|
||||
#include "applentsc.h"
|
||||
class AnalogTV;
|
||||
class VideoMode;
|
||||
|
||||
class PictureGenerator
|
||||
{
|
||||
private:
|
||||
AnalogTV& display;
|
||||
VideoMode& mode;
|
||||
|
||||
unsigned char latchGraphics;
|
||||
bool d7;
|
||||
unsigned char latchText;
|
||||
unsigned int hpos;
|
||||
unsigned int line;
|
||||
bool lasthires;
|
||||
static const signed char lutCB[];
|
||||
|
||||
signed char testsig[AppleNTSC::SIGNAL_LEN];
|
||||
signed char* itestsig;
|
||||
signed char* itestsiglim;
|
||||
|
||||
void shiftLoRes();
|
||||
void shiftHiRes();
|
||||
void shiftText();
|
||||
bool getTextBit();
|
||||
bool getHiResBit();
|
||||
bool getLoResBit(const bool odd, const bool vc);
|
||||
void loadGraphics(const unsigned char value);
|
||||
void loadText(const int value);
|
||||
bool shiftLatch(const int t, const int cycle, const bool isText, const bool isHiRes);
|
||||
signed char* writeVideoSignal(const bool shift, const bool showLastHiRes, const int firstBlankedCycle, const int cycle, const int hcycle, const bool bit, const bool lineVis, const bool hVis, signed char* is);
|
||||
signed char vbl(const int hcycle);
|
||||
signed char hbl(const int hcycle);
|
||||
|
||||
const unsigned int VISIBLE_X_OFFSET;
|
||||
|
||||
const int& revision;
|
||||
|
||||
public:
|
||||
|
||||
PictureGenerator(AnalogTV& display, VideoMode& mode, const int& revision);
|
||||
~PictureGenerator();
|
||||
|
||||
void powerOn();
|
||||
void tick(const int t, const unsigned char c);
|
||||
};
|
||||
|
||||
#endif
|
48
src/powerupreset.cpp
Normal file
48
src/powerupreset.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "powerupreset.h"
|
||||
#include "apple2.h"
|
||||
#include "e2const.h"
|
||||
|
||||
PowerUpReset::PowerUpReset(Apple2& apple):
|
||||
apple(apple)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PowerUpReset::~PowerUpReset()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void PowerUpReset::tick()
|
||||
{
|
||||
if (this->pendingTicks > 0)
|
||||
{
|
||||
--this->pendingTicks;
|
||||
if (this->pendingTicks == 0)
|
||||
{
|
||||
this->apple.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PowerUpReset::powerOn()
|
||||
{
|
||||
this->pendingTicks = (int)(E2Const::AVG_CPU_HZ*.3); // U.A.II, p. 7-15
|
||||
}
|
36
src/powerupreset.h
Normal file
36
src/powerupreset.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef POWERUPRESET_H
|
||||
#define POWERUPRESET_H
|
||||
|
||||
class Apple2;
|
||||
|
||||
class PowerUpReset
|
||||
{
|
||||
private:
|
||||
Apple2& apple;
|
||||
int pendingTicks;
|
||||
|
||||
public:
|
||||
PowerUpReset(Apple2& apple);
|
||||
~PowerUpReset();
|
||||
void powerOn();
|
||||
void tick();
|
||||
};
|
||||
|
||||
#endif
|
137
src/raminitializer.cpp
Normal file
137
src/raminitializer.cpp
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "raminitializer.h"
|
||||
#include "memory.h"
|
||||
#include <ctime>
|
||||
#include <cstdlib>
|
||||
|
||||
RAMInitializer::RAMInitializer(Memory& mem):
|
||||
ram(mem)
|
||||
{
|
||||
srand(time(0));
|
||||
}
|
||||
|
||||
void RAMInitializer::init()
|
||||
{
|
||||
this->ram.clear();
|
||||
|
||||
int b(0);
|
||||
// TODO make the types of RAM chips configurable
|
||||
putBytesUntilFull(b++,1);
|
||||
putBytesUntilFull(b++,2);
|
||||
putBytesUntilFull(b++,1);
|
||||
putBytesUntilFull(b++,2);
|
||||
putBytesUntilFull(b++,1);
|
||||
putBytesUntilFull(b++,2);
|
||||
putBytesUntilFull(b++,2);
|
||||
putBytesUntilFull(b++,1);
|
||||
};
|
||||
|
||||
|
||||
void RAMInitializer::putBytesUntilFull(int bit, int pat)
|
||||
{
|
||||
this->nextinit = 0;
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (pat==1)
|
||||
ramPattern1(bit);
|
||||
else
|
||||
ramPattern2(bit);
|
||||
}
|
||||
}
|
||||
catch (const done&)
|
||||
{
|
||||
// done filling this bit in RAM
|
||||
}
|
||||
}
|
||||
|
||||
void RAMInitializer::ramPattern1(const int bit) throw (done)
|
||||
{
|
||||
for (int k = 0; k < 2; ++k)
|
||||
{
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 0x10; ++i)
|
||||
{
|
||||
putn(4,false,bit);
|
||||
putn(2,true,bit);
|
||||
putn(2,false,bit);
|
||||
}
|
||||
for (i = 0; i < 0x40; ++i)
|
||||
{
|
||||
putn(2,true,bit);
|
||||
putn(2,false,bit);
|
||||
}
|
||||
for (i = 0; i < 0x08; ++i)
|
||||
{
|
||||
putn(2,true,bit);
|
||||
putn(1,false,bit);
|
||||
putn(3,true,bit);
|
||||
putn(2,false,bit);
|
||||
putn(2,true,bit);
|
||||
putn(2,false,bit);
|
||||
putn(2,true,bit);
|
||||
putn(2,false,bit);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 0x400; ++i)
|
||||
{
|
||||
putn(2,true,bit);
|
||||
putn(2,false,bit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RAMInitializer::ramPattern2(const int bit) throw (done)
|
||||
{
|
||||
for (int i = 0; i < 0x40; ++i)
|
||||
{
|
||||
putn(0x80,true,bit);
|
||||
putn(0x80,false,bit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RAMInitializer::putn(const int c, bool on, const int bit) throw (done)
|
||||
{
|
||||
if (((rand() >> 9) & 0x1F) == 5)
|
||||
on = !on;
|
||||
const unsigned char mask(1 << bit);
|
||||
for (int i = 0; i < c; ++i)
|
||||
{
|
||||
if (this->nextinit >= this->ram.size())
|
||||
{
|
||||
throw done();
|
||||
}
|
||||
unsigned char b = this->ram.read(this->nextinit);
|
||||
if (on)
|
||||
{
|
||||
b |= mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
b &= ~mask;
|
||||
}
|
||||
this->ram.write(this->nextinit,b);
|
||||
++this->nextinit;
|
||||
}
|
||||
}
|
41
src/raminitializer.h
Normal file
41
src/raminitializer.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef RAMINITIALIZER_H
|
||||
#define RAMINITIALIZER_H
|
||||
|
||||
class Memory;
|
||||
|
||||
class RAMInitializer
|
||||
{
|
||||
private:
|
||||
class done {};
|
||||
|
||||
Memory& ram;
|
||||
unsigned short nextinit;
|
||||
|
||||
void putBytesUntilFull(int bit, int pat);
|
||||
void ramPattern1(const int bit) throw (done);
|
||||
void ramPattern2(const int bit) throw (done);
|
||||
void putn(const int c, bool on, const int bit) throw (done);
|
||||
|
||||
public:
|
||||
RAMInitializer(Memory& mem);
|
||||
void init();
|
||||
};
|
||||
|
||||
#endif
|
561
src/screenimage.cpp
Normal file
561
src/screenimage.cpp
Normal file
|
@ -0,0 +1,561 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "screenimage.h"
|
||||
#include "e2const.h"
|
||||
#include "applentsc.h"
|
||||
#include "card.h"
|
||||
#include "util.h"
|
||||
#include <SDL/SDL.h>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
|
||||
static const char* power =
|
||||
" @@@@ @@@ @ @ @ @@@@@ @@@@ "
|
||||
" @ @ @ @ @ @ @ @ @ @ @"
|
||||
" @ @ @ @ @ @ @ @ @ @ @"
|
||||
" @@@@ @ @ @ @ @ @ @@@@@ @@@@ "
|
||||
" @ @ @ @ @ @ @ @ @ @ "
|
||||
" @ @ @ @ @ @ @ @ @ @ "
|
||||
" @ @@@ @ @ @@@@@ @ @";
|
||||
|
||||
#define POWERD 56
|
||||
#define LABEL_Y 24
|
||||
#define ON_CLR 0xF0D050
|
||||
#define OFF_CLR 0x807870
|
||||
#define SCRW 640
|
||||
#define SCRH 480
|
||||
|
||||
static const int HEIGHT = E2Const::VISIBLE_ROWS_PER_FIELD*2;
|
||||
static const int WIDTH = AppleNTSC::H-AppleNTSC::PIC_START-2;
|
||||
|
||||
#include "font3x5.h"
|
||||
|
||||
class ScreenException { };
|
||||
|
||||
ScreenImage::ScreenImage():
|
||||
fullscreen(false),
|
||||
hyper(false),
|
||||
buffer(true),
|
||||
fillLines(false),
|
||||
display(AnalogTV::MONITOR_COLOR),
|
||||
slotnames(8),
|
||||
cassettename(32,' ')
|
||||
{
|
||||
createScreen();
|
||||
}
|
||||
|
||||
void ScreenImage::toggleFullScreen()
|
||||
{
|
||||
this->fullscreen = !this->fullscreen;
|
||||
createScreen();
|
||||
}
|
||||
|
||||
void ScreenImage::createScreen()
|
||||
{
|
||||
this->screen = SDL_SetVideoMode(SCRW,SCRH,32,SDL_HWSURFACE|SDL_HWPALETTE|(this->fullscreen?SDL_FULLSCREEN:0));
|
||||
if (this->screen == NULL)
|
||||
{
|
||||
printf("Unable to set video mode: %s\n",SDL_GetError());
|
||||
throw ScreenException();
|
||||
};
|
||||
if (this->screen->pitch/4 != SCRW)
|
||||
{
|
||||
printf("Cannot set video screen pitch to 640*4 pixels (gets set to %d)\n",this->screen->pitch);
|
||||
throw ScreenException();
|
||||
};
|
||||
drawLabels();
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
void ScreenImage::drawLabels()
|
||||
{
|
||||
drawText("EPPLE ][",0,141);
|
||||
drawSlots();
|
||||
drawCassette();
|
||||
drawFnKeys();
|
||||
}
|
||||
|
||||
void ScreenImage::drawSlots()
|
||||
{
|
||||
int r(65);
|
||||
int c(17);
|
||||
drawText("SLOTS:",r++,c);
|
||||
for (int slot(0); slot < 8; ++slot)
|
||||
{
|
||||
drawSlot(slot,r++,c);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenImage::drawSlot(int slot, int r, int c)
|
||||
{
|
||||
drawChar('0'+slot,r,c++);
|
||||
drawChar(':',r,c++);
|
||||
drawChar(' ',r,c++);
|
||||
drawText(this->slotnames[slot],r,c);
|
||||
const int len = this->slotnames[slot].length();
|
||||
if (len < 100)
|
||||
{
|
||||
drawText(std::string(100-len,' '),r,c+len);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenImage::drawCassette()
|
||||
{
|
||||
int r(65);
|
||||
int c(85);
|
||||
drawText("CASSETTE:",r,c);
|
||||
c += 9;
|
||||
drawText(this->cassettename,r,c);
|
||||
const int len = this->cassettename.length();
|
||||
if (len < 40)
|
||||
{
|
||||
drawText(std::string(40-len,' '),r,c+len);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* displays[] =
|
||||
{
|
||||
"COLOR MONITOR ",
|
||||
"WHITE MONITOR ",
|
||||
"GREEN MONITOR ",
|
||||
"ORANGE MONITOR",
|
||||
"OLD COLOR TV ",
|
||||
"OLD B & W TV ",
|
||||
"NEW COLOR TV ",
|
||||
"NEW B & W TV ",
|
||||
};
|
||||
|
||||
void ScreenImage::drawFnKeys()
|
||||
{
|
||||
int r(76);
|
||||
int c(1);
|
||||
drawText(
|
||||
" FULLSCRN SCAN-LINES KEYBOARD",r++,c);
|
||||
drawText(
|
||||
" XXXXXXXXXXXXXX WINDOW FILL-LINES CMD REPT HYPER BUFFER RESET PASTE SAVE BMP QUIT!",r++,c);
|
||||
drawText(
|
||||
" F1 F2 F3 F4 F5 F10 F11 F12 Break Insert PrintScreen End",r++,c);
|
||||
|
||||
if (this->fullscreen)
|
||||
invertText(76,32,42); // FULLSCRN
|
||||
else
|
||||
invertText(77,32,40); // WINDOW
|
||||
|
||||
if (this->fillLines)
|
||||
invertText(77,43,55); // FILL-LINES
|
||||
else
|
||||
invertText(76,43,55); // SCAN-LINES
|
||||
|
||||
if (this->hyper)
|
||||
invertText(77,67,74); // HYPER
|
||||
|
||||
if (this->buffer)
|
||||
invertText(77,75,83); // BUFFER
|
||||
|
||||
drawDisplayLabel();
|
||||
}
|
||||
|
||||
void ScreenImage::toggleFillLinesLabel()
|
||||
{
|
||||
this->fillLines = !this->fillLines;
|
||||
invertText(76,43,55); // SCAN-LINES
|
||||
invertText(77,43,55); // FILL-LINES
|
||||
}
|
||||
|
||||
void ScreenImage::drawDisplayLabel()
|
||||
{
|
||||
const char* label = displays[(int)(this->display)];
|
||||
drawText(label,77,17);
|
||||
}
|
||||
|
||||
void ScreenImage::cycleDisplayLabel()
|
||||
{
|
||||
this->display = (AnalogTV::DisplayType)((((int)this->display)+1)%AnalogTV::NUM_DISPLAY_TYPES);
|
||||
drawDisplayLabel();
|
||||
}
|
||||
|
||||
void ScreenImage::toggleHyperLabel()
|
||||
{
|
||||
this->hyper = !this->hyper;
|
||||
invertText(77,67,74); // HYPER
|
||||
}
|
||||
|
||||
void ScreenImage::toggleKdbBufferLabel()
|
||||
{
|
||||
this->buffer = !this->buffer;
|
||||
invertText(77,75,83); // BUFFER
|
||||
}
|
||||
|
||||
void ScreenImage::invertText(int row, int begincol, int endcol)
|
||||
{
|
||||
unsigned int* pn = (unsigned int*)this->screen->pixels;
|
||||
pn += row*FONTH*SCRW+begincol*FONTW;
|
||||
const int dc = (endcol-begincol)*FONTW;
|
||||
for (int ir = 0; ir < FONTH; ++ir)
|
||||
{
|
||||
for (int ic = 0; ic < dc; ++ic)
|
||||
{
|
||||
*pn = ~*pn;
|
||||
++pn;
|
||||
}
|
||||
pn -= dc;
|
||||
pn += SCRW;
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenImage::drawText(const std::string& text, int row, int col, int color, int bgcolor)
|
||||
{
|
||||
for (std::string::const_iterator i = text.begin(); i != text.end(); ++i)
|
||||
{
|
||||
char c = (*i) & 0x7F;
|
||||
if (0 <= c && c < 0x20)
|
||||
c += 0x40;
|
||||
drawChar(c,row,col++,color,bgcolor);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenImage::drawChar(const char ch, int row, int col, int color, int bgcolor)
|
||||
{
|
||||
if (!(0 <= row && row < SCRH/6 && 0 <= col && col < SCRW/4))
|
||||
{
|
||||
printf("bad text plotting (r %d, c %d): \"%c\"\n",row,col,ch);
|
||||
}
|
||||
unsigned int* pn = (unsigned int*)this->screen->pixels;
|
||||
pn += row*FONTH*SCRW+col*FONTW;
|
||||
|
||||
const char* pt = font3x5+FONTH*FONTW*(ch-0x20);
|
||||
for (int r = 0; r < FONTH; ++r)
|
||||
{
|
||||
for (int c = 0; c < FONTW; ++c)
|
||||
{
|
||||
*pn++ = *pt++ == '@' ? color : bgcolor;
|
||||
}
|
||||
pn -= FONTW;
|
||||
pn += SCRW;
|
||||
}
|
||||
SDL_UpdateRect(this->screen,col*FONTW,row*FONTH,(col+1)*FONTW,(row+1)*FONTH);
|
||||
}
|
||||
|
||||
void ScreenImage::displayHz(int hz)
|
||||
{
|
||||
char s[20];
|
||||
sprintf(s,"%4.2f MHz ",hz/1e6);
|
||||
drawText(s,3,141);
|
||||
}
|
||||
|
||||
void ScreenImage::drawPower(bool on)
|
||||
{
|
||||
unsigned int* pn = (unsigned int*)this->screen->pixels;
|
||||
pn += (HEIGHT+5)*(this->screen->pitch/4)+5;
|
||||
for (int r = 0; r < POWERD; ++r)
|
||||
{
|
||||
if (r < LABEL_Y || LABEL_Y+7 <= r)
|
||||
{
|
||||
for (int c = 0; c < POWERD; ++c)
|
||||
{
|
||||
*pn++ = on ? ON_CLR : OFF_CLR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
for (int c = 0; c < 8; ++c)
|
||||
{
|
||||
*pn++ = on ? ON_CLR : OFF_CLR;
|
||||
}
|
||||
}
|
||||
for (const char* ppow = power+(r-(LABEL_Y))*40; ppow < power+(r-(LABEL_Y-1))*40; ++ppow)
|
||||
{
|
||||
if (*ppow == '@')
|
||||
*pn++ = 0;
|
||||
else
|
||||
*pn++ = on ? ON_CLR : OFF_CLR;
|
||||
}
|
||||
{
|
||||
for (int c = 0; c < 8; ++c)
|
||||
{
|
||||
*pn++ = on ? ON_CLR : OFF_CLR;
|
||||
}
|
||||
}
|
||||
}
|
||||
pn -= POWERD;
|
||||
pn += this->screen->pitch/4;
|
||||
}
|
||||
SDL_UpdateRect(this->screen,0,HEIGHT,POWERD,HEIGHT+POWERD);
|
||||
}
|
||||
|
||||
ScreenImage::~ScreenImage()
|
||||
{
|
||||
}
|
||||
|
||||
void ScreenImage::notifyObservers()
|
||||
{
|
||||
SDL_UpdateRect(this->screen,0,0,SCRW,SCRH);
|
||||
}
|
||||
|
||||
void ScreenImage::setElem(unsigned int i, const unsigned int val)
|
||||
{
|
||||
unsigned int* pn = (unsigned int*)this->screen->pixels;
|
||||
i += (i/WIDTH)*(SCRW-WIDTH);
|
||||
pn += i;
|
||||
*pn = val;
|
||||
}
|
||||
|
||||
void ScreenImage::blank()
|
||||
{
|
||||
for (int r = 0; r < HEIGHT; ++r)
|
||||
{
|
||||
memset((char*)(this->screen->pixels)+r*SCRW*4,0,WIDTH*4);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenImage::enterCommandMode()
|
||||
{
|
||||
int r(76);
|
||||
int c(1);
|
||||
unsigned int* pn = (unsigned int*)this->screen->pixels;
|
||||
pn += r*FONTH*SCRW+c*FONTW;
|
||||
|
||||
memset((char*)pn,0,SCRW*4*FONTH*3);
|
||||
|
||||
drawText("command: ",78,1);
|
||||
this->cmdpos = 9;
|
||||
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
void ScreenImage::exitCommandMode()
|
||||
{
|
||||
drawFnKeys();
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
void ScreenImage::addkeyCommand(unsigned char key)
|
||||
{
|
||||
++this->cmdpos;
|
||||
drawChar((char)key,78,this->cmdpos);
|
||||
}
|
||||
|
||||
void ScreenImage::backspaceCommand()
|
||||
{
|
||||
drawChar(' ',78,this->cmdpos);
|
||||
--this->cmdpos;
|
||||
}
|
||||
|
||||
void ScreenImage::updateSlotName(const int slot, Card* card)
|
||||
{
|
||||
int r(66+slot);
|
||||
int c(20);
|
||||
const std::string& name = card->getName();
|
||||
this->slotnames[slot] = name;
|
||||
drawText(std::string(80,' '),r,c);
|
||||
drawText(name,r,c);
|
||||
}
|
||||
|
||||
void ScreenImage::removeCard(const int slot, Card* card /* empty */)
|
||||
{
|
||||
updateSlotName(slot,card);
|
||||
}
|
||||
|
||||
/*
|
||||
1 2 3 4 5 6 7 8
|
||||
789012345678901234567890123456789012345678901234567890123456789012345
|
||||
6: disk][ drive 1M*filename.nib T$FF drive 2M*filename.nib T$FF
|
||||
*/
|
||||
void ScreenImage::setDiskFile(int slot, int drive, const std::string& filepath)
|
||||
{
|
||||
std::string f = truncateFilePath(filepath);
|
||||
int r(66+slot);
|
||||
int c(37+32*drive);
|
||||
drawText(f,r,c);
|
||||
|
||||
const int dlen = 12 - f.length();
|
||||
if (dlen > 0)
|
||||
{
|
||||
std::string d(dlen,' ');
|
||||
drawText(d,r,c+f.length());
|
||||
}
|
||||
|
||||
this->slotnames[slot].replace(c-20,12,12,' ');
|
||||
this->slotnames[slot].replace(c-20,f.length(),f);
|
||||
}
|
||||
|
||||
std::string ScreenImage::truncateFilePath(const std::string& filepath)
|
||||
{
|
||||
std::string f(filepath);
|
||||
size_t slash = f.find_last_of("/\\");
|
||||
if (slash != std::string::npos)
|
||||
{
|
||||
f = f.substr(slash+1);
|
||||
}
|
||||
if (f.length() > 12)
|
||||
{
|
||||
f = f.substr(0,12);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
void ScreenImage::clearCurrentDrive(int slot, int drive)
|
||||
{
|
||||
int r(66+slot);
|
||||
int c(35+32*drive);
|
||||
drawChar(' ',r,c);
|
||||
this->slotnames[slot][c-20] = ' ';
|
||||
c += 15;
|
||||
drawText(" ",r,c);
|
||||
this->slotnames[slot].replace(c-20,4,4,' ');
|
||||
}
|
||||
|
||||
void ScreenImage::setCurrentDrive(int slot, int drive, int track, bool on)
|
||||
{
|
||||
int r(66+slot);
|
||||
int c(35+32*drive);
|
||||
drawChar(' ',r,c,0xFFFFFF,on?0xFF0000:0);
|
||||
c += 15;
|
||||
drawChar('T',r,c);
|
||||
this->slotnames[slot][c-20] = 'T';
|
||||
++c;
|
||||
drawChar('$',r,c);
|
||||
this->slotnames[slot][c-20] = '$';
|
||||
++c;
|
||||
char nibh = Util::hexDigit((((unsigned char)track) >> 4) & 0xF);
|
||||
drawChar(nibh,r,c);
|
||||
this->slotnames[slot][c-20] = nibh;
|
||||
++c;
|
||||
char nibl = Util::hexDigit((unsigned char)track & 0xF);
|
||||
drawChar(nibl,r,c);
|
||||
this->slotnames[slot][c-20] = nibl;
|
||||
}
|
||||
|
||||
void ScreenImage::setTrack(int slot, int drive, int track)
|
||||
{
|
||||
int r(66+slot);
|
||||
int c(52+32*drive);
|
||||
char nibh = Util::hexDigit((((unsigned char)track) >> 4) & 0xF);
|
||||
drawChar(nibh,r,c);
|
||||
this->slotnames[slot][c-20] = nibh;
|
||||
++c;
|
||||
char nibl = Util::hexDigit((unsigned char)track & 0xF);
|
||||
drawChar(nibl,r,c);
|
||||
this->slotnames[slot][c-20] = nibl;
|
||||
}
|
||||
|
||||
void ScreenImage::setIO(int slot, int drive, bool on)
|
||||
{
|
||||
int r(66+slot);
|
||||
int c(35+32*drive);
|
||||
drawChar(' ',r,c,0xFFFFFF,on?0xFF0000:0);
|
||||
}
|
||||
|
||||
void ScreenImage::setDirty(int slot, int drive, bool dirty)
|
||||
{
|
||||
int r(66+slot);
|
||||
int c(36+32*drive);
|
||||
drawChar(dirty?'*':' ',r,c);
|
||||
this->slotnames[slot][c-20] = dirty?'*':' ';
|
||||
}
|
||||
|
||||
void ScreenImage::setCassetteFile(const std::string& filepath)
|
||||
{
|
||||
std::string f = truncateFilePath(filepath);
|
||||
int r(65);
|
||||
int c(85+11);
|
||||
drawText(f,r,c);
|
||||
|
||||
const int dlen = 12 - f.length();
|
||||
if (dlen > 0)
|
||||
{
|
||||
std::string d(dlen,' ');
|
||||
drawText(d,r,c+f.length());
|
||||
}
|
||||
|
||||
this->cassettename.replace(c-94,12,12,' ');
|
||||
this->cassettename.replace(c-94,f.length(),f);
|
||||
}
|
||||
|
||||
void ScreenImage::setCassetteDirty(bool dirty)
|
||||
{
|
||||
int r(65);
|
||||
int c(85+10);
|
||||
drawChar(dirty?'*':' ',r,c);
|
||||
this->cassettename[c-94] = dirty?'*':' ';
|
||||
}
|
||||
|
||||
void ScreenImage::setCassettePos(int pos, int siz)
|
||||
{
|
||||
int r(65);
|
||||
int c(110);
|
||||
std::ostringstream os;
|
||||
os << pos << '/' << siz << " ";
|
||||
drawText(os.str(),r,c);
|
||||
}
|
||||
|
||||
/*
|
||||
1 2 3 4 5 6 7 8
|
||||
789012345678901234567890123456789012345678901234567890123456789012345678
|
||||
0: language RW B2
|
||||
*/
|
||||
void ScreenImage::setLangCard(int slot, bool readEnable, bool writeEnable, int bank)
|
||||
{
|
||||
int r(66+slot);
|
||||
int c(29);
|
||||
drawChar(readEnable?'R':' ',r,c);
|
||||
this->slotnames[slot][c-20] = readEnable?'R':' ';
|
||||
++c;
|
||||
drawChar(writeEnable?'W':' ',r,c);
|
||||
this->slotnames[slot][c-20] = writeEnable?'W':' ';
|
||||
++c;
|
||||
++c;
|
||||
drawChar('B',r,c);
|
||||
this->slotnames[slot][c-20] = 'B';
|
||||
++c;
|
||||
drawChar(bank==0?'1':'2',r,c);
|
||||
this->slotnames[slot][c-20] = bank==0?'1':'2';
|
||||
}
|
||||
|
||||
/*
|
||||
1 2 3 4 5 6 7 8
|
||||
789012345678901234567890123456789012345678901234567890123456789012345678
|
||||
0: firmware D F8
|
||||
*/
|
||||
void ScreenImage::setFirmCard(int slot, bool bank, bool F8)
|
||||
{
|
||||
int r(66+slot);
|
||||
int c(29);
|
||||
drawChar(bank?'D':' ',r,c);
|
||||
this->slotnames[slot][c-20] = bank?'D':' ';
|
||||
++c;
|
||||
++c;
|
||||
drawChar(F8?'F':' ',r,c);
|
||||
this->slotnames[slot][c-20] = F8?'F':' ';
|
||||
++c;
|
||||
drawChar(F8?'8':' ',r,c);
|
||||
this->slotnames[slot][c-20] = F8?'8':' ';
|
||||
}
|
||||
|
||||
#define TIMEFORMAT "ep2_%Y%m%d%H%M%S.bmp"
|
||||
|
||||
void ScreenImage::saveBMP()
|
||||
{
|
||||
time_t now;
|
||||
::time(&now);
|
||||
struct tm* nowtm = ::localtime(&now);
|
||||
char time[64];
|
||||
::strftime(time,sizeof(time),TIMEFORMAT,nowtm);
|
||||
SDL_SaveBMP(this->screen,time);
|
||||
}
|
94
src/screenimage.h
Normal file
94
src/screenimage.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SCREENIMAGE_H
|
||||
#define SCREENIMAGE_H
|
||||
|
||||
#include "analogtv.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class Card;
|
||||
struct SDL_Surface;
|
||||
|
||||
class ScreenImage
|
||||
{
|
||||
private:
|
||||
SDL_Surface* screen;
|
||||
bool fullscreen;
|
||||
bool hyper;
|
||||
bool buffer;
|
||||
bool fillLines;
|
||||
AnalogTV::DisplayType display;
|
||||
unsigned int cmdpos;
|
||||
void createScreen();
|
||||
std::vector<std::string> slotnames;
|
||||
std::string cassettename;
|
||||
|
||||
static std::string truncateFilePath(const std::string& filepath);
|
||||
|
||||
// TODO some of these methods should be private
|
||||
public:
|
||||
ScreenImage();
|
||||
~ScreenImage();
|
||||
|
||||
void toggleFullScreen();
|
||||
void drawPower(bool on);
|
||||
void notifyObservers();
|
||||
void setElem(const unsigned int i, const unsigned int val);
|
||||
void blank();
|
||||
void drawText(const std::string& text, int row, int col, int color = 0xFFFFFF, int bgcolor = 0);
|
||||
void drawChar(const char ch, int row, int col, int color = 0xFFFFFF, int bgcolor = 0);
|
||||
void drawLabels();
|
||||
void drawSlots();
|
||||
void drawSlot(int slot, int r, int c);
|
||||
void drawCassette();
|
||||
void drawFnKeys();
|
||||
void toggleHyperLabel();
|
||||
void toggleKdbBufferLabel();
|
||||
void cycleDisplayLabel();
|
||||
void displayHz(int hz);
|
||||
void toggleFillLinesLabel();
|
||||
void invertText(int row, int begincol, int endcol);
|
||||
void drawDisplayLabel();
|
||||
void updateSlotName(const int slot, Card* card);
|
||||
void removeCard(const int slot, Card* card /* empty */);
|
||||
|
||||
void enterCommandMode();
|
||||
void exitCommandMode();
|
||||
void addkeyCommand(unsigned char key);
|
||||
void backspaceCommand();
|
||||
|
||||
void setDiskFile(int slot, int drive, const std::string& filename);
|
||||
|
||||
void clearCurrentDrive(int slt, int drv);
|
||||
void setCurrentDrive(int slt, int drv, int track, bool on);
|
||||
void setTrack(int slot, int drive, int track);
|
||||
void setIO(int slot, int drive, bool on);
|
||||
void setDirty(int slot, int drive, bool dirty);
|
||||
|
||||
void setCassetteFile(const std::string& filepath);
|
||||
void setCassetteDirty(bool dirty);
|
||||
void setCassettePos(int pos, int siz);
|
||||
|
||||
void setLangCard(int slot, bool readEnable, bool writeEnable, int bank);
|
||||
void setFirmCard(int slot, bool bank, bool F8);
|
||||
|
||||
void saveBMP();
|
||||
};
|
||||
|
||||
#endif
|
151
src/slots.cpp
Normal file
151
src/slots.cpp
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "slots.h"
|
||||
#include "screenimage.h"
|
||||
#include <algorithm>
|
||||
|
||||
Slots::Slots(ScreenImage& gui):
|
||||
gui(gui),
|
||||
empty(),
|
||||
cards(8,&this->empty)
|
||||
{
|
||||
forceGuiUpdate();
|
||||
}
|
||||
|
||||
Slots::~Slots()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned char Slots::io(const int islot, const int iswch, const unsigned char b, const bool writing)
|
||||
{
|
||||
return this->cards[islot]->io(iswch,b,writing);
|
||||
}
|
||||
|
||||
struct Slots_Card_reset
|
||||
{
|
||||
void operator() (Card* p) { p->reset(); }
|
||||
};
|
||||
|
||||
void Slots::reset()
|
||||
{
|
||||
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_reset());
|
||||
}
|
||||
|
||||
unsigned char Slots::readRom(const int islot, const unsigned short addr, const unsigned char data)
|
||||
{
|
||||
return this->cards[islot]->readRom(addr,data);
|
||||
}
|
||||
|
||||
struct Slots_Card_readSeventhRom
|
||||
{
|
||||
const unsigned short addr;
|
||||
unsigned char* b;
|
||||
Slots_Card_readSeventhRom(const unsigned short addr, unsigned char* b):addr(addr),b(b){}
|
||||
void operator() (Card* p) { p->readSeventhRom(this->addr,this->b); }
|
||||
};
|
||||
|
||||
unsigned char Slots::readSeventhRom(const unsigned short addr, const unsigned char data)
|
||||
{
|
||||
unsigned char b(data);
|
||||
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_readSeventhRom(addr,&b));
|
||||
return b;
|
||||
}
|
||||
|
||||
struct Slots_Card_ioBankRom
|
||||
{
|
||||
const unsigned short addr;
|
||||
unsigned char* b;
|
||||
const bool write;
|
||||
Slots_Card_ioBankRom(const unsigned short addr, unsigned char* b, const bool write):addr(addr),b(b),write(write){}
|
||||
void operator() (Card* p) { p->ioBankRom(this->addr,this->b,this->write); }
|
||||
};
|
||||
|
||||
unsigned char Slots::ioBankRom(const unsigned short addr, const unsigned char data, const bool write)
|
||||
{
|
||||
unsigned char b(data);
|
||||
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_ioBankRom(addr,&b,write));
|
||||
return b;
|
||||
}
|
||||
|
||||
struct Slots_Card_inhibitMotherboardRom
|
||||
{
|
||||
bool inhibit;
|
||||
Slots_Card_inhibitMotherboardRom():inhibit(false) { }
|
||||
void operator() (Card* p) { if (p->inhibitMotherboardRom()) { inhibit = true; }}
|
||||
};
|
||||
|
||||
bool Slots::inhibitMotherboardRom()
|
||||
{
|
||||
return std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_inhibitMotherboardRom()).inhibit;
|
||||
}
|
||||
|
||||
void Slots::set(const int slot, Card* card)
|
||||
{
|
||||
remove(slot);
|
||||
this->cards[slot] = card;
|
||||
this->gui.updateSlotName(slot,this->cards[slot]);
|
||||
}
|
||||
|
||||
void Slots::remove(const int slot)
|
||||
{
|
||||
if (this->cards[slot] != &this->empty)
|
||||
{
|
||||
delete this->cards[slot];
|
||||
this->cards[slot] = &this->empty;
|
||||
this->gui.removeCard(slot,this->cards[slot]);
|
||||
}
|
||||
}
|
||||
|
||||
Card* Slots::get(const int slot)
|
||||
{
|
||||
return this->cards[slot];
|
||||
}
|
||||
|
||||
|
||||
void Slots::forceGuiUpdate()
|
||||
{
|
||||
for (int slot(0); slot < 8; ++slot)
|
||||
this->gui.updateSlotName(slot,this->cards[slot]);
|
||||
}
|
||||
|
||||
/*
|
||||
struct isAnyDiskDriveMotorOnCard
|
||||
{
|
||||
bool on;
|
||||
isAnyDiskDriveMotorOnCard():on(false) {}
|
||||
void operator() (Card* p) { if (p->isMotorOn()) on = true; }
|
||||
};
|
||||
|
||||
bool isAnyDiskDriveMotorOn()
|
||||
{
|
||||
isAnyDiskDriveMotorOnCard on = isAnyDiskDriveMotorOnCard();
|
||||
std::for_each(this->cards.begin(),this->cards.end(),inh);
|
||||
return on.inhibit;
|
||||
}
|
||||
*/
|
||||
struct Slots_Card_isDirty
|
||||
{
|
||||
bool dirty;
|
||||
Slots_Card_isDirty():dirty(false) {}
|
||||
void operator() (Card* p) { if (p->isDirty()) dirty = true; }
|
||||
};
|
||||
|
||||
bool Slots::isDirty()
|
||||
{
|
||||
return std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_isDirty()).dirty;
|
||||
}
|
51
src/slots.h
Normal file
51
src/slots.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SLOTS_H
|
||||
#define SLOTS_H
|
||||
|
||||
#include <vector>
|
||||
#include "card.h"
|
||||
#include "emptyslot.h"
|
||||
|
||||
class ScreenImage;
|
||||
|
||||
class Slots
|
||||
{
|
||||
private:
|
||||
ScreenImage& gui;
|
||||
EmptySlot empty;
|
||||
std::vector<Card*> cards;
|
||||
|
||||
public:
|
||||
Slots(ScreenImage& gui);
|
||||
~Slots();
|
||||
|
||||
unsigned char io(const int islot, const int iswch, const unsigned char b, const bool writing);
|
||||
void reset();
|
||||
unsigned char readRom(const int islot, const unsigned short addr, const unsigned char data);
|
||||
unsigned char readSeventhRom(const unsigned short addr, const unsigned char data);
|
||||
unsigned char ioBankRom(const unsigned short addr, const unsigned char data, const bool write);
|
||||
bool inhibitMotherboardRom();
|
||||
void set(const int slot, Card* card);
|
||||
Card* get(const int slot);
|
||||
void remove(const int slot);
|
||||
bool isDirty();
|
||||
void forceGuiUpdate();
|
||||
};
|
||||
|
||||
#endif
|
179
src/speakerclicker.cpp
Normal file
179
src/speakerclicker.cpp
Normal file
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "speakerclicker.h"
|
||||
#include <SDL/SDL.h>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <deque>
|
||||
|
||||
std::deque<char> locbuf;
|
||||
volatile bool done;
|
||||
SDL_cond* bufchg;
|
||||
SDL_mutex* buflck;
|
||||
|
||||
// TODO figure out why sound is so choppy, and fix it
|
||||
void fillbuf(void *userdata, Uint8 *stream, int len)
|
||||
{
|
||||
int tot(0);
|
||||
while (len && !done)
|
||||
{
|
||||
// wait for locbuf to have some data
|
||||
// (it gets filled up by tick() method)
|
||||
SDL_LockMutex(buflck);
|
||||
while (locbuf.empty() && !done)
|
||||
{
|
||||
SDL_CondWait(bufchg,buflck);
|
||||
}
|
||||
if (done)
|
||||
{
|
||||
SDL_UnlockMutex(buflck);
|
||||
return;
|
||||
}
|
||||
while (locbuf.size() > 0 && len > 0)
|
||||
{
|
||||
int v = locbuf.front();
|
||||
*stream++ = v;
|
||||
|
||||
if (v < 0) v = -v;
|
||||
tot += v;
|
||||
|
||||
--len;
|
||||
locbuf.pop_front();
|
||||
}
|
||||
if (tot <= 0)
|
||||
{
|
||||
if (locbuf.size() >= 1024)
|
||||
locbuf.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (locbuf.size() >= 65536);
|
||||
locbuf.clear();
|
||||
}
|
||||
SDL_UnlockMutex(buflck);
|
||||
}
|
||||
}
|
||||
|
||||
#define TICKS_PER_SAMPLE 47
|
||||
#define AMP 126
|
||||
|
||||
SpeakerClicker::SpeakerClicker():
|
||||
clicked(false),
|
||||
t(TICKS_PER_SAMPLE)
|
||||
{
|
||||
done = false;
|
||||
|
||||
SDL_AudioSpec audio;
|
||||
audio.freq = 22050; // samples per second
|
||||
audio.format = AUDIO_S8; // 8 bits (1 byte) per sample
|
||||
audio.channels = 1; // mono
|
||||
audio.silence = 0;
|
||||
audio.samples = 4096;
|
||||
audio.callback = fillbuf;
|
||||
audio.userdata = 0;
|
||||
SDL_AudioSpec obtained;
|
||||
obtained.callback = 0;
|
||||
obtained.userdata = 0;
|
||||
if (SDL_OpenAudio(&audio,&obtained) != 0)
|
||||
{
|
||||
done = true;
|
||||
std::cerr << "Unable to initialize audio: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufchg = SDL_CreateCond();
|
||||
buflck = SDL_CreateMutex();
|
||||
|
||||
std::cout << "initialized audio: " << std::endl;
|
||||
std::cout << "freq: " << obtained.freq << std::endl;
|
||||
std::cout << "format: " << (obtained.format==AUDIO_S8?"8-bit":"other") << std::endl;
|
||||
std::cout << "channels: " << (int)obtained.channels << std::endl;
|
||||
std::cout << "silence: " << (int)obtained.silence << std::endl;
|
||||
std::cout << "samples: " << obtained.samples << std::endl;
|
||||
std::cout << "size: " << obtained.size << std::endl;
|
||||
SDL_PauseAudio(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SpeakerClicker::~SpeakerClicker()
|
||||
{
|
||||
if (done)
|
||||
{
|
||||
return;
|
||||
}
|
||||
done = true;
|
||||
SDL_LockMutex(buflck);
|
||||
SDL_CondSignal(bufchg);
|
||||
SDL_UnlockMutex(buflck);
|
||||
SDL_CloseAudio();
|
||||
SDL_DestroyCond(bufchg);
|
||||
SDL_DestroyMutex(buflck);
|
||||
}
|
||||
|
||||
/*
|
||||
void SpeakerClicker::tick()
|
||||
{
|
||||
--this->t;
|
||||
if (this->t <= 0)
|
||||
{
|
||||
this->t = TICKS_PER_SAMPLE;
|
||||
if (this->clicked)
|
||||
{
|
||||
this->positive = !this->positive;
|
||||
this->clicked = false;
|
||||
}
|
||||
locbuf.push_back(this->positive ? AMP : -AMP);
|
||||
locbuf.push_back(this->positive ? AMP : -AMP);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void SpeakerClicker::tick()
|
||||
{
|
||||
if (done)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
--this->t;
|
||||
if (this->t <= 0)
|
||||
{
|
||||
this->t = TICKS_PER_SAMPLE;
|
||||
int amp;
|
||||
if (this->clicked)
|
||||
{
|
||||
amp = this->positive ? AMP : -AMP;
|
||||
this->positive = !this->positive;
|
||||
this->clicked = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
amp = 0;
|
||||
}
|
||||
SDL_LockMutex(buflck);
|
||||
locbuf.push_back(amp);
|
||||
SDL_CondSignal(bufchg);
|
||||
SDL_UnlockMutex(buflck);
|
||||
}
|
||||
}
|
||||
|
||||
void SpeakerClicker::click()
|
||||
{
|
||||
this->clicked = true;
|
||||
}
|
34
src/speakerclicker.h
Normal file
34
src/speakerclicker.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SPEAKERCLICKER_H
|
||||
#define SPEAKERCLICKER_H
|
||||
|
||||
class SpeakerClicker
|
||||
{
|
||||
private:
|
||||
bool clicked;
|
||||
int t;
|
||||
bool positive;
|
||||
public:
|
||||
SpeakerClicker();
|
||||
~SpeakerClicker();
|
||||
void tick();
|
||||
void click();
|
||||
};
|
||||
|
||||
#endif
|
65
src/standardin.cpp
Normal file
65
src/standardin.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "standardin.h"
|
||||
|
||||
StandardIn::StandardIn():
|
||||
latch(0),
|
||||
gotEOF(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
StandardIn::~StandardIn()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned char StandardIn::io(const unsigned short address, const unsigned char data, const bool writing)
|
||||
{
|
||||
int sw = address & 0x0F;
|
||||
if (sw == 0)
|
||||
{
|
||||
if (!(this->latch & 0x80))
|
||||
{
|
||||
if (this->gotEOF)
|
||||
{
|
||||
this->latch = 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this->producer.getKeys().empty())
|
||||
{
|
||||
this->latch = this->producer.getKeys().front();
|
||||
this->producer.getKeys().pop();
|
||||
if (this->latch == 0xFF)
|
||||
{
|
||||
this->gotEOF = true;
|
||||
}
|
||||
this->latch |= 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sw == 1)
|
||||
{
|
||||
this->latch &= 0x7F;
|
||||
}
|
||||
return this->latch;
|
||||
}
|
39
src/standardin.h
Normal file
39
src/standardin.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef STANDARDIN_H
|
||||
#define STANDARDIN_H
|
||||
|
||||
#include "card.h"
|
||||
#include "standardinproducer.h"
|
||||
|
||||
class StandardIn : public Card
|
||||
{
|
||||
private:
|
||||
StandardInProducer producer;
|
||||
unsigned char latch;
|
||||
bool gotEOF;
|
||||
|
||||
public:
|
||||
StandardIn();
|
||||
~StandardIn();
|
||||
|
||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||
virtual std::string getName() { return "standard input"; }
|
||||
};
|
||||
|
||||
#endif
|
100
src/standardinproducer.cpp
Normal file
100
src/standardinproducer.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "standardinproducer.h"
|
||||
#include <SDL/SDL.h>
|
||||
#include <SDL/SDL_thread.h>
|
||||
#include <iostream>
|
||||
|
||||
#define CR '\r'
|
||||
#define LF '\n'
|
||||
|
||||
enum state_t { START, GOT_CR, GOT_LF, GOT_EOF };
|
||||
|
||||
|
||||
static int readInput(void *voidkeys)
|
||||
{
|
||||
KeypressQueue* keys = (KeypressQueue*)voidkeys;
|
||||
|
||||
/*
|
||||
* Continuously read characters from standard in
|
||||
* and put them onto the queue.
|
||||
* Stop when we hit EOF (placing EOF onto the queue).
|
||||
* Translate LF to CR.
|
||||
* If we hit a CR immediately after a LF, drop it.
|
||||
* If we hit a LF immediately after a CR, drop it.
|
||||
*/
|
||||
enum state_t state = START;
|
||||
|
||||
while (state != GOT_EOF)
|
||||
{
|
||||
char c = std::cin.get();
|
||||
c &= 0x7F;
|
||||
if (!std::cin.good())
|
||||
{
|
||||
state = GOT_EOF;
|
||||
keys->push(0xFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state == START)
|
||||
{
|
||||
if (c == CR)
|
||||
{
|
||||
state = GOT_CR;
|
||||
}
|
||||
else if (c == LF)
|
||||
{
|
||||
state = GOT_LF;
|
||||
c = CR;
|
||||
}
|
||||
keys->push(c);
|
||||
}
|
||||
else if (state == GOT_CR)
|
||||
{
|
||||
if (c != LF)
|
||||
{
|
||||
keys->push(c);
|
||||
}
|
||||
state = START;
|
||||
}
|
||||
else if (state == GOT_LF)
|
||||
{
|
||||
if (c != CR)
|
||||
{
|
||||
if (c == LF)
|
||||
{
|
||||
c = CR;
|
||||
}
|
||||
keys->push(c);
|
||||
}
|
||||
state = START;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
StandardInProducer::StandardInProducer()
|
||||
{
|
||||
SDL_CreateThread(readInput,&this->keys);
|
||||
}
|
||||
|
||||
StandardInProducer::~StandardInProducer()
|
||||
{
|
||||
}
|
35
src/standardinproducer.h
Normal file
35
src/standardinproducer.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef STANDARDINPRODUCER_H
|
||||
#define STANDARDINPRODUCER_H
|
||||
|
||||
#include "keyboard.h"
|
||||
|
||||
class StandardInProducer
|
||||
{
|
||||
private:
|
||||
KeypressQueue keys;
|
||||
|
||||
public:
|
||||
StandardInProducer();
|
||||
~StandardInProducer();
|
||||
|
||||
KeypressQueue& getKeys() { return this->keys; }
|
||||
};
|
||||
|
||||
#endif
|
50
src/standardout.cpp
Normal file
50
src/standardout.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "standardout.h"
|
||||
#include <iostream>
|
||||
|
||||
StandardOut::StandardOut()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
StandardOut::~StandardOut()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unsigned char StandardOut::io(const unsigned short address, const unsigned char data, const bool writing)
|
||||
{
|
||||
if (!writing)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
const char c = (char)(data&0x7F);
|
||||
if (c == '\r')
|
||||
{
|
||||
std::cout << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << c;
|
||||
}
|
||||
std::cout << std::flush;
|
||||
|
||||
return data;
|
||||
}
|
34
src/standardout.h
Normal file
34
src/standardout.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
epple2
|
||||
Copyright (C) 2008 by Chris Mosher <chris@mosher.mine.nu>
|
||||
|
||||
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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef STANDARDOUT_H
|
||||
#define STANDARDOUT_H
|
||||
|
||||
#include "card.h"
|
||||
|
||||
class StandardOut : public Card
|
||||
{
|
||||
|
||||
public:
|
||||
StandardOut();
|
||||
~StandardOut();
|
||||
|
||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||
virtual std::string getName() { return "standard output"; }
|
||||
};
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user