mirror of
https://github.com/cmosher01/Epple-II.git
synced 2024-06-11 20:29:28 +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