KEK
This commit is contained in:
commit
2e5b2022fd
26 changed files with 6160 additions and 0 deletions
661
LICENSE
Normal file
661
LICENSE
Normal file
|
@ -0,0 +1,661 @@
|
||||||
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU Affero General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works, specifically designed to ensure
|
||||||
|
cooperation with the community in the case of network server software.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
our General Public Licenses are 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Developers that use our General Public Licenses protect your rights
|
||||||
|
with two steps: (1) assert copyright on the software, and (2) offer
|
||||||
|
you this License which gives you legal permission to copy, distribute
|
||||||
|
and/or modify the software.
|
||||||
|
|
||||||
|
A secondary benefit of defending all users' freedom is that
|
||||||
|
improvements made in alternate versions of the program, if they
|
||||||
|
receive widespread use, become available for other developers to
|
||||||
|
incorporate. Many developers of free software are heartened and
|
||||||
|
encouraged by the resulting cooperation. However, in the case of
|
||||||
|
software used on network servers, this result may fail to come about.
|
||||||
|
The GNU General Public License permits making a modified version and
|
||||||
|
letting the public access it on a server without ever releasing its
|
||||||
|
source code to the public.
|
||||||
|
|
||||||
|
The GNU Affero General Public License is designed specifically to
|
||||||
|
ensure that, in such cases, the modified source code becomes available
|
||||||
|
to the community. It requires the operator of a network server to
|
||||||
|
provide the source code of the modified version running there to the
|
||||||
|
users of that server. Therefore, public use of a modified version, on
|
||||||
|
a publicly accessible server, gives the public access to the source
|
||||||
|
code of the modified version.
|
||||||
|
|
||||||
|
An older license, called the Affero General Public License and
|
||||||
|
published by Affero, was designed to accomplish similar goals. This is
|
||||||
|
a different license, not a version of the Affero GPL, but Affero has
|
||||||
|
released a new version of the Affero GPL which permits relicensing under
|
||||||
|
this license.
|
||||||
|
|
||||||
|
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 Affero 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. Remote Network Interaction; Use with the GNU General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, if you modify the
|
||||||
|
Program, your modified version must prominently offer all users
|
||||||
|
interacting with it remotely through a computer network (if your version
|
||||||
|
supports such interaction) an opportunity to receive the Corresponding
|
||||||
|
Source of your version by providing access to the Corresponding Source
|
||||||
|
from a network server at no charge, through some standard or customary
|
||||||
|
means of facilitating copying of software. This Corresponding Source
|
||||||
|
shall include the Corresponding Source for any work covered by version 3
|
||||||
|
of the GNU General Public License that is incorporated pursuant to the
|
||||||
|
following paragraph.
|
||||||
|
|
||||||
|
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 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 work with which it is combined will remain governed by version
|
||||||
|
3 of the GNU General Public License.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If your software can interact with users remotely through a computer
|
||||||
|
network, you should also make sure that it provides a way for users to
|
||||||
|
get its source. For example, if your program is a web application, its
|
||||||
|
interface could display a "Source" link that leads users to an archive
|
||||||
|
of the code. There are many ways you could offer source, and different
|
||||||
|
solutions will be better for different programs; see section 13 for the
|
||||||
|
specific requirements.
|
||||||
|
|
||||||
|
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 AGPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
30
README.md
Normal file
30
README.md
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
KEK
|
||||||
|
Kek might (I work occasionally on it so don't hold your breath) become a DEC PDP-11 emulator capable of running UNIX-v7.
|
||||||
|
|
||||||
|
Run:
|
||||||
|
make all
|
||||||
|
to build.
|
||||||
|
|
||||||
|
To run the test-cases:
|
||||||
|
|
||||||
|
./kek -m tc
|
||||||
|
|
||||||
|
... it should end in "ALL FINE".
|
||||||
|
|
||||||
|
|
||||||
|
To run a disk image:
|
||||||
|
|
||||||
|
./kek -R filename.rk -p offset 2> /dev/null
|
||||||
|
|
||||||
|
... where offset is a decimal(!) address to start (optional).
|
||||||
|
|
||||||
|
|
||||||
|
To run a tape image:
|
||||||
|
|
||||||
|
./kek -T filename.bin -p offset 2> /dev/null
|
||||||
|
|
||||||
|
... where offset is a decimal(!) address to start (optional).
|
||||||
|
|
||||||
|
|
||||||
|
Released in 2018 under AGPL v3.0
|
||||||
|
Folkert van Heusden
|
448
bus.cpp
Normal file
448
bus.cpp
Normal file
|
@ -0,0 +1,448 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "bus.h"
|
||||||
|
#include "gen.h"
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "tm-11.h"
|
||||||
|
#include "tty.h"
|
||||||
|
|
||||||
|
bus::bus() : c(nullptr), tm11(nullptr), rk05_(nullptr), rx02_(nullptr), tty_(nullptr)
|
||||||
|
{
|
||||||
|
m = new memory(16 * 8192);
|
||||||
|
|
||||||
|
for(int i=0; i<16; i++) {
|
||||||
|
pages[i].par = (i & 7) * 8192 / 64;
|
||||||
|
pages[i].pdr = (3 << 1) | (0 << 4) | (0 << 6) | ((8192 / (32 * 2)) << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
CPUERR = MMR2 = MMR3 = PIR = CSR = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bus::~bus()
|
||||||
|
{
|
||||||
|
delete c;
|
||||||
|
delete tm11;
|
||||||
|
delete rk05_;
|
||||||
|
delete rx02_;
|
||||||
|
delete tty_;
|
||||||
|
delete m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bus::clearmem()
|
||||||
|
{
|
||||||
|
m -> reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t bus::read(const uint16_t a, const bool word_mode, const bool use_prev)
|
||||||
|
{
|
||||||
|
uint16_t temp = 0;
|
||||||
|
|
||||||
|
if (a >= 0160000) {
|
||||||
|
fprintf(stderr, "read%c I/O %o\n", word_mode ? 'b' : ' ', a);
|
||||||
|
|
||||||
|
if (a == 0177750) { // MAINT
|
||||||
|
fprintf(stderr, "read MAINT\n");
|
||||||
|
return 1; // POWER OK
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177570) { // console switch & display register
|
||||||
|
fprintf(stderr, "read console switch\n");
|
||||||
|
return 128; // educated guess
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0172540) { // KW11P programmable clock
|
||||||
|
fprintf(stderr, "read programmable clock\n");
|
||||||
|
return 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177772) { // PIR
|
||||||
|
fprintf(stderr, "read PIT\n");
|
||||||
|
return PIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177546) { // line frequency clock and status register
|
||||||
|
fprintf(stderr, "read line freq clock\n");
|
||||||
|
return CSR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177514) { // printer, CSR register, LP11
|
||||||
|
fprintf(stderr, "read LP11 CSR\n");
|
||||||
|
return 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MMU ///
|
||||||
|
if (a >= 0172300 && a < 0172320) {
|
||||||
|
uint16_t t = pages[((a & 017) >> 1)].pdr;
|
||||||
|
fprintf(stderr, "read PDR for %d: %o\n", (a & 017) >> 1, t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a >= 0172340 && a < 0172360) {
|
||||||
|
uint16_t t = pages[((a & 017) >> 1)].par;
|
||||||
|
fprintf(stderr, "read PAR for %d: %o\n", (a & 017) >> 1, t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a >= 0177600 && a < 0177620) {
|
||||||
|
uint16_t t = pages[((a & 017) >> 1) + 8].pdr;
|
||||||
|
fprintf(stderr, "read PDR for %d: %o\n", ((a & 017) >> 1) + 8, t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a >= 0177640 && a < 0177660) {
|
||||||
|
uint16_t t = pages[((a & 017) >> 1) + 8].par;
|
||||||
|
fprintf(stderr, "read PAR for %d: %o\n", ((a & 017) >> 1) + 8, t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177572) {
|
||||||
|
uint16_t t = ((c -> getRunMode() ? 0b11 : 0b00) << 5) | // kernel == 00
|
||||||
|
((c -> getRegister(7) >> 13) << 1) | // page nr
|
||||||
|
0 // MMU enabled
|
||||||
|
;
|
||||||
|
fprintf(stderr, "read MMU SR0 %o\n", t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
///////////
|
||||||
|
|
||||||
|
if (word_mode) {
|
||||||
|
if (a == 0177776) { // PSW
|
||||||
|
fprintf(stderr, "readb PSW LSB\n");
|
||||||
|
return c -> getPSW() & 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177777) {
|
||||||
|
fprintf(stderr, "readb PSW MSB\n");
|
||||||
|
return c -> getPSW() >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177774) { // stack limit register
|
||||||
|
fprintf(stderr, "readb stack limit register\n");
|
||||||
|
return c -> getStackLimitRegister() & 0xff;
|
||||||
|
}
|
||||||
|
if (a == 0177775) { // stack limit register
|
||||||
|
fprintf(stderr, "readb stack limit register\n");
|
||||||
|
return c -> getStackLimitRegister() >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a >= 0177700 && a <= 0177705) { // kernel R0-R5
|
||||||
|
fprintf(stderr, "readb kernel R%d\n", a - 0177700);
|
||||||
|
return c -> getRegister(false, a - 0177700) & 0xff;
|
||||||
|
}
|
||||||
|
if (a >= 0177710 && a <= 0177715) { // user R0-R5
|
||||||
|
fprintf(stderr, "readb user R%d\n", a - 0177710);
|
||||||
|
return c -> getRegister(true, a - 0177710) & 0xff;
|
||||||
|
}
|
||||||
|
if (a == 0177706) { // kernel SP
|
||||||
|
fprintf(stderr, "readb kernel sp\n");
|
||||||
|
return c -> getStackPointer(0) & 0xff;
|
||||||
|
}
|
||||||
|
if (a == 0177707) { // PC
|
||||||
|
fprintf(stderr, "readb pc\n");
|
||||||
|
return c -> getPC() & 0xff;
|
||||||
|
}
|
||||||
|
if (a == 0177716) { // supervisor SP
|
||||||
|
fprintf(stderr, "readb supervisor sp\n");
|
||||||
|
return c -> getStackPointer(1) & 0xff;
|
||||||
|
}
|
||||||
|
if (a == 0177717) { // user SP
|
||||||
|
fprintf(stderr, "readb user sp\n");
|
||||||
|
return c -> getStackPointer(3) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177766) { // cpu error register
|
||||||
|
fprintf(stderr, "readb cpuerr\n");
|
||||||
|
return CPUERR & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (a == 0177576) { // MMR2
|
||||||
|
fprintf(stderr, "read MMR2\n");
|
||||||
|
return MMR2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0172516) { // MMR3
|
||||||
|
fprintf(stderr, "read MMR3\n");
|
||||||
|
return MMR3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177776) { // PSW
|
||||||
|
fprintf(stderr, "read PSW\n");
|
||||||
|
return c -> getPSW();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177774) { // stack limit register
|
||||||
|
return c -> getStackLimitRegister();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a >= 0177700 && a <= 0177705) { // kernel R0-R5
|
||||||
|
fprintf(stderr, "read kernel R%d\n", a - 0177700);
|
||||||
|
return c -> getRegister(false, a - 0177700);
|
||||||
|
}
|
||||||
|
if (a >= 0177710 && a <= 0177715) { // user R0-R5
|
||||||
|
fprintf(stderr, "read user R%d\n", a - 0177710);
|
||||||
|
return c -> getRegister(true, a - 0177710);
|
||||||
|
}
|
||||||
|
if (a == 0177706) { // kernel SP
|
||||||
|
fprintf(stderr, "read kernel sp\n");
|
||||||
|
return c -> getStackPointer(0);
|
||||||
|
}
|
||||||
|
if (a == 0177707) { // PC
|
||||||
|
fprintf(stderr, "read pc\n");
|
||||||
|
return c -> getPC();
|
||||||
|
}
|
||||||
|
if (a == 0177716) { // supervisor SP
|
||||||
|
fprintf(stderr, "read supervisor sp\n");
|
||||||
|
return c -> getStackPointer(1);
|
||||||
|
}
|
||||||
|
if (a == 0177717) { // user SP
|
||||||
|
fprintf(stderr, "read user sp\n");
|
||||||
|
return c -> getStackPointer(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177766) { // cpu error register
|
||||||
|
fprintf(stderr, "read CPUERR\n");
|
||||||
|
return CPUERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tm11 && a >= TM_11_BASE && a < TM_11_END)
|
||||||
|
return word_mode ? tm11 -> readByte(a) : tm11 -> readWord(a);
|
||||||
|
|
||||||
|
if (rk05_ && a >= RK05_BASE && a < RK05_END)
|
||||||
|
return word_mode ? rk05_ -> readByte(a) : rk05_ -> readWord(a);
|
||||||
|
|
||||||
|
if (tty_ && a >= PDP11TTY_BASE && a < PDP11TTY_END)
|
||||||
|
return word_mode ? tty_ -> readByte(a) : tty_ -> readWord(a);
|
||||||
|
|
||||||
|
if (a & 1)
|
||||||
|
D(fprintf(stderr, "bus::readWord: odd address UNHANDLED %o\n", a);)
|
||||||
|
D(fprintf(stderr, "UNHANDLED read %o(%c)\n", a, word_mode ? 'B' : ' ');)
|
||||||
|
|
||||||
|
c -> busError();
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t apf = a >> 13; // active page field
|
||||||
|
bool is_user = use_prev ? (c -> getBitPSW(12) && c -> getBitPSW(13)) : (c -> getBitPSW(14) && c -> getBitPSW(15));
|
||||||
|
fprintf(stderr, "READ: is_user %d, offset %d\n", is_user, apf + is_user * 8);
|
||||||
|
uint32_t m_offset = pages[apf + is_user * 8].par * 64;
|
||||||
|
|
||||||
|
if ((a & 1) && word_mode == 0)
|
||||||
|
fprintf(stderr, "odd addressing\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "READ FROM %o\n", m_offset);
|
||||||
|
if (!word_mode)
|
||||||
|
temp = m -> readWord(m_offset + (a & 8191));
|
||||||
|
else
|
||||||
|
temp = m -> readByte(m_offset + (a & 8191));
|
||||||
|
|
||||||
|
// D(fprintf(stderr, "read bus %o(%d): %o\n", a, word_mode, temp);)
|
||||||
|
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t bus::write(const uint16_t a, const bool word_mode, uint16_t value, const bool use_prev)
|
||||||
|
{
|
||||||
|
//D(fprintf(stderr, "write bus %o(%d): %o\n", a, word_mode, value);)
|
||||||
|
|
||||||
|
assert(word_mode == 0 || value < 256);
|
||||||
|
|
||||||
|
if (a >= 0160000) {
|
||||||
|
fprintf(stderr, "write%c %o to I/O %o\n", word_mode ? 'b' : ' ', value, a);
|
||||||
|
|
||||||
|
if (word_mode) {
|
||||||
|
if (a == 0177776 || a == 0177777) { // PSW
|
||||||
|
D(fprintf(stderr, "writeb PSW %s\n", a & 1 ? "MSB" : "LSB");)
|
||||||
|
assert(value < 256);
|
||||||
|
uint16_t vtemp = c -> getPSW();
|
||||||
|
|
||||||
|
if (a & 1)
|
||||||
|
vtemp = (vtemp & 0x00ff) | (value << 8);
|
||||||
|
else
|
||||||
|
vtemp = (vtemp & 0xff00) | value;
|
||||||
|
|
||||||
|
c -> setPSW(vtemp);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177774 || a == 0177775) { // stack limit register
|
||||||
|
D(fprintf(stderr, "writeb Set stack limit register to %o\n", value);)
|
||||||
|
uint16_t v = c -> getStackLimitRegister();
|
||||||
|
|
||||||
|
if (a & 1)
|
||||||
|
v = (v & 0xff00) | value;
|
||||||
|
else
|
||||||
|
v = (v & 0x00ff) | (value << 8);
|
||||||
|
|
||||||
|
c -> setStackLimitRegister(v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (a == 0177776) { // PSW
|
||||||
|
D(fprintf(stderr, "write PSW %o\n", value);)
|
||||||
|
c -> setPSW(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177774) { // stack limit register
|
||||||
|
D(fprintf(stderr, "write Set stack limit register to %o\n", value);)
|
||||||
|
c -> setStackLimitRegister(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a >= 0177700 && a <= 0177705) { // kernel R0-R5
|
||||||
|
fprintf(stderr, "write kernel R%d to %o\n", a - 01777700, value);
|
||||||
|
c -> setRegister(false, a - 0177700, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (a >= 0177710 && a <= 0177715) { // user R0-R5
|
||||||
|
fprintf(stderr, "write user R%d to %o\n", a - 01777710, value);
|
||||||
|
c -> setRegister(true, a - 0177710, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (a == 0177706) { // kernel SP
|
||||||
|
fprintf(stderr, "write kernel SP to %o\n", value);
|
||||||
|
c -> setStackPointer(0, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (a == 0177707) { // PC
|
||||||
|
fprintf(stderr, "write PC to %o\n", value);
|
||||||
|
c -> setPC(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (a == 0177716) { // supervisor SP
|
||||||
|
fprintf(stderr, "write supervisor sp to %o\n", value);
|
||||||
|
c -> setStackPointer(1, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (a == 0177717) { // user SP
|
||||||
|
fprintf(stderr, "write user sp to %o\n", value);
|
||||||
|
c -> setStackPointer(3, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177766) { // cpu error register
|
||||||
|
fprintf(stderr, "write CPUERR %o\n", value);
|
||||||
|
CPUERR = 0;
|
||||||
|
return CPUERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0172516) { // MMR3
|
||||||
|
fprintf(stderr, "write set MMR3 to %o\n", value);
|
||||||
|
MMR3 = value;
|
||||||
|
return MMR3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177772) { // PIR
|
||||||
|
fprintf(stderr, "write set PIR to %o\n", value);
|
||||||
|
PIR = value; // FIXME
|
||||||
|
return PIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177546) { // line frequency clock and status register
|
||||||
|
fprintf(stderr, "write set LFC/SR to %o\n", value);
|
||||||
|
CSR = value;
|
||||||
|
return CSR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tm11 && a >= TM_11_BASE && a < TM_11_END) {
|
||||||
|
word_mode ? tm11 -> writeByte(a, value) : tm11 -> writeWord(a, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rk05_ && a >= RK05_BASE && a < RK05_END) {
|
||||||
|
word_mode ? rk05_ -> writeByte(a, value) : rk05_ -> writeWord(a, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tty_ && a >= PDP11TTY_BASE && a < PDP11TTY_END) {
|
||||||
|
word_mode ? tty_ -> writeByte(a, value) : tty_ -> writeWord(a, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// MMU ///
|
||||||
|
if (a >= 0172300 && a < 0172320) {
|
||||||
|
fprintf(stderr, "write set PDR for %d to %o\n", (a & 017) >> 1, value);
|
||||||
|
pages[((a & 017) >> 1)].pdr = value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a >= 0172340 && a < 0172360) {
|
||||||
|
fprintf(stderr, "write set PAR for %d to %o\n", (a & 017) >> 1, value);
|
||||||
|
pages[((a & 017) >> 1)].par = value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a >= 0117600 && a < 0117620) {
|
||||||
|
fprintf(stderr, "write set PDR for %d to %o\n", ((a & 017) >> 1) + 8, value);
|
||||||
|
pages[((a & 017) >> 1) + 8].pdr = value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a >= 0117640 && a < 0177660) {
|
||||||
|
fprintf(stderr, "write set PAR for %d to %o\n", ((a & 017) >> 1) + 8, value);
|
||||||
|
pages[((a & 017) >> 1) + 8].par = value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a == 0177746) { // cache control register
|
||||||
|
// FIXME
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////
|
||||||
|
|
||||||
|
if (a == 0177374) { // FIXME
|
||||||
|
fprintf(stderr, "char: %c\n", value & 127);
|
||||||
|
return 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a & 1)
|
||||||
|
D(fprintf(stderr, "bus::writeWord: odd address UNHANDLED\n");)
|
||||||
|
D(fprintf(stderr, "UNHANDLED write %o(%c): %o\n", a, word_mode ? 'B' : ' ', value);)
|
||||||
|
|
||||||
|
c -> busError();
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t apf = a >> 13; // active page field
|
||||||
|
bool is_user = use_prev ? (c -> getBitPSW(12) && c -> getBitPSW(13)) : (c -> getBitPSW(14) && c -> getBitPSW(15));
|
||||||
|
fprintf(stderr, "WRITE: is_user %d, offset %d\n", is_user, apf + is_user * 8);
|
||||||
|
uint32_t m_offset = pages[apf + is_user * 8].par * 64;
|
||||||
|
|
||||||
|
pages[apf].pdr |= 1 << 6; // page has been written to
|
||||||
|
|
||||||
|
if ((a & 1) && word_mode == 0)
|
||||||
|
fprintf(stderr, "odd addressing\n");
|
||||||
|
|
||||||
|
fprintf(stderr, "WRITE TO: %o\n", m_offset);
|
||||||
|
if (word_mode)
|
||||||
|
m -> writeByte(m_offset + (a & 8191), value);
|
||||||
|
else
|
||||||
|
m -> writeWord(m_offset + (a & 8191), value);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t bus::readWord(const uint16_t a)
|
||||||
|
{
|
||||||
|
return read(a, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t bus::writeWord(const uint16_t a, const uint16_t value)
|
||||||
|
{
|
||||||
|
write(a, false, value);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
59
bus.h
Normal file
59
bus.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "tm-11.h"
|
||||||
|
#include "rk05.h"
|
||||||
|
#include "rx02.h"
|
||||||
|
#include "tty.h"
|
||||||
|
|
||||||
|
class cpu;
|
||||||
|
class memory;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint16_t par, pdr;
|
||||||
|
} page_t;
|
||||||
|
|
||||||
|
class bus
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
cpu *c { nullptr };
|
||||||
|
tm_11 *tm11 { nullptr };
|
||||||
|
rk05 *rk05_ { nullptr };
|
||||||
|
rx02 *rx02_ { nullptr };
|
||||||
|
tty *tty_ { nullptr };
|
||||||
|
|
||||||
|
memory *m { nullptr };
|
||||||
|
|
||||||
|
page_t pages[16];
|
||||||
|
|
||||||
|
uint16_t MMR2 { 0 }, MMR3 { 0 }, CPUERR { 0 }, PIR { 0 }, CSR { 0 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
bus();
|
||||||
|
~bus();
|
||||||
|
|
||||||
|
void clearmem();
|
||||||
|
|
||||||
|
void add_cpu(cpu *const c) { this -> c = c; }
|
||||||
|
void add_tm11(tm_11 *tm11) { this -> tm11 = tm11; }
|
||||||
|
void add_rk05(rk05 *rk05_) { this -> rk05_ = rk05_; }
|
||||||
|
void add_rx02(rx02 *rx02_) { this -> rx02_ = rx02_; }
|
||||||
|
void add_tty(tty *tty_) { this -> tty_ = tty_; }
|
||||||
|
|
||||||
|
cpu *getCpu() { return this -> c; }
|
||||||
|
|
||||||
|
uint16_t read(const uint16_t a, const bool word_mode, const bool use_prev=false);
|
||||||
|
uint16_t readByte(const uint16_t a) { return read(a, true); }
|
||||||
|
uint16_t readWord(const uint16_t a);
|
||||||
|
|
||||||
|
uint16_t write(const uint16_t a, const bool word_mode, uint16_t value, const bool use_prev=false);
|
||||||
|
uint8_t writeByte(const uint16_t a, const uint8_t value) { return write(a, true, value); }
|
||||||
|
uint16_t writeWord(const uint16_t a, const uint16_t value);
|
||||||
|
|
||||||
|
void setMMR2(const uint16_t value) { MMR2 = value; }
|
||||||
|
};
|
92
cpu.h
Normal file
92
cpu.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "bus.h"
|
||||||
|
|
||||||
|
class cpu
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint16_t regs0_5[2][6]; // R0...5, selected by bit 11 in PSW,
|
||||||
|
uint16_t sp[3+1]; // stackpointers, MF../MT.. select via 12/13 from PSW, others via 14/15
|
||||||
|
uint16_t pc { 0 };
|
||||||
|
uint16_t psw { 0 }, fpsr { 0 };
|
||||||
|
uint16_t stackLimitRegister { 0 };
|
||||||
|
bool haltFlag { false }, resetFlag { false };
|
||||||
|
bool runMode { false };
|
||||||
|
|
||||||
|
bool emulateMFPT { false };
|
||||||
|
|
||||||
|
bus *const b { nullptr };
|
||||||
|
|
||||||
|
uint16_t getRegister(const int nr, const bool MF_MT) const;
|
||||||
|
void setRegister(const int nr, const bool MF_MT, const uint16_t value);
|
||||||
|
void addRegister(const int nr, const bool MF_MT, const uint16_t value);
|
||||||
|
|
||||||
|
uint16_t getGAMAddress(const uint8_t mode, const int reg, const bool word_mode, const bool MF_MT);
|
||||||
|
uint16_t getGAM(const uint8_t mode, const uint8_t reg, const bool word_mode, const bool MF_MT, std::string *const text);
|
||||||
|
void putGAM(const uint8_t mode, const int reg, const bool word_mode, const uint16_t value, const bool MF_FT, std::string *const text);
|
||||||
|
|
||||||
|
void switchModeToKernel();
|
||||||
|
|
||||||
|
bool double_operand_instructions(const uint16_t instr);
|
||||||
|
bool additional_double_operand_instructions(const uint16_t instr);
|
||||||
|
bool single_operand_instructions(const uint16_t instr);
|
||||||
|
bool conditional_branch_instructions(const uint16_t instr);
|
||||||
|
bool condition_code_operations(const uint16_t instr);
|
||||||
|
bool misc_operations(const uint16_t instr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit cpu(bus *const b);
|
||||||
|
~cpu();
|
||||||
|
|
||||||
|
bus *getBus() { return b; }
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
bool step(); // FIXME return mask of flags (halt, reset, etc)
|
||||||
|
void resetHalt() { haltFlag = false; }
|
||||||
|
void resetReset() { resetFlag = false; }
|
||||||
|
|
||||||
|
void pushStack(const uint16_t v);
|
||||||
|
uint16_t popStack();
|
||||||
|
|
||||||
|
void busError();
|
||||||
|
|
||||||
|
void setEmulateMFPT(const bool v) { emulateMFPT = v; }
|
||||||
|
|
||||||
|
bool getRunMode() { return runMode; }
|
||||||
|
|
||||||
|
bool getPSW_c() const;
|
||||||
|
bool getPSW_v() const;
|
||||||
|
bool getPSW_z() const;
|
||||||
|
bool getPSW_n() const;
|
||||||
|
bool getBitPSW(const int bit) const;
|
||||||
|
|
||||||
|
void setPSW_c(const bool v);
|
||||||
|
void setPSW_v(const bool v);
|
||||||
|
void setPSW_z(const bool v);
|
||||||
|
void setPSW_n(const bool v);
|
||||||
|
void setPSW_spl(const int v);
|
||||||
|
void setBitPSW(const int bit, const bool v);
|
||||||
|
|
||||||
|
uint16_t getPSW() const { return psw; }
|
||||||
|
void setPSW(const uint16_t v) { psw = v; }
|
||||||
|
|
||||||
|
uint16_t getStackLimitRegister() { return stackLimitRegister; }
|
||||||
|
void setStackLimitRegister(const uint16_t v) { stackLimitRegister = v; }
|
||||||
|
|
||||||
|
uint16_t getRegister(const bool user, const int nr) const { assert(nr >= 0 && nr < 6); return regs0_5[user][nr]; }
|
||||||
|
uint16_t getStackPointer(const int which) const { assert(which >= 0 && which < 4); return sp[which]; }
|
||||||
|
uint16_t getPC() const { return pc; }
|
||||||
|
|
||||||
|
void setRegister(const bool user, const int nr, const uint16_t value) { assert(nr >= 0 && nr < 6); regs0_5[user][nr] = value; }
|
||||||
|
void setStackPointer(const int which, const uint16_t value) { assert(which >= 0 && which < 4); sp[which] = value; }
|
||||||
|
void setPC(const uint16_t value) { pc = value; }
|
||||||
|
|
||||||
|
uint16_t getRegister(const int nr) const { return getRegister(nr, false); } // FIXME remove
|
||||||
|
void setRegister(const int nr, const uint16_t v) { setRegister(nr, false, v); } // FIXME remove
|
||||||
|
};
|
29
error.cpp
Normal file
29
error.cpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// (C) 2018 by folkert@vanheusden.com, released under AGPL 3.0
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <regex.h>
|
||||||
|
#include <ncursesw/ncurses.h>
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
[[ noreturn ]] void error_exit(bool sys_err, const char *format, ...)
|
||||||
|
{
|
||||||
|
int e = errno;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
(void)endwin();
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
(void)vfprintf(stderr, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (sys_err == TRUE)
|
||||||
|
fprintf(stderr, "error: %s (%d)\n", strerror(e), e);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
2
error.h
Normal file
2
error.h
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// (C) 2018 by folkert@vanheusden.com, released under AGPL 3.0
|
||||||
|
[[ noreturn ]] void error_exit(bool sys_err, const char *format, ...);
|
7
gen.h
Normal file
7
gen.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define D(x) do { x } while(0);
|
||||||
|
#else
|
||||||
|
#define D(...) do { } while(0);
|
||||||
|
#endif
|
329
main.cpp
Normal file
329
main.cpp
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
#include "cpu.h"
|
||||||
|
#include "tty.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "tests.h"
|
||||||
|
#include "terminal.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
void loadbin(bus *const b, uint16_t base, const char *const file)
|
||||||
|
{
|
||||||
|
FILE *fh = fopen(file, "rb");
|
||||||
|
|
||||||
|
while(!feof(fh))
|
||||||
|
b -> writeByte(base++, fgetc(fh));
|
||||||
|
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBootLoader(bus *const b)
|
||||||
|
{
|
||||||
|
cpu *const c = b -> getCpu();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
const uint16_t offset = 0200;
|
||||||
|
constexpr uint16_t bootrom[] = {
|
||||||
|
0012737,
|
||||||
|
0000400,
|
||||||
|
0177572,
|
||||||
|
0012737,
|
||||||
|
0070707,
|
||||||
|
0000200,
|
||||||
|
0000000
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
#if 1
|
||||||
|
const uint16_t offset = 01000;
|
||||||
|
constexpr uint16_t bootrom[] = {
|
||||||
|
0012700,
|
||||||
|
0177406,
|
||||||
|
0012710,
|
||||||
|
0177400,
|
||||||
|
0012740,
|
||||||
|
0000005,
|
||||||
|
0105710,
|
||||||
|
0100376,
|
||||||
|
0005007
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
const uint16_t offset = 02000;
|
||||||
|
constexpr uint16_t bootrom[] = {
|
||||||
|
// 0042113,
|
||||||
|
0012706,
|
||||||
|
0002000,
|
||||||
|
0012700,
|
||||||
|
0000000, /* boot unit */
|
||||||
|
0010003,
|
||||||
|
0000303,
|
||||||
|
0006303,
|
||||||
|
0006303,
|
||||||
|
0006303,
|
||||||
|
0006303,
|
||||||
|
0006303,
|
||||||
|
0012701,
|
||||||
|
0177412,
|
||||||
|
0010311,
|
||||||
|
0005041,
|
||||||
|
0012741,
|
||||||
|
0177000,
|
||||||
|
0012741,
|
||||||
|
0000005,
|
||||||
|
0005002,
|
||||||
|
0005003,
|
||||||
|
0012704,
|
||||||
|
0002020,
|
||||||
|
0005005,
|
||||||
|
0105711,
|
||||||
|
0100376,
|
||||||
|
0105011,
|
||||||
|
0005007
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FILE *fh = fopen("boot.dat", "wb");
|
||||||
|
|
||||||
|
for(size_t i=0; i<sizeof bootrom / 2; i++) {
|
||||||
|
b -> writeWord(offset + i * 2, bootrom[i]);
|
||||||
|
fputc(bootrom[i] & 255, fh);
|
||||||
|
fputc(bootrom[i] >> 8, fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fh);
|
||||||
|
|
||||||
|
c -> setRegister(7, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t loadTape(bus *const b, const char *const file)
|
||||||
|
{
|
||||||
|
FILE *fh = fopen(file, "rb");
|
||||||
|
if (!fh) {
|
||||||
|
fprintf(stderr, "Cannot open %s\n", file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t start = 0, end = 0;
|
||||||
|
|
||||||
|
for(;!feof(fh);) {
|
||||||
|
uint8_t buffer[6];
|
||||||
|
|
||||||
|
if (fread(buffer, 1, 6, fh) != 6)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int count = (buffer[3] << 8) | buffer[2];
|
||||||
|
int p = (buffer[5] << 8) | buffer[4];
|
||||||
|
|
||||||
|
uint8_t csum = 0;
|
||||||
|
for(int i=2; i<6; i++)
|
||||||
|
csum += buffer[i];
|
||||||
|
|
||||||
|
if (count == 6) { // eg no data
|
||||||
|
if (p != 1) {
|
||||||
|
fprintf(stderr, "Setting start address to %o\n", p);
|
||||||
|
start = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "%ld] reading %d (dec) bytes to %o (oct)\n", ftell(fh), count - 6, p);
|
||||||
|
|
||||||
|
for(int i=0; i<count - 6; i++) {
|
||||||
|
if (feof(fh)) {
|
||||||
|
fprintf(stderr, "short read\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
uint8_t c = fgetc(fh);
|
||||||
|
|
||||||
|
csum += c;
|
||||||
|
b -> writeByte(p++, c);
|
||||||
|
|
||||||
|
if (p > end)
|
||||||
|
end = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fcs = fgetc(fh);
|
||||||
|
csum += fcs;
|
||||||
|
|
||||||
|
if (csum != 255)
|
||||||
|
fprintf(stderr, "checksum error %d\n", csum);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fh);
|
||||||
|
|
||||||
|
fh = fopen("test.dat", "wb");
|
||||||
|
for(int i=0; i<end; i++)
|
||||||
|
fputc(b -> readByte(i), fh);
|
||||||
|
fclose(fh);
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
NEWWIN *w_main_b = nullptr, *w_main = nullptr;
|
||||||
|
|
||||||
|
void resize_terminal()
|
||||||
|
{
|
||||||
|
determine_terminal_size();
|
||||||
|
|
||||||
|
if (ERR == resizeterm(max_y, max_x))
|
||||||
|
error_exit(true, "problem resizing terminal");
|
||||||
|
|
||||||
|
wresize(stdscr, max_y, max_x);
|
||||||
|
|
||||||
|
endwin();
|
||||||
|
refresh();
|
||||||
|
|
||||||
|
wclear(stdscr);
|
||||||
|
|
||||||
|
delete_window(w_main_b);
|
||||||
|
delete_window(w_main);
|
||||||
|
create_win_border(0, 0, max_x - 2, max_y - 2, "window", &w_main_b, &w_main, false);
|
||||||
|
scrollok(w_main -> win, TRUE);
|
||||||
|
|
||||||
|
mydoupdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile bool sw = false;
|
||||||
|
void sw_handler(int s)
|
||||||
|
{
|
||||||
|
sw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void help()
|
||||||
|
{
|
||||||
|
printf("-h this help\n");
|
||||||
|
printf("-m mode \"test\": for running xxdp (stop on bell)\n");
|
||||||
|
printf(" \"tc\": run testcases\n");
|
||||||
|
printf("-T t.bin load file as a binary tape file (like simh \"load\" command)\n");
|
||||||
|
printf("-R d.rk load file as a RK05 disk device\n");
|
||||||
|
printf("-p 123 set CPU start pointer to decimal(!) value\n");
|
||||||
|
printf("-L f.bin load file into memory at address given by -p (and run it)\n");
|
||||||
|
printf("-n ncurses UI\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
//setlocale(LC_ALL, "");
|
||||||
|
|
||||||
|
bus *b = new bus();
|
||||||
|
cpu *c = new cpu(b);
|
||||||
|
b->add_cpu(c);
|
||||||
|
|
||||||
|
c -> setEmulateMFPT(true);
|
||||||
|
|
||||||
|
bool testMode = false, testCases = false, withUI = false;
|
||||||
|
int opt = -1;
|
||||||
|
while((opt = getopt(argc, argv, "hm:T:R:p:nL:")) != -1)
|
||||||
|
{
|
||||||
|
switch(opt) {
|
||||||
|
case 'h':
|
||||||
|
help();
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case 'n':
|
||||||
|
withUI = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'm':
|
||||||
|
if (strcasecmp(optarg, "test") == 0)
|
||||||
|
testMode = true;
|
||||||
|
else if (strcasecmp(optarg, "tc") == 0)
|
||||||
|
testCases = true;
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "\"-m %s\" is not known\n", optarg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'T':
|
||||||
|
c->setRegister(7, loadTape(b, optarg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'R': {
|
||||||
|
b->add_rk05(new rk05(optarg, b));
|
||||||
|
setBootLoader(b);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
c->setRegister(7, atoi(optarg));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'L':
|
||||||
|
loadbin(b, c->getRegister(7), optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "-%c is not understood\n", opt);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tty *tty_ = new tty(withUI);
|
||||||
|
b->add_tty(tty_);
|
||||||
|
|
||||||
|
if (testMode)
|
||||||
|
tty_->setTest();
|
||||||
|
|
||||||
|
if (testCases)
|
||||||
|
tests(c);
|
||||||
|
|
||||||
|
fprintf(stderr, "Start running at %o\n", c->getRegister(7));
|
||||||
|
|
||||||
|
if (withUI) {
|
||||||
|
init_ncurses(true);
|
||||||
|
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = sw_handler;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
sigaction(SIGWINCH, &sa, nullptr);
|
||||||
|
resize_terminal();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pollfd fds[] = { { 0, POLLIN, 0 } };
|
||||||
|
|
||||||
|
const unsigned long start = get_ms();
|
||||||
|
unsigned long icount = 0;
|
||||||
|
for(;;) {
|
||||||
|
if (c->step()) {
|
||||||
|
//c->setRegister(7, 01000);
|
||||||
|
//c->resetHalt();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
icount++;
|
||||||
|
|
||||||
|
if (icount % 1000 == 0) {
|
||||||
|
if (poll(fds, 1, 0) == 1) {
|
||||||
|
int ch = getch();
|
||||||
|
|
||||||
|
if (ch == 3)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (ch > 0 && ch < 127)
|
||||||
|
tty_->sendChar(ch);
|
||||||
|
|
||||||
|
fds[0].revents = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icount % 1000000 == 0 && withUI) {
|
||||||
|
unsigned long now = get_ms();
|
||||||
|
mvwprintw(w_main_b -> win, 0, 24, "%.1f/s ", icount * 1000.0 / (now - start));
|
||||||
|
mydoupdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (withUI)
|
||||||
|
endwin();
|
||||||
|
|
||||||
|
delete b;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
20
memory.cpp
Normal file
20
memory.cpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
memory::memory(const uint32_t size) : size(size)
|
||||||
|
{
|
||||||
|
m = new uint8_t[size]();
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::~memory()
|
||||||
|
{
|
||||||
|
delete [] m;
|
||||||
|
}
|
||||||
|
|
||||||
|
void memory::reset()
|
||||||
|
{
|
||||||
|
memset(m, 0x00, size);
|
||||||
|
}
|
24
memory.h
Normal file
24
memory.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class memory
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
const uint32_t size;
|
||||||
|
uint8_t *m { nullptr };
|
||||||
|
|
||||||
|
public:
|
||||||
|
memory(const uint32_t size);
|
||||||
|
~memory();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint16_t readByte(const uint16_t a) const { return m[a]; }
|
||||||
|
void writeByte(const uint16_t a, const uint16_t v) { m[a] = v; }
|
||||||
|
|
||||||
|
uint16_t readWord(const uint16_t a) const { return m[a] | (m[a + 1] << 8); }
|
||||||
|
void writeWord(const uint16_t a, const uint16_t v) { m[a] = v; m[a + 1] = v >> 8; }
|
||||||
|
};
|
209
rk05.cpp
Normal file
209
rk05.cpp
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "rk05.h"
|
||||||
|
#include "gen.h"
|
||||||
|
#include "bus.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
const char * const regnames[] = {
|
||||||
|
"RK05_DS drivestatus",
|
||||||
|
"RK05_ERROR ",
|
||||||
|
"RK05_CS ctrlstatus",
|
||||||
|
"RK05_WC word count",
|
||||||
|
"RK05_BA busaddress",
|
||||||
|
"RK05_DA disk addrs",
|
||||||
|
"RK05_DATABUF "
|
||||||
|
};
|
||||||
|
|
||||||
|
rk05::rk05(const std::string & file, bus *const b) : b(b)
|
||||||
|
{
|
||||||
|
memset(registers, 0x00, sizeof registers);
|
||||||
|
memset(xfer_buffer, 0x00, sizeof xfer_buffer);
|
||||||
|
|
||||||
|
fh = fopen(file.c_str(), "rb");
|
||||||
|
}
|
||||||
|
|
||||||
|
rk05::~rk05()
|
||||||
|
{
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t rk05::readByte(const uint16_t addr)
|
||||||
|
{
|
||||||
|
uint16_t v = readWord(addr & ~1);
|
||||||
|
|
||||||
|
if (addr & 1)
|
||||||
|
return v >> 8;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t rk05::readWord(const uint16_t addr)
|
||||||
|
{
|
||||||
|
const int reg = (addr - RK05_BASE) / 2;
|
||||||
|
|
||||||
|
fprintf(stderr, "RK05 read %s/%o: ", reg[regnames], addr);
|
||||||
|
|
||||||
|
if (addr == RK05_DS) { // 0177400
|
||||||
|
setBit(registers[reg], 11, true); // disk on-line
|
||||||
|
setBit(registers[reg], 8, true); // sector ok
|
||||||
|
setBit(registers[reg], 7, true); // drive ready
|
||||||
|
setBit(registers[reg], 6, true); // seek ready
|
||||||
|
setBit(registers[reg], 4, true); // heads in position
|
||||||
|
}
|
||||||
|
else if (addr == RK05_ERROR) // 0177402
|
||||||
|
registers[reg] = 0;
|
||||||
|
else if (addr == RK05_CS) { // 0177404
|
||||||
|
setBit(registers[reg], 15, false); // clear error
|
||||||
|
setBit(registers[reg], 14, false); // clear hard error
|
||||||
|
#if 0
|
||||||
|
if (registers[reg] & 1)
|
||||||
|
registers[reg] &= ~128; // controller ready
|
||||||
|
else
|
||||||
|
registers[reg] |= 128; // controller ready
|
||||||
|
#else
|
||||||
|
setBit(registers[reg], 7, true); // controller ready
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t vtemp = registers[reg];
|
||||||
|
|
||||||
|
if (addr == RK05_CS)
|
||||||
|
setBit(registers[reg], 0, false); // clear go
|
||||||
|
|
||||||
|
fprintf(stderr, "%o\n", vtemp);
|
||||||
|
|
||||||
|
return vtemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk05::writeByte(const uint16_t addr, const uint8_t v)
|
||||||
|
{
|
||||||
|
uint16_t vtemp = registers[(addr - RK05_BASE) / 2];
|
||||||
|
|
||||||
|
if (addr & 1) {
|
||||||
|
vtemp &= ~0xff00;
|
||||||
|
vtemp |= v << 8;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vtemp &= ~0x00ff;
|
||||||
|
vtemp |= v;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeWord(addr, vtemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rk05::writeWord(const uint16_t addr, uint16_t v)
|
||||||
|
{
|
||||||
|
const int reg = (addr - RK05_BASE) / 2;
|
||||||
|
fprintf(stderr, "RK05 write %s/%o: %o\n", regnames[reg], addr, v);
|
||||||
|
|
||||||
|
if (addr == RK05_CS) {
|
||||||
|
if (v & 1) { // GO
|
||||||
|
const int func = (v >> 1) & 7; // FUNCTION
|
||||||
|
int16_t wc = registers[(RK05_WC - RK05_BASE) / 2];
|
||||||
|
const size_t reclen = wc < 0 ? (-wc * 2) : wc * 2;
|
||||||
|
fprintf(stderr, "RK05 rec len %zd\n", reclen);
|
||||||
|
|
||||||
|
uint16_t dummy = registers[(RK05_DA - RK05_BASE) / 2];
|
||||||
|
uint8_t sector = dummy & 0b1111;
|
||||||
|
uint8_t surface = (dummy >> 4) & 1;
|
||||||
|
int track = (dummy >> 4) & 511;
|
||||||
|
uint16_t cylinder = (dummy >> 5) & 255;
|
||||||
|
fprintf(stderr, "RK05 position sec %d surf %d cyl %d\n", sector, surface, cylinder);
|
||||||
|
|
||||||
|
const int diskoff = track * 12 + sector;
|
||||||
|
|
||||||
|
const int diskoffb = diskoff * 512; // RK05 is high density
|
||||||
|
const uint16_t memoff = registers[(RK05_BA - RK05_BASE) / 2];
|
||||||
|
|
||||||
|
fprintf(stderr, "invoke %d\n", func);
|
||||||
|
|
||||||
|
if (func == 0) { // controller reset
|
||||||
|
}
|
||||||
|
else if (func == 1) { // write
|
||||||
|
D(fprintf(stderr, "RK05 writing %zo bytes to offset %o (%d dec)\n", reclen, diskoffb, diskoffb);)
|
||||||
|
|
||||||
|
int p = reclen; // FIXME
|
||||||
|
for(size_t i=0; i<reclen; i++)
|
||||||
|
xfer_buffer[i] = b -> readByte(memoff + i);
|
||||||
|
|
||||||
|
if (fseek(fh, diskoffb, SEEK_SET) == -1)
|
||||||
|
fprintf(stderr, "RK05 seek error %s\n", strerror(errno));
|
||||||
|
if (fwrite(xfer_buffer, 1, reclen, fh) != reclen)
|
||||||
|
fprintf(stderr, "RK05 fwrite error %s\n", strerror(errno));
|
||||||
|
|
||||||
|
if (v & 2048)
|
||||||
|
fprintf(stderr, "RK05 inhibit BA increase\n");
|
||||||
|
else
|
||||||
|
registers[(RK05_BA - RK05_BASE) / 2] += p;
|
||||||
|
|
||||||
|
if (++sector >= 12) {
|
||||||
|
sector = 0;
|
||||||
|
if (++surface >= 2) {
|
||||||
|
surface = 0;
|
||||||
|
cylinder++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registers[(RK05_DA - RK05_BASE) / 2] = sector | (surface << 4) | (cylinder << 5);
|
||||||
|
}
|
||||||
|
else if (func == 2) { // read
|
||||||
|
fprintf(stderr, "RK05 reading %zo bytes from offset %o (%d dec) to %o\n", reclen, diskoffb, diskoffb, memoff);
|
||||||
|
|
||||||
|
if (fseek(fh, diskoffb, SEEK_SET) == -1)
|
||||||
|
fprintf(stderr, "RK05 seek error %s\n", strerror(errno));
|
||||||
|
|
||||||
|
int temp = reclen;
|
||||||
|
int p = memoff;
|
||||||
|
while(temp > 0) {
|
||||||
|
int cur = std::min(int(sizeof xfer_buffer), temp);
|
||||||
|
|
||||||
|
if (fread(xfer_buffer, 1, cur, fh) != size_t(cur))
|
||||||
|
D(fprintf(stderr, "RK05 fread error: %s\n", strerror(errno));)
|
||||||
|
|
||||||
|
for(int i=0; i<cur; i++) {
|
||||||
|
if (p < 0160000)
|
||||||
|
b -> writeByte(p, xfer_buffer[i]);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp -= cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v & 2048)
|
||||||
|
fprintf(stderr, "RK05 inhibit BA increase\n");
|
||||||
|
else
|
||||||
|
registers[(RK05_BA - RK05_BASE) / 2] += p;
|
||||||
|
|
||||||
|
if (++sector >= 12) {
|
||||||
|
sector = 0;
|
||||||
|
if (++surface >= 2) {
|
||||||
|
surface = 0;
|
||||||
|
cylinder++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
registers[(RK05_DA - RK05_BASE) / 2] = sector | (surface << 4) | (cylinder << 5);
|
||||||
|
}
|
||||||
|
else if (func == 4) {
|
||||||
|
fprintf(stderr, "RK05 seek to offset %o\n", diskoffb);
|
||||||
|
}
|
||||||
|
else if (func == 7)
|
||||||
|
fprintf(stderr, "RK05 write lock\n");
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "RK05 command %d UNHANDLED\n", func);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v & 64) { // bit 6, invoke interrupt when done vector address 220, see http://www.pdp-11.nl/peripherals/disk/rk05-info.html
|
||||||
|
fprintf(stderr, "RK05 HIER\n"); // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
registers[(RK05_WC - RK05_BASE) / 2] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
D(fprintf(stderr, "set register %o to %o\n", addr, v);)
|
||||||
|
registers[reg] = v;
|
||||||
|
}
|
39
rk05.h
Normal file
39
rk05.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// FIXME namen van defines
|
||||||
|
#define RK05_DS 0177400 // drive status
|
||||||
|
#define RK05_ERROR 0177402 // error
|
||||||
|
#define RK05_CS 0177404 // control status
|
||||||
|
#define RK05_WC 0177406 // word count
|
||||||
|
#define RK05_BA 0177410 // bus address
|
||||||
|
#define RK05_DA 0177412 // disk address
|
||||||
|
#define RK05_DATABUF 0177414 // data buffer
|
||||||
|
#define RK05_BASE RK05_DS
|
||||||
|
#define RK05_END (RK05_DATABUF + 2)
|
||||||
|
|
||||||
|
class bus;
|
||||||
|
|
||||||
|
class rk05
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bus *const b;
|
||||||
|
uint16_t registers[7];
|
||||||
|
uint8_t xfer_buffer[512];
|
||||||
|
FILE *fh;
|
||||||
|
|
||||||
|
public:
|
||||||
|
rk05(const std::string & file, bus *const b);
|
||||||
|
virtual ~rk05();
|
||||||
|
|
||||||
|
uint8_t readByte(const uint16_t addr);
|
||||||
|
uint16_t readWord(const uint16_t addr);
|
||||||
|
|
||||||
|
void writeByte(const uint16_t addr, const uint8_t v);
|
||||||
|
void writeWord(const uint16_t addr, uint16_t v);
|
||||||
|
};
|
72
rx02.cpp
Normal file
72
rx02.cpp
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "rx02.h"
|
||||||
|
#include "gen.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
rx02::rx02(const std::string & file, memory *const m) : m(m)
|
||||||
|
{
|
||||||
|
offset = 0;
|
||||||
|
memset(registers, 0x00, sizeof registers);
|
||||||
|
|
||||||
|
fh = fopen(file.c_str(), "rb");
|
||||||
|
}
|
||||||
|
|
||||||
|
rx02::~rx02()
|
||||||
|
{
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t rx02::readByte(const uint16_t addr)
|
||||||
|
{
|
||||||
|
uint16_t v = readWord(addr & ~1);
|
||||||
|
|
||||||
|
if (addr & 1)
|
||||||
|
return v >> 8;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t rx02::readWord(const uint16_t addr)
|
||||||
|
{
|
||||||
|
const int reg = (addr - RX02_BASE) / 2;
|
||||||
|
uint16_t vtemp = registers[reg];
|
||||||
|
|
||||||
|
D(printf("RX02 read addr %o: ", addr);)
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
|
||||||
|
D(printf("%o\n", vtemp);)
|
||||||
|
|
||||||
|
return vtemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rx02::writeByte(const uint16_t addr, const uint8_t v)
|
||||||
|
{
|
||||||
|
uint16_t vtemp = registers[(addr - RX02_BASE) / 2];
|
||||||
|
|
||||||
|
if (addr & 1) {
|
||||||
|
vtemp &= ~0xff00;
|
||||||
|
vtemp |= v << 8;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vtemp &= ~0x00ff;
|
||||||
|
vtemp |= v;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeWord(addr, vtemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rx02::writeWord(const uint16_t addr, uint16_t v)
|
||||||
|
{
|
||||||
|
D(printf("RX02 write %o: %o\n", addr, v);)
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
|
||||||
|
D(printf("set register %o to %o\n", addr, v);)
|
||||||
|
registers[(addr - RX02_BASE) / 2] = v;
|
||||||
|
}
|
33
rx02.h
Normal file
33
rx02.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
// FIXME namen van defines
|
||||||
|
#define RX02_BASE 0
|
||||||
|
#define RX02_END (1 + 2)
|
||||||
|
|
||||||
|
class memory;
|
||||||
|
|
||||||
|
class rx02
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
memory *const m;
|
||||||
|
uint16_t registers[7];
|
||||||
|
uint8_t xfer_buffer[512];
|
||||||
|
int offset;
|
||||||
|
FILE *fh;
|
||||||
|
|
||||||
|
public:
|
||||||
|
rx02(const std::string & file, memory *const m);
|
||||||
|
virtual ~rx02();
|
||||||
|
|
||||||
|
uint8_t readByte(const uint16_t addr);
|
||||||
|
uint16_t readWord(const uint16_t addr);
|
||||||
|
|
||||||
|
void writeByte(const uint16_t addr, const uint8_t v);
|
||||||
|
void writeWord(const uint16_t addr, uint16_t v);
|
||||||
|
};
|
322
terminal.cpp
Normal file
322
terminal.cpp
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
// (C) 2018 by folkert@vanheusden.com, released under AGPL 3.0
|
||||||
|
#include <algorithm>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ncursesw/curses.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include "terminal.h"
|
||||||
|
#include "error.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
int max_x = 80, max_y = 25;
|
||||||
|
|
||||||
|
void determine_terminal_size()
|
||||||
|
{
|
||||||
|
struct winsize size;
|
||||||
|
|
||||||
|
if (ioctl(1, TIOCGWINSZ, &size) == 0)
|
||||||
|
{
|
||||||
|
max_y = size.ws_row;
|
||||||
|
max_x = size.ws_col;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *dummy = getenv("COLUMNS");
|
||||||
|
if (dummy)
|
||||||
|
max_x = atoi(dummy);
|
||||||
|
|
||||||
|
dummy = getenv("LINES");
|
||||||
|
if (dummy)
|
||||||
|
max_x = atoi(dummy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_mouse_setting(void)
|
||||||
|
{
|
||||||
|
if (1) // FIXME (ignore_mouse)
|
||||||
|
mousemask(0, nullptr);
|
||||||
|
else
|
||||||
|
mousemask(BUTTON1_CLICKED | BUTTON1_DOUBLE_CLICKED | BUTTON3_CLICKED, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_ncurses(bool init_mouse)
|
||||||
|
{
|
||||||
|
initscr();
|
||||||
|
start_color();
|
||||||
|
use_default_colors();
|
||||||
|
keypad(stdscr, TRUE);
|
||||||
|
cbreak();
|
||||||
|
intrflush(stdscr, FALSE);
|
||||||
|
noecho();
|
||||||
|
nonl();
|
||||||
|
refresh();
|
||||||
|
nodelay(stdscr, FALSE);
|
||||||
|
meta(stdscr, TRUE); /* enable 8-bit input */
|
||||||
|
raw(); /* to be able to catch ctrl+c */
|
||||||
|
leaveok(stdscr, FALSE);
|
||||||
|
|
||||||
|
if (init_mouse)
|
||||||
|
apply_mouse_setting();
|
||||||
|
|
||||||
|
max_y = LINES;
|
||||||
|
max_x = COLS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wrong_key(void)
|
||||||
|
{
|
||||||
|
flash();
|
||||||
|
beep();
|
||||||
|
flushinp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_on(NEWWIN *win, int pair)
|
||||||
|
{
|
||||||
|
wattron(win -> win, COLOR_PAIR(pair));
|
||||||
|
}
|
||||||
|
|
||||||
|
void color_off(NEWWIN *win, int pair)
|
||||||
|
{
|
||||||
|
wattroff(win -> win, COLOR_PAIR(pair));
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_window(NEWWIN *mywin)
|
||||||
|
{
|
||||||
|
mydelwin(mywin);
|
||||||
|
|
||||||
|
free(mywin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mydelwin(NEWWIN *win)
|
||||||
|
{
|
||||||
|
if (win)
|
||||||
|
{
|
||||||
|
if (win -> pwin && ERR == del_panel(win -> pwin))
|
||||||
|
error_exit(false, "del_panel() failed");
|
||||||
|
|
||||||
|
if (win -> win && ERR == delwin(win -> win))
|
||||||
|
error_exit(false, "delwin() failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mydoupdate()
|
||||||
|
{
|
||||||
|
update_panels();
|
||||||
|
|
||||||
|
#if 0 // FIXME
|
||||||
|
else if (input_window)
|
||||||
|
{
|
||||||
|
wmove(input_window -> win, 0, ul_x);
|
||||||
|
setsyx(input_window -> y + 0, input_window -> x + ul_x);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
doupdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
WINDOW * mynewwin(int nlines, int ncols, int y, int x)
|
||||||
|
{
|
||||||
|
assert(x >= 0 && y >= 0);
|
||||||
|
assert(x < max_x && y < max_y);
|
||||||
|
assert(x + ncols <= max_x && y + nlines <= max_y);
|
||||||
|
|
||||||
|
WINDOW *dummy = newwin(nlines, ncols, y, x);
|
||||||
|
if (!dummy)
|
||||||
|
error_exit(false, "failed to create window (subwin) with dimensions %d-%d at offset %d,%d (terminal size: %d,%d)", ncols, nlines, x, y, max_x, max_y);
|
||||||
|
|
||||||
|
keypad(dummy, TRUE);
|
||||||
|
leaveok(dummy, TRUE);
|
||||||
|
|
||||||
|
return dummy;
|
||||||
|
}
|
||||||
|
|
||||||
|
NEWWIN * create_window(int n_lines, int n_colls)
|
||||||
|
{
|
||||||
|
return create_window_xy((max_y/2) - (n_lines/2), (max_x/2) - (n_colls/2), n_lines, n_colls);
|
||||||
|
}
|
||||||
|
|
||||||
|
NEWWIN * create_window_xy(int y, int x, int n_lines, int n_colls)
|
||||||
|
{
|
||||||
|
assert(x >= 0 && y >= 0);
|
||||||
|
assert(x < max_x && y < max_y);
|
||||||
|
assert(x + n_colls <= max_x && y + n_lines <= max_y);
|
||||||
|
NEWWIN *newwin = (NEWWIN *)malloc(sizeof(NEWWIN));
|
||||||
|
|
||||||
|
/* create new window */
|
||||||
|
newwin -> win = mynewwin(n_lines, n_colls, y, x);
|
||||||
|
newwin -> pwin = new_panel(newwin -> win);
|
||||||
|
werase(newwin -> win);
|
||||||
|
|
||||||
|
newwin -> ncols = n_colls;
|
||||||
|
newwin -> nlines = n_lines;
|
||||||
|
|
||||||
|
newwin -> x = x;
|
||||||
|
newwin -> y = y;
|
||||||
|
|
||||||
|
return newwin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void limit_print(NEWWIN *win, int width, int y, int x, char *format, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
int len = 0;
|
||||||
|
char *buf = nullptr;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
len = vasprintf(&buf, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (len > width)
|
||||||
|
buf[width] = 0x00;
|
||||||
|
|
||||||
|
mvwprintw(win -> win, y, x, "%s", buf);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void escape_print_xy(NEWWIN *win, int y, int x, char *str)
|
||||||
|
{
|
||||||
|
int loop = 0, cursor_x = 0, len = strlen(str);
|
||||||
|
bool inv = false, underline = false;
|
||||||
|
|
||||||
|
for(loop=0; loop<len; loop++)
|
||||||
|
{
|
||||||
|
if (str[loop] == '^')
|
||||||
|
{
|
||||||
|
if (!inv)
|
||||||
|
mywattron(win -> win, A_REVERSE);
|
||||||
|
else
|
||||||
|
mywattroff(win -> win, A_REVERSE);
|
||||||
|
|
||||||
|
inv = 1 - inv;
|
||||||
|
}
|
||||||
|
else if (str[loop] == '_')
|
||||||
|
{
|
||||||
|
if (!underline)
|
||||||
|
mywattron(win -> win, A_UNDERLINE);
|
||||||
|
else
|
||||||
|
mywattroff(win -> win, A_UNDERLINE);
|
||||||
|
|
||||||
|
underline = 1 - underline;
|
||||||
|
}
|
||||||
|
else if (str[loop] == '\n')
|
||||||
|
{
|
||||||
|
cursor_x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mvwprintw(win -> win, y, x + cursor_x++, "%c", str[loop]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inv)
|
||||||
|
mywattroff(win -> win, A_REVERSE);
|
||||||
|
|
||||||
|
if (underline)
|
||||||
|
mywattroff(win -> win, A_UNDERLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void escape_print(NEWWIN *win, const char *str, const char rev, const char un)
|
||||||
|
{
|
||||||
|
int loop, len = strlen(str);
|
||||||
|
bool inv = false, underline = false;
|
||||||
|
|
||||||
|
for(loop=0; loop<len; loop++)
|
||||||
|
{
|
||||||
|
if (str[loop] == rev)
|
||||||
|
{
|
||||||
|
if (!inv)
|
||||||
|
mywattron(win -> win, A_REVERSE);
|
||||||
|
else
|
||||||
|
mywattroff(win -> win, A_REVERSE);
|
||||||
|
|
||||||
|
inv = 1 - inv;
|
||||||
|
}
|
||||||
|
else if (str[loop] == un)
|
||||||
|
{
|
||||||
|
if (!underline)
|
||||||
|
mywattron(win -> win, A_UNDERLINE);
|
||||||
|
else
|
||||||
|
mywattroff(win -> win, A_UNDERLINE);
|
||||||
|
|
||||||
|
underline = 1 - underline;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
waddch(win -> win, str[loop]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inv)
|
||||||
|
mywattroff(win -> win, A_REVERSE);
|
||||||
|
|
||||||
|
if (underline)
|
||||||
|
mywattroff(win -> win, A_UNDERLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_win_border(int x, int y, int width, int height, const char *title, NEWWIN **bwin, NEWWIN **win, bool f1, bool with_blank_border)
|
||||||
|
{
|
||||||
|
assert(x >= 0 && y >= 0);
|
||||||
|
assert(x < max_x && y < max_y);
|
||||||
|
assert(x + width <= max_x && y + height <= max_y);
|
||||||
|
const char f1_for_help [] = " F1 for help ";
|
||||||
|
|
||||||
|
bool wbb = with_blank_border;
|
||||||
|
|
||||||
|
*bwin = create_window_xy(y + 0, x + 0, height + 2 + wbb * 2, width + 2 + wbb * 2);
|
||||||
|
*win = create_window_xy(y + 1 + wbb, x + 1 + wbb, height + 0, width + 0);
|
||||||
|
|
||||||
|
mywattron((*bwin) -> win, A_REVERSE);
|
||||||
|
box((*bwin) -> win, 0, 0);
|
||||||
|
mywattroff((*bwin) -> win, A_REVERSE);
|
||||||
|
|
||||||
|
mywattron((*bwin) -> win, A_STANDOUT);
|
||||||
|
|
||||||
|
mvwprintw((*bwin) -> win, 0, 1, "[ %s ]", title);
|
||||||
|
|
||||||
|
if (f1)
|
||||||
|
mvwprintw((*bwin) -> win, (*bwin) -> nlines - 1, 2, "[ %s ]", f1_for_help);
|
||||||
|
|
||||||
|
mywattroff((*bwin) -> win, A_STANDOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_wb_popup(int width, int height, const char *title, NEWWIN **bwin, NEWWIN **win)
|
||||||
|
{
|
||||||
|
create_win_border(max_x / 2 - width / 2, max_y / 2 - height / 2, width, height, title, bwin, win, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mywattron(WINDOW *w, int a)
|
||||||
|
{
|
||||||
|
if (a != A_BLINK && a != A_BOLD && a != A_NORMAL && a != A_REVERSE && a != A_STANDOUT && a != A_UNDERLINE)
|
||||||
|
error_exit(false, "funny attributes: %d", a);
|
||||||
|
|
||||||
|
wattron(w, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mywattroff(WINDOW *w, int a)
|
||||||
|
{
|
||||||
|
if (a != A_BLINK && a != A_BOLD && a != A_NORMAL && a != A_REVERSE && a != A_STANDOUT && a != A_UNDERLINE)
|
||||||
|
error_exit(false, "funny attributes: %d", a);
|
||||||
|
|
||||||
|
wattroff(w, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_attributes(NEWWIN *win)
|
||||||
|
{
|
||||||
|
wattrset(win -> win, A_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_in_window(NEWWIN *win, int x, int y)
|
||||||
|
{
|
||||||
|
return wenclose(win -> win, y, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool right_mouse_button_clicked(void)
|
||||||
|
{
|
||||||
|
MEVENT event;
|
||||||
|
|
||||||
|
return getmouse(&event) == OK && (event.bstate & BUTTON3_CLICKED);
|
||||||
|
}
|
46
terminal.h
Normal file
46
terminal.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// (C) 2018 by folkert@vanheusden.com, released under AGPL 3.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <ncurses.h>
|
||||||
|
#include <panel.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
WINDOW *win;
|
||||||
|
PANEL *pwin;
|
||||||
|
|
||||||
|
unsigned nlines, ncols;
|
||||||
|
int x, y;
|
||||||
|
} NEWWIN;
|
||||||
|
|
||||||
|
extern int default_colorpair, highlight_colorpair, meta_colorpair, error_colorpair, notice_colorpair, markerline_colorpair;
|
||||||
|
extern int max_y, max_x;
|
||||||
|
|
||||||
|
void wrong_key(void);
|
||||||
|
void color_on(NEWWIN *win, int pair);
|
||||||
|
void color_off(NEWWIN *win, int pair);
|
||||||
|
void mywattron(WINDOW *w, int a);
|
||||||
|
void mywattroff(WINDOW *w, int a);
|
||||||
|
void mywbkgd(NEWWIN *win, int pair);
|
||||||
|
void mydelwin(NEWWIN *win);
|
||||||
|
void mydoupdate();
|
||||||
|
void delete_window(NEWWIN *mywin);
|
||||||
|
NEWWIN * create_window(int n_lines, int n_colls);
|
||||||
|
NEWWIN * create_window_xy(int y_offset, int x_offset, int n_lines, int n_colls);
|
||||||
|
void limit_print(NEWWIN *win, int width, int y, int x, const char *format, ...);
|
||||||
|
void escape_print_xy(NEWWIN *win, int y, int x, const char *str);
|
||||||
|
void escape_print(NEWWIN *win, const char *str, const char reverse, const char underline);
|
||||||
|
void determine_terminal_size(void);
|
||||||
|
void create_win_border(int x, int y, int width, int height, const char *title, NEWWIN **bwin, NEWWIN **win, bool f1, bool with_blank_border = false);
|
||||||
|
void create_wb_popup(int width, int height, const char *title, NEWWIN **bwin, NEWWIN **win);
|
||||||
|
void initcol(void);
|
||||||
|
void apply_mouse_setting(void);
|
||||||
|
void init_ncurses(bool ignore_mouse);
|
||||||
|
void reset_attributes(NEWWIN *win);
|
||||||
|
bool is_in_window(NEWWIN *win, int x, int y);
|
||||||
|
bool right_mouse_button_clicked(void);
|
||||||
|
void display_markerline(NEWWIN *win, const char *msg);
|
||||||
|
void simple_marker(NEWWIN *win);
|
||||||
|
|
||||||
|
void estimate_popup_size(const std::string & in, int *const w, int *const h);
|
3
tests.h
Normal file
3
tests.h
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
void tests(cpu *const c);
|
140
tm-11.cpp
Normal file
140
tm-11.cpp
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tm-11.h"
|
||||||
|
#include "gen.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
tm_11::tm_11(const std::string & file, memory *const m) : m(m)
|
||||||
|
{
|
||||||
|
offset = 0;
|
||||||
|
memset(registers, 0x00, sizeof registers);
|
||||||
|
|
||||||
|
fh = fopen(file.c_str(), "rb");
|
||||||
|
}
|
||||||
|
|
||||||
|
tm_11::~tm_11()
|
||||||
|
{
|
||||||
|
fclose(fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tm_11::readByte(const uint16_t addr)
|
||||||
|
{
|
||||||
|
uint16_t v = readWord(addr & ~1);
|
||||||
|
|
||||||
|
if (addr & 1)
|
||||||
|
return v >> 8;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t tm_11::readWord(const uint16_t addr)
|
||||||
|
{
|
||||||
|
const int reg = (addr - TM_11_BASE) / 2;
|
||||||
|
uint16_t vtemp = registers[reg];
|
||||||
|
|
||||||
|
D(printf("TM-11 read addr %o: ", addr);)
|
||||||
|
|
||||||
|
if (addr == TM_11_MTS) {
|
||||||
|
setBit(vtemp, 15, false); // ILC
|
||||||
|
setBit(vtemp, 14, false); // EOC
|
||||||
|
setBit(vtemp, 13, false); // CRE
|
||||||
|
setBit(vtemp, 12, false); // PAE
|
||||||
|
setBit(vtemp, 11, false); // BGL
|
||||||
|
setBit(vtemp, 10, false); // EOT
|
||||||
|
setBit(vtemp, 9, false); // RLE
|
||||||
|
setBit(vtemp, 8, false); // BTE
|
||||||
|
setBit(vtemp, 7, false); // NXM
|
||||||
|
setBit(vtemp, 6, true); // SELR
|
||||||
|
setBit(vtemp, 5, false); // BOT - beginning of tape
|
||||||
|
setBit(vtemp, 4, false); // 7CH
|
||||||
|
setBit(vtemp, 3, false); // SDWN
|
||||||
|
setBit(vtemp, 2, false); // WRL - write lock
|
||||||
|
setBit(vtemp, 1, false); // RWS
|
||||||
|
setBit(vtemp, 0, true); // TUR - tape unit ready
|
||||||
|
}
|
||||||
|
else if (addr == TM_11_MTC) {
|
||||||
|
registers[reg] ^= 1 << 7; // CU RDY
|
||||||
|
}
|
||||||
|
else if (addr == TM_11_MTBRC) { // record length
|
||||||
|
vtemp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
D(printf("%o\n", vtemp);)
|
||||||
|
|
||||||
|
return vtemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tm_11::writeByte(const uint16_t addr, const uint8_t v)
|
||||||
|
{
|
||||||
|
uint16_t vtemp = registers[(addr - TM_11_BASE) / 2];
|
||||||
|
|
||||||
|
if (addr & 1) {
|
||||||
|
vtemp &= ~0xff00;
|
||||||
|
vtemp |= v << 8;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vtemp &= ~0x00ff;
|
||||||
|
vtemp |= v;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeWord(addr, vtemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tm_11::writeWord(const uint16_t addr, uint16_t v)
|
||||||
|
{
|
||||||
|
D(printf("TM-11 write %o: %o\n", addr, v);)
|
||||||
|
|
||||||
|
if (addr == TM_11_MTC) {
|
||||||
|
if (v & 1) { // GO
|
||||||
|
const int func = (v >> 1) & 7; // FUNCTION
|
||||||
|
const int reclen = 512;
|
||||||
|
|
||||||
|
D(printf("invoke %d\n", func);)
|
||||||
|
|
||||||
|
if (func == 0) { // off-line
|
||||||
|
v = 128; // FIXME set error if error
|
||||||
|
}
|
||||||
|
else if (func == 1) { // read
|
||||||
|
D(printf("reading %d bytes from offset %d\n", reclen, offset);)
|
||||||
|
if (fread(xfer_buffer, 1, reclen, fh) != reclen)
|
||||||
|
D(printf("failed: %s\n", strerror(errno));)
|
||||||
|
for(int i=0; i<reclen; i++)
|
||||||
|
m -> writeByte(registers[(TM_11_MTCMA - TM_11_BASE) / 2] + i, xfer_buffer[i]);
|
||||||
|
offset += reclen;
|
||||||
|
|
||||||
|
v = 128; // FIXME set error if error
|
||||||
|
}
|
||||||
|
else if (func == 2) { // write
|
||||||
|
for(int i=0; i<reclen; i++)
|
||||||
|
xfer_buffer[i] = m -> readByte(registers[(TM_11_MTCMA - TM_11_BASE) / 2] + i);
|
||||||
|
fwrite(xfer_buffer, 1, reclen, fh);
|
||||||
|
offset += reclen;
|
||||||
|
v = 128; // FIXME
|
||||||
|
}
|
||||||
|
else if (func == 4) { // space forward
|
||||||
|
offset += reclen;
|
||||||
|
v = 128; // FIXME
|
||||||
|
}
|
||||||
|
else if (func == 5) { // space backward
|
||||||
|
if (offset >= reclen)
|
||||||
|
offset -= reclen;
|
||||||
|
v = 128; // FIXME
|
||||||
|
}
|
||||||
|
else if (func == 7) { // rewind
|
||||||
|
offset = 0;
|
||||||
|
v = 128; // FIXME set error if error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (addr == TM_11_MTCMA) {
|
||||||
|
v &= ~1;
|
||||||
|
D(printf("Set DMA address to %o\n", v);)
|
||||||
|
}
|
||||||
|
|
||||||
|
D(printf("set register %o to %o\n", addr, v);)
|
||||||
|
registers[(addr - TM_11_BASE) / 2] = v;
|
||||||
|
}
|
38
tm-11.h
Normal file
38
tm-11.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define TM_11_MTS 0172520 // status register
|
||||||
|
#define TM_11_MTC 0172522 // command register
|
||||||
|
#define TM_11_MTBRC 0172524 // byte record counter
|
||||||
|
#define TM_11_MTCMA 0172526 // current memory address register
|
||||||
|
#define TM_11_MTD 0172530 // data buffer register
|
||||||
|
#define TM_11_MTRD 0172532 // TU10 read lines
|
||||||
|
#define TM_11_BASE TM_11_MTS
|
||||||
|
#define TM_11_END (TM_11_MTRD + 2)
|
||||||
|
|
||||||
|
class memory;
|
||||||
|
|
||||||
|
class tm_11
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
memory *const m;
|
||||||
|
uint16_t registers[6];
|
||||||
|
uint8_t xfer_buffer[65536];
|
||||||
|
int offset;
|
||||||
|
FILE *fh;
|
||||||
|
|
||||||
|
public:
|
||||||
|
tm_11(const std::string & file, memory *const m);
|
||||||
|
virtual ~tm_11();
|
||||||
|
|
||||||
|
uint8_t readByte(const uint16_t addr);
|
||||||
|
uint16_t readWord(const uint16_t addr);
|
||||||
|
|
||||||
|
void writeByte(const uint16_t addr, const uint8_t v);
|
||||||
|
void writeWord(const uint16_t addr, uint16_t v);
|
||||||
|
};
|
119
tty.cpp
Normal file
119
tty.cpp
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// // Released under AGPL v3.0
|
||||||
|
#include <errno.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "tty.h"
|
||||||
|
#include "gen.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "terminal.h"
|
||||||
|
|
||||||
|
extern NEWWIN *w_main;
|
||||||
|
|
||||||
|
const char * const regnames[] = {
|
||||||
|
"reader status ",
|
||||||
|
"reader buffer ",
|
||||||
|
"puncher status",
|
||||||
|
"puncher buffer"
|
||||||
|
};
|
||||||
|
|
||||||
|
tty::tty(const bool withUI) : withUI(withUI)
|
||||||
|
{
|
||||||
|
memset(registers, 0x00, sizeof registers);
|
||||||
|
}
|
||||||
|
|
||||||
|
tty::~tty()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t tty::readByte(const uint16_t addr)
|
||||||
|
{
|
||||||
|
uint16_t v = readWord(addr & ~1);
|
||||||
|
|
||||||
|
if (addr & 1)
|
||||||
|
return v >> 8;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t tty::readWord(const uint16_t addr)
|
||||||
|
{
|
||||||
|
const int reg = (addr - PDP11TTY_BASE) / 2;
|
||||||
|
uint16_t vtemp = registers[reg];
|
||||||
|
|
||||||
|
fprintf(stderr, "PDP11TTY read addr %o (%s): ", addr, regnames[reg]);
|
||||||
|
|
||||||
|
if (addr == PDP11TTY_TKS) {
|
||||||
|
vtemp = c ? 128 : 0;
|
||||||
|
}
|
||||||
|
else if (addr == PDP11TTY_TKB) {
|
||||||
|
vtemp = c | (parity(c) << 7);
|
||||||
|
c = 0;
|
||||||
|
}
|
||||||
|
else if (addr == PDP11TTY_TPS) {
|
||||||
|
vtemp = 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "%o\n", vtemp);
|
||||||
|
|
||||||
|
registers[reg] = vtemp;
|
||||||
|
|
||||||
|
return vtemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty::writeByte(const uint16_t addr, const uint8_t v)
|
||||||
|
{
|
||||||
|
uint16_t vtemp = registers[(addr - PDP11TTY_BASE) / 2];
|
||||||
|
|
||||||
|
if (addr & 1) {
|
||||||
|
vtemp &= ~0xff00;
|
||||||
|
vtemp |= v << 8;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vtemp &= ~0x00ff;
|
||||||
|
vtemp |= v;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeWord(addr, vtemp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tty::writeWord(const uint16_t addr, uint16_t v)
|
||||||
|
{
|
||||||
|
const int reg = (addr - PDP11TTY_BASE) / 2;
|
||||||
|
fprintf(stderr, "PDP11TTY write %o (%s): %o\n", addr, regnames[reg], v);
|
||||||
|
|
||||||
|
if (v == 0207 && testMode) {
|
||||||
|
fprintf(stderr, "TestMode: TTY 0207 char\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
if (addr == PDP11TTY_TPB) {
|
||||||
|
v &= 127;
|
||||||
|
|
||||||
|
FILE *tf = fopen("tty.dat", "a+");
|
||||||
|
if (tf) {
|
||||||
|
fprintf(tf, "%c", v);
|
||||||
|
fclose(tf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (withUI) {
|
||||||
|
if (v >= 32 || (v != 12 && v != 27 && v != 13)) {
|
||||||
|
wprintw(w_main -> win, "%c", v);
|
||||||
|
mydoupdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("%c", v);
|
||||||
|
fflush(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "punch char: '%c'\n", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
D(fprintf(stderr, "set register %o to %o\n", addr, v);)
|
||||||
|
registers[(addr - PDP11TTY_BASE) / 2] = v;
|
||||||
|
}
|
38
tty.h
Normal file
38
tty.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#define PDP11TTY_TKS 0177560 // reader status
|
||||||
|
#define PDP11TTY_TKB 0177562 // reader buffer
|
||||||
|
#define PDP11TTY_TPS 0177564 // puncher status
|
||||||
|
#define PDP11TTY_TPB 0177566 // puncher buffer
|
||||||
|
#define PDP11TTY_BASE PDP11TTY_TKS
|
||||||
|
#define PDP11TTY_END (PDP11TTY_TPB + 2)
|
||||||
|
|
||||||
|
class memory;
|
||||||
|
|
||||||
|
class tty
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
uint16_t registers[4];
|
||||||
|
bool testMode { false }, withUI { false };
|
||||||
|
char c { 0 };
|
||||||
|
|
||||||
|
public:
|
||||||
|
tty(const bool withUI);
|
||||||
|
virtual ~tty();
|
||||||
|
|
||||||
|
void setTest() { testMode = true; }
|
||||||
|
|
||||||
|
void sendChar(const char v) { c = v; };
|
||||||
|
|
||||||
|
uint8_t readByte(const uint16_t addr);
|
||||||
|
uint16_t readWord(const uint16_t addr);
|
||||||
|
|
||||||
|
void writeByte(const uint16_t addr, const uint8_t v);
|
||||||
|
void writeWord(const uint16_t addr, uint16_t v);
|
||||||
|
};
|
45
utils.cpp
Normal file
45
utils.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
void setBit(uint16_t & v, const int bit, const bool vb)
|
||||||
|
{
|
||||||
|
const uint16_t mask = 1 << bit;
|
||||||
|
|
||||||
|
v &= ~mask;
|
||||||
|
|
||||||
|
if (vb)
|
||||||
|
v |= mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string format(const char *const fmt, ...)
|
||||||
|
{
|
||||||
|
char *buffer = nullptr;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
(void)vasprintf(&buffer, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
std::string result = buffer;
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long get_ms()
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parity(int v)
|
||||||
|
{
|
||||||
|
return __builtin_parity(v); // FIXME
|
||||||
|
}
|
12
utils.h
Normal file
12
utils.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// (C) 2018 by Folkert van Heusden
|
||||||
|
// Released under AGPL v3.0
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void setBit(uint16_t & v, const int bit, const bool vb);
|
||||||
|
int parity(int v);
|
||||||
|
|
||||||
|
#define sign(a) ( ( (a) < 0 ) ? -1 : ( (a) > 0 ) )
|
||||||
|
|
||||||
|
std::string format(const char *const fmt, ...);
|
||||||
|
unsigned long get_ms();
|
Loading…
Add table
Reference in a new issue