mirror of
https://github.com/wwarthen/RomWBW.git
synced 2026-02-07 23:13:13 -06:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3495614803 |
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -1,2 +0,0 @@
|
||||
# Leave all line endings alone!
|
||||
* -text
|
||||
@@ -1,8 +0,0 @@
|
||||
@echo off
|
||||
if exist *.bin del *.bin
|
||||
if exist *.com del *.com
|
||||
if exist *.img del *.img
|
||||
if exist *.rom del *.rom
|
||||
if exist *.pdf del *.pdf
|
||||
if exist *.log del *.log
|
||||
if exist *.eeprom del *.eeprom
|
||||
@@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
@@ -1,107 +0,0 @@
|
||||
***********************************************************************
|
||||
*** ***
|
||||
*** R o m W B W ***
|
||||
*** ***
|
||||
*** Z80/Z180 System Software ***
|
||||
*** ***
|
||||
***********************************************************************
|
||||
|
||||
This directory ("Binary") is part of the RomWBW System Software
|
||||
distribution archive. It contains the completed binary outputs of
|
||||
the build process. As described below, these files are used to
|
||||
assemble a working RetroBrew Computers system.
|
||||
|
||||
The files in this directory are created by the build process that is
|
||||
documented in the ReadMe.txt file in the Source directory. When
|
||||
released the directory is populated with the default output files.
|
||||
However, the output of custom builds will be placed in this directory
|
||||
as well.
|
||||
|
||||
ROM Firmware Images (<plt>_<cfg>.rom)
|
||||
-------------------------------------
|
||||
|
||||
The files with a ".rom" extension are binary images ready to program
|
||||
into an appropriate PROM. These files are named with the format
|
||||
<plt>_<cfg>.rom. <plt> refers to the primary platform such as Zeta,
|
||||
N8, Mark IV, etc. <cfg> refers to the specific configuration. When
|
||||
released, there will be a standard configuration ("std") for each
|
||||
platform. So, for example, the file called MK4_std.rom is a ROM
|
||||
image for the Mark IV with the standard configuration. If a custom
|
||||
configuration called "custom" is created and built, a new file called
|
||||
MK4_custom.rom will be added to this directory.
|
||||
|
||||
Documentation of the pre-built ROM Images is contained in the
|
||||
RomList.txt file.
|
||||
|
||||
ROM Executable Images (<plt>_<cfg>.com)
|
||||
---------------------------------------
|
||||
|
||||
When a ROM image (".rom") is created, an executable version of the
|
||||
ROM is also created. These files have the same naming convention as
|
||||
the ROM Image files, but have the extension ".com". These files can
|
||||
be copied to a working system and run like a normal application.
|
||||
|
||||
When run on the target system, they install in RAM just like they had
|
||||
been programmed into the ROM. This allows a new ROM build to be
|
||||
tested without reprogramming the actual ROM.
|
||||
|
||||
ROM Binary Images (<plt>_<cfg>.img)
|
||||
-----------------------------------
|
||||
|
||||
Also when a ROM image is created, a third variation of the ROM is
|
||||
created again with the same naming convention, but with the extension
|
||||
of .img. These files are similar to the .com files in that they can
|
||||
be used to test a ROM build without actually programming a new ROM.
|
||||
The .img files are specifically for loading via UNA from a FAT file
|
||||
system. The functionality of the UNA FAT file system loader is
|
||||
beyond the scope of this document.
|
||||
|
||||
VDU ROM Image (vdu.rom)
|
||||
-----------------------
|
||||
|
||||
The VDU video board requires a dedicated onboard ROM containing the
|
||||
font data. The "vdu.rom" file contains the binary data to program
|
||||
onto that chip.
|
||||
|
||||
Disk Images (fd*.img, hd*.img)
|
||||
------------------------------
|
||||
|
||||
RomWBW includes a mechanism for generating floppy disk and hard disk
|
||||
binary images that are ready to copy directly to a floppy, hard disk,
|
||||
CF Card, or SD Card which will then be ready for use in any
|
||||
RomWBW-based system.
|
||||
|
||||
Essentially, these files contain prepared floppy and hard disk images
|
||||
with a large set of programs and related files. By copying the
|
||||
contents of these files to appropriate media as described below, you
|
||||
can quickly create ready-to-use media.
|
||||
|
||||
The fd*.img files are floppy disk images. They are sized for 1.44MB
|
||||
floppy media and can be copied to actual floppy disks using
|
||||
RawWriteWin (as long as you have access to a floppy drive on your
|
||||
Windows computer). The resulting floppy disks will be usable on any
|
||||
RomWBW-based system with floppy drive(s).
|
||||
|
||||
Likewise, the hd*.img files are hard disk images. Each file is
|
||||
intended to be copied to the start of any type of hard disk media
|
||||
(typically a CF Card or SD Card). The resulting media will be usable
|
||||
on any RomWBW-based system that accepts the corresponding media type.
|
||||
|
||||
Note that the contents of the floppy/hard disk images are created by
|
||||
the BuildImages.cmd script in the Source directory. Additional
|
||||
information on how to generate custom disk images is found in the
|
||||
Source\Images directory.
|
||||
|
||||
Propeller ROM Images (*.eeprom)
|
||||
-------------------------------
|
||||
|
||||
The files with and extension of ".eeprom" contain the binary images
|
||||
to be programmed into the Propeller-based boards. The list below
|
||||
indicates which file targets each of the Propeller board variants:
|
||||
|
||||
ParPortProp ParPortProp.eeprom
|
||||
PropIO V1 PropIO.eeprom
|
||||
PropIO V2 PropIO2.eeprom
|
||||
|
||||
Refer to the board documentation of the boards for more information
|
||||
on how to program the EEPROMs on these boards.
|
||||
@@ -1,111 +0,0 @@
|
||||
***********************************************************************
|
||||
*** ***
|
||||
*** R o m W B W ***
|
||||
*** ***
|
||||
*** Z80/Z180 System Software ***
|
||||
*** ***
|
||||
***********************************************************************
|
||||
|
||||
This directory ("Binary") is part of the RomWBW System Software
|
||||
distribution archive. Refer to the ReadMe.txt file in this
|
||||
directory for more information on the overall contents of the
|
||||
directory.
|
||||
|
||||
When distributed, RomWBW contains a set of pre-built ROM images that
|
||||
are ready to program onto the EEPROM of any of the Z80/Z180 based
|
||||
RetroBrew Computers CPU boards. Additionally, any custom built ROM
|
||||
images will be placed in this directory.
|
||||
|
||||
All of the pre-built ROM images are 512KB. This size is compatible
|
||||
with all of the Z80/Z180 systems. Some systems can accept different
|
||||
size ROM images. Creating alternative sizes requires a custom ROM
|
||||
build (see ReadMe.txt in the Source directory).
|
||||
|
||||
It is critical that the right ROM Imgae be selected for the target
|
||||
platform being used. The table below indicates the correct ROM
|
||||
image to use for each platform:
|
||||
|
||||
SBC V1/V2 SBC_std.rom
|
||||
Zeta V1 ZETA_std.rom
|
||||
Zeta V2 ZETA2_std.rom
|
||||
N8 N8_std.rom
|
||||
Mark IV MK4_std.rom
|
||||
|
||||
You will find there is one additional ROM image called
|
||||
"UNA_std.rom". This ROM image is an UNA-based RomWBW ROM image. As
|
||||
such, this ROM image can be used on any Z80/Z180 platform supported
|
||||
by John Coffman's UNA BIOS. Refer to RetroBrew Computers Wiki for
|
||||
more information on UNA hardware support.
|
||||
|
||||
For each of the ROM Images (".rom"), there are corresponding files
|
||||
with the extensions of ".com" and ".img". The .com variant can be
|
||||
copied to a functional RomWBW-based system and executed like a
|
||||
normal application under CP/M or Z-System. This will load the new
|
||||
ROM on-the-fly. It is an excellent way to test a ROM Image before
|
||||
actually burning it. Similarly, the .img files can be loaded using
|
||||
the UNA FAT loader for testing.
|
||||
|
||||
All of the standard ROM Images are configured with:
|
||||
- 512KB ROM Disk
|
||||
- 512KB RAM Disk
|
||||
- 38.4Kbps baud serial console
|
||||
- Auto-discovery of all serial ports
|
||||
|
||||
All hard disk type devices (IDE, PPIDE, CF Card, SD Card) will be
|
||||
automatically assigned two drive letters per device. The drive
|
||||
letters will refer to the first 2 slices of the device. The ASSIGN
|
||||
command can be used to display and reassign drives to disk devices
|
||||
and slices as desired.
|
||||
|
||||
Standard ROM Image Notes
|
||||
------------------------
|
||||
|
||||
The standard ROM images will detect and install support for certain
|
||||
devices and peripherals that are on-board or frequently used with
|
||||
each platform as documented below. If the device or peripheral is
|
||||
not detected at boot, the ROM will simply bypass support
|
||||
appropriately.
|
||||
|
||||
SBC:
|
||||
- Includes support for PPIDE/CF Card(s) connected to on-board
|
||||
parallel port.
|
||||
- Includes support for CVDU and VGA3 boards. If detected at
|
||||
startup, support for video and keyboard is installed
|
||||
including VT-100/ANSI terminal emulation.
|
||||
- Auto-detects PropIO or PropIO V2 and installs associated
|
||||
video, keyboard and SD Card support if present.
|
||||
- If PropIO, PropIO V2, CVDU, or VGA hardware is detected,
|
||||
initial console output is determined by JP2. If JP2 is
|
||||
shorted, console will go to on-board serial port, if JP2
|
||||
is open, console will go to the detected video and keyboard
|
||||
ports.
|
||||
- SBC V1 has a known race condition in the bank switching
|
||||
circuit which is likely to cause system instability. SBC
|
||||
V2 does not have this issue.
|
||||
|
||||
ZETA/ZETA2:
|
||||
- Includes support for on-board floppy disk controller and
|
||||
two attached floppy disks.
|
||||
- Auto-detects ParPortProp and includes support for it if it
|
||||
is attached.
|
||||
- If ParPortProp is installed, initial console output is
|
||||
determined by JP1. If JP1 is shorted, console will go to
|
||||
on-board serial port, if JP1 is open, console will go to
|
||||
ParPortProp video and keyboard ports.
|
||||
|
||||
N8:
|
||||
- Includes support for on-board floppy disk controller and
|
||||
two attached floppy disks.
|
||||
- Includes support for on-board TMS9918 video and keyboard
|
||||
including VT-100/ANSI terminal emulation.
|
||||
- Includes support for on-board SD Card as hard disk and
|
||||
assumes a production level N8 board (date code >= 2312).
|
||||
|
||||
MK4:
|
||||
- Includes support for on-board IDE port (CF Card via adapter).
|
||||
- Includes support for on-board SD Card port.
|
||||
- Auto-detects PropIO or PropIO V2 and installs associated
|
||||
video, keyboard and SD Card support if present.
|
||||
- Includes support for CVDU and VGA3 boards. If detected at
|
||||
startup, support for video and keyboard is installed
|
||||
including VT-100/ANSI terminal emulation.
|
||||
4
BuildCommon.cmd
Normal file
4
BuildCommon.cmd
Normal file
@@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
pushd Source && call BuildCommon && popd
|
||||
4
BuildImages.cmd
Normal file
4
BuildImages.cmd
Normal file
@@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
pushd Images && Build && popd
|
||||
11
Clean.cmd
Normal file
11
Clean.cmd
Normal file
@@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
|
||||
setlocal
|
||||
|
||||
pushd Source && call Clean && popd
|
||||
pushd Images && call Clean && popd
|
||||
|
||||
if exist *.img del *.img /Q
|
||||
if exist *.log del *.log /Q
|
||||
|
||||
if exist Output\*.* del Output\*.* /Q
|
||||
350
Doc/Build.txt
Normal file
350
Doc/Build.txt
Normal file
@@ -0,0 +1,350 @@
|
||||
Building a Custom ROM
|
||||
---------------------
|
||||
|
||||
At present, the build environment assumes you are running
|
||||
a current version of Microsoft Windows (either 32-bit or
|
||||
64-bit). Additionally, you will need Microsoft PowerShell.
|
||||
PowerShell is included in all distributions of Microsoft
|
||||
Windows starting with Vista. It is available as a free
|
||||
download for Windows XP from Microsoft
|
||||
|
||||
Other than PowerShell, all required tools are included in
|
||||
the distribution. You should not need anything other than
|
||||
what comes as part of Windows or as part of the distribution.
|
||||
|
||||
In summary, the process involves the 4 steps below. You must
|
||||
configure PowerShell prior to these steps, but this only needs
|
||||
to be done once.
|
||||
|
||||
The basic steps to create a custom ROM are:
|
||||
|
||||
1) Create/update configuration file
|
||||
|
||||
2) Update/Add/Delete any files you want incorporated in
|
||||
the ROM Disk
|
||||
|
||||
3) Run the build scripts and
|
||||
confirm there are no errors.
|
||||
|
||||
4) Burn the resultant ROM image and try it.
|
||||
|
||||
I strongly recommend that you initially SKIP steps
|
||||
1 & 2. Just try steps 3 & 4 to make sure you are
|
||||
able to build a ROM and test it in your hardware.
|
||||
|
||||
Each of the 4 steps above is described in more detail
|
||||
below.
|
||||
|
||||
Acquiring the Distribution
|
||||
--------------------------
|
||||
|
||||
Preparing PowerShell
|
||||
--------------------
|
||||
|
||||
|
||||
1. Create/Update Configuration File
|
||||
-----------------------------------
|
||||
|
||||
The settings for a build are primarily controled by
|
||||
a configuration file that is included in the build
|
||||
process. In order to customize your settings, you
|
||||
need to modify an existing configuration file or
|
||||
create your own.
|
||||
|
||||
Configuration files are found in the Source\BIOS\Config
|
||||
directory. If you look in the this directory, you will see
|
||||
a series of files named XXXX_yyyy.asm. Each of
|
||||
them corresponds to one of the standard configurations
|
||||
listed in the ROMList.txt file.
|
||||
|
||||
You have two choices. You can simply modify the existing
|
||||
configuration file that is closest to your situation, or
|
||||
you can copy it to a new XXXX_yyyy.asm file and modify
|
||||
that. I recommend that you copy one to your own name so
|
||||
that you will always have the unmodified standard configuration
|
||||
files left in place. So, for example, you could just
|
||||
copy ZETA_std.asm to ZETA_wayne.asm. You MUST
|
||||
name your config file as XXXX_yyyy.asm. The XXXX portion
|
||||
must match your platform (N8VEM, ZETA, ZETA2, N8, UNA).
|
||||
The yyyy portion can be whatever you want.
|
||||
|
||||
The config files are simply text files with various
|
||||
settings. Open your target config file with your
|
||||
favorite text editor and modify the settings as desired.
|
||||
|
||||
Unfortunately, I have not yet documented each of the
|
||||
settings in detail; that will be a separate document
|
||||
provided in the future. However, there are comments
|
||||
in the config file that will probably be sufficient
|
||||
for the most part.
|
||||
|
||||
2. Update/Add/Delete ROM Disk Files
|
||||
-----------------------------------
|
||||
|
||||
The files that are included on the ROM Disk of your
|
||||
ROM are copied from a set of directories during the
|
||||
build process. This allows you to have complete
|
||||
flexibility over the files you want included in your
|
||||
ROM.
|
||||
|
||||
If you look at the RomDsk directory, you will see
|
||||
a variety of subdirectories. These subdirectories
|
||||
contain the files that will be included in the
|
||||
ROM disk. The build process will determine
|
||||
which subdirectories to include files from based
|
||||
on the following rules:
|
||||
|
||||
First, all files from either ROM_512KB or ROM_1024KB will
|
||||
be included depending on on the size of the ROM you
|
||||
are building. If you are building a 512KB ROM, then
|
||||
all the files from ROM_512KB will be included. If you
|
||||
are building a 1MB ROM, then all the files from ROM_1024KB
|
||||
will be included. Essentialy, the files in ROM_1204KB are
|
||||
a superset of the ones in ROM_512KB because there is more
|
||||
space available for the ROM drive.
|
||||
|
||||
Second, all files from the directory that corresponds to
|
||||
your configuration file will be included. If you build
|
||||
the "ZETA_std" configuration, all files in ZETA_std will
|
||||
be added. Note that these files will be in addition
|
||||
to the files from the ROM_XXXKB directory.
|
||||
|
||||
If you created your own config file (like ZETA_wayne.asm
|
||||
described above), you MUST create a subdirectory within
|
||||
the RomDsk directory and populate it with the files
|
||||
you want added. Normally, you would include the
|
||||
files from the original standard config. So, if
|
||||
you created ZETA_wayne.asm from ZETA_std.asm,
|
||||
then you would create a subdirectory in RomDsk called
|
||||
ZETA_wayne and copy all the files from ZETA_std to
|
||||
ZETA_wayne.
|
||||
|
||||
3. Run the Build Process
|
||||
------------------------
|
||||
|
||||
NOTE: The process described here is the more commonly
|
||||
used build script. If you wish to use a makefile
|
||||
instead, refer to the comments in the makefile in
|
||||
the Source directory as an alternative to the
|
||||
process described here.
|
||||
|
||||
The build involves running commands at the command
|
||||
prompt. From a Command Prompt window, you will need
|
||||
to change to the high level directory for the build.
|
||||
Normally, you would be changing to the RomWBW directory
|
||||
unless you renamed it.
|
||||
|
||||
First, you will need to build the components that are
|
||||
common to all configurations. These components do not
|
||||
require any configuration. To build these, use the
|
||||
following command and ensure it completes
|
||||
without error:
|
||||
|
||||
BuildCommon
|
||||
|
||||
To run the configuration specific build and be prompted
|
||||
for required information, just enter "Build". You will
|
||||
be prompted for the information described below and the
|
||||
build should run. If an error is encountered, the build
|
||||
should stop and display an error in red text.
|
||||
|
||||
If you immediately receive the error "the execution of
|
||||
scripts is disabled on this system", then you will need to
|
||||
change the PowerShell Execution-Polcy to "RemoteSigned".
|
||||
To do this, you need to right-click on FixPowerShell.cmd and
|
||||
choose "Run as Administrator" to make the change. It is
|
||||
critical that you right-click and use "Run as Administrator"
|
||||
or the change will not work (you will get an error
|
||||
indicating "Access to the registry denied" if you fail to
|
||||
use "Run as Administrator".
|
||||
|
||||
The build script will prompt you for the following information
|
||||
which you will need to provide (don't worry, it is simple):
|
||||
|
||||
Platform:
|
||||
|
||||
Respond with the name of the platform that you are targeting.
|
||||
It must be one of N8VEM, ZETA, ZETA2, N8, or UNA.
|
||||
|
||||
Configuration:
|
||||
|
||||
Respond with the name of the configuration you wish to build.
|
||||
A list of all available configurations is displayed for your
|
||||
convenience. For example, if you are building the provided
|
||||
ZETA_std configuration, just enter "std". If you have created a
|
||||
custom configuration as described above, you would enter
|
||||
"wayne".
|
||||
|
||||
ROM Size [512|1024]:
|
||||
|
||||
Respond with either "512" for a 512KB ROM build or "1024" for a
|
||||
1MB ROM build. Only the two choices are possible at this time.
|
||||
It is important that you choose a ROM size that is no larger than
|
||||
the size of the ROM you will ultimately be burning. This is
|
||||
dependant on your hardware.
|
||||
|
||||
At this point, the build should run and you will see output related
|
||||
to the assembler runs and some utility invocations. Just review
|
||||
the output for any obvioius errors. Normally, all errors will
|
||||
cause the build to stop immediately and display an error message
|
||||
in red.
|
||||
|
||||
You will see some lines in the output indicating the amount of
|
||||
space various components have taken. You should check these
|
||||
to make sure you do not see any negative numbers which would
|
||||
indicate that you have included too many features/drivers for
|
||||
the available memory space. Here are examples of the lines
|
||||
showing the space used:
|
||||
|
||||
DATA space remaining: 39 bytes.
|
||||
BOOT LOADER space remaining: 3503 bytes.
|
||||
CBIOS space remaining: 161 bytes.
|
||||
DBGMON space remaining: 860 bytes.
|
||||
ROMX space remaining: 8191 bytes.
|
||||
BOOT LOADER space remaining: 3503 bytes.
|
||||
|
||||
4. Deploy the ROM
|
||||
-----------------
|
||||
|
||||
If you look in the Output directory. You should find the following files:
|
||||
|
||||
<config>.rom - binary ROM image to burn to EEPROM
|
||||
<config>.com - executable version of the system image that can be
|
||||
copied via xmodem to a running system to test
|
||||
the build.
|
||||
<config>.img - system image that can be written to an SD/CF Card
|
||||
and loaded via the UNA FS FAT loader.
|
||||
|
||||
The actual ROM image is the file ending in .rom. It should be exactly
|
||||
512KB or 1MB depending on the ROM size you chose. Simply burn the .rom
|
||||
image to your ROM and install it in your hardware.
|
||||
|
||||
Specifying Build Options on Command Line
|
||||
----------------------------------------
|
||||
|
||||
If you don't want to be prompted for the options to the "Build"
|
||||
command, you can specify the options right on the command line.
|
||||
|
||||
For example:
|
||||
|
||||
Build ZETA std 512
|
||||
|
||||
In this case, you will not be prompted. This is useful if you
|
||||
wish to automate your build process.
|
||||
|
||||
Example Build Run
|
||||
-----------------
|
||||
|
||||
C:\Users\WWarthen\Projects\N8VEM\Build\RomWBW>Build.cmd
|
||||
Platform [N8VEM|ZETA|N8|UNA|S100]: ZETA
|
||||
Configurations available:
|
||||
> ppp
|
||||
> std
|
||||
Configuration: std
|
||||
ROM Size [512|1024]: 512
|
||||
|
||||
Building ZETA_std: 512KB ROM configuration std for Z80...
|
||||
|
||||
tasm -t80 -g3 ccpb03.asm cp.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 bdosb01.asm dos.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 syscfg.asm syscfg.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE (STD)
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 -dBLD_SYS=SYS_CPM cbios.asm cbios.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE (STD)
|
||||
INFOLIST occupies 18 bytes.
|
||||
UTIL occupies 484 bytes.
|
||||
FD_DATA occupies 340 bytes.
|
||||
PPIDE_DATA occupies 1116 bytes.
|
||||
CBIOS space remaining: 2092 bytes.
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 dbgmon.asm dbgmon.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE (STD)
|
||||
DBGMON space remaining: 795 bytes.
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 prefix.asm prefix.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE (STD)
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 bootrom.asm bootrom.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE (STD)
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 bootapp.asm bootapp.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE (STD)
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 loader.asm loader.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE (STD)
|
||||
LOADER space remaining: 1205 bytes.
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 pgzero.asm pgzero.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 hbios.asm hbios.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE (STD)
|
||||
UART occupies 146 bytes.
|
||||
FD occupies 2071 bytes.
|
||||
PPIDE occupies 809 bytes.
|
||||
HBIOS space remaining: 24428 bytes.
|
||||
STACK space remaining: 145 bytes.
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 hbfill.asm hbfill.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE (STD)
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
tasm -t80 -g3 romfill.asm romfill.bin
|
||||
TASM Z80 Assembler. Version 3.2 September, 2001.
|
||||
Copyright (C) 2001 Squak Valley Software
|
||||
tasm: pass 1 complete.
|
||||
tasm: pass 2 complete.
|
||||
tasm: Number of errors = 0
|
||||
Building ZETA_std output files...
|
||||
Building 512KB ZETA_std ROM disk data file...
|
||||
|
||||
C:\Users\WWarthen\Projects\N8VEM\Build\RomWBW>
|
||||
Binary file not shown.
@@ -1,28 +1,10 @@
|
||||
Version 2.8.2
|
||||
-------------
|
||||
- WBW: Adjusted VGA3 register setup per John's recommendations
|
||||
|
||||
Version 2.8.1
|
||||
-------------
|
||||
- WBW: Fix FDISK80
|
||||
- WBW: Upgrade to latest production UNA 2.1-45
|
||||
|
||||
Version 2.8.0
|
||||
-------------
|
||||
- WBW: Add support for VGA3 board
|
||||
|
||||
Version 2.7.1
|
||||
-------------
|
||||
- WBW: Replace ZX with XP compatible build (no functional changes)
|
||||
- WBW: Reset BDOS serial number on warm start
|
||||
- WBW: Turn off DRAM refresh on Z180 (fixes Z180 CPU speed detection)
|
||||
- WBW: Support loading from image file (UNA FSFAT)
|
||||
|
||||
Version 2.7.0
|
||||
-------------
|
||||
- WBW: Memory page reorganization
|
||||
- WBW: Support for Zeta 2 (from Sergey Kiselev)
|
||||
- WBW: Support loading from image file (UNA FSFAT)
|
||||
- WBW: Dynamic CPU speed detection
|
||||
|
||||
Version 2.6.5
|
||||
-------------
|
||||
|
||||
Binary file not shown.
@@ -5,21 +5,21 @@
|
||||
= Warning =
|
||||
|
||||
FLASH4 has been tested and confirmed working on:
|
||||
* N8VEM SBCv2
|
||||
* N8VEM N8-2312
|
||||
* N8VEM Mark IV SBC
|
||||
* DX-Designs P112
|
||||
* ZETA SBC v2
|
||||
* SBCv2
|
||||
* N8-2312
|
||||
* Mark IV SBC
|
||||
|
||||
However it remains somewhat experimental. If it works for you, please let me
|
||||
know. If it breaks please also let me know so I can fix it!
|
||||
know. If it breaks please also let me know so I can fix it! Until it is more
|
||||
widely tested please ensure you have some other means to reprogram your flash
|
||||
ROM before exclusively trusting FLASH4.
|
||||
|
||||
|
||||
= Introduction =
|
||||
|
||||
FLASH4 is a CP/M program which can read, write and verify Flash ROM contents to
|
||||
or from an image file stored on a CP/M filesystem. It is intended for in-system
|
||||
programming of Flash ROM chips on Z80 and Z180 systems.
|
||||
programming of Flash ROM chips on N8VEM Z80 and Z180 systems.
|
||||
|
||||
FLASH4 aims to support a range of Flash ROM chips. Ideally I would like to
|
||||
support all Flash ROM chips that are in use in Z80/Z180 N8VEM machines. If
|
||||
@@ -46,26 +46,23 @@ the "srec_cat" program from SRecord:
|
||||
$ srec_cat image.hex -intel -fill 0xFF 0 0x80000 -output image.bin -binary
|
||||
$ srec_cat image.bin -binary -output image.hex -intel
|
||||
|
||||
FLASH4 can use several different methods to access the Flash ROM chip. The best
|
||||
FLASH4 can use three different methods to access the Flash ROM chip. The best
|
||||
available method is determined automatically at run time. Alternatively you may
|
||||
provide a command-line option to force the use of a specific method.
|
||||
|
||||
The first two methods use bank switching to map sections of the ROM into the
|
||||
CPU address space. FLASH4 will detect the presence of RomWBW or UNA BIOS and
|
||||
use the bank switching methods they provide.
|
||||
use the bank switching methods they provide.
|
||||
|
||||
On P112 systems the P112 B/P BIOS is detected and P112 bank switching is used.
|
||||
|
||||
If no bank switching method can be auto-detected, and the system has a Z180
|
||||
CPU, FLASH4 will use the Z180 DMA engine to access the Flash ROM chip. This
|
||||
does not require any bank switching but it is slower and will not work on all
|
||||
platforms.
|
||||
If neither RomWBW nor UNA BIOS is detected and the system has a Z180 CPU,
|
||||
FLASH4 will use the Z180 DMA engine to access the Flash ROM chip. This does not
|
||||
require any bank switching but it is slower and will not work on all platforms.
|
||||
|
||||
Z180 DMA access requires the flash ROM to be linearly mapped into the lower
|
||||
region of physical memory, as it is on the Mark IV SBC (for example). The
|
||||
N8-2312 has additional memory mapping hardware, consequently Z180 DMA access on
|
||||
the N8-2312 is NOT SUPPORTED and if forced will corrupt the contents of RAM;
|
||||
use one of the supported bank switching methods instead.
|
||||
region of physical memory, as it is on the Mark IV SBC. The N8-2312 has
|
||||
additional memory mapping hardware, consequently Z180 DMA access on the N8-2312
|
||||
is NOT SUPPORTED and if forced will corrupt the contents of RAM; use bank
|
||||
switched access instead.
|
||||
|
||||
Z180 DMA access requires the Z180 CPU I/O base control register configured to
|
||||
locate the internal I/O addresses at 0x40 (ie ICR bits IOA7, IOA6 = 0, 1).
|
||||
@@ -96,27 +93,13 @@ If your ROM chip is larger than the image you wish to write, use the "/PARTIAL"
|
||||
the image file must be an exact multiple of 32KB in length. The portion of the
|
||||
ROM not occupied by the image file is left either unmodified or erased.
|
||||
|
||||
If you are using an ROM/EPROM/EEPROM chip which cannot be programmed in-system,
|
||||
FLASH4 will not be able to recognise it, however the software can still
|
||||
usefully READ and VERIFY the chip. Use the "/ROM" command line option to enable
|
||||
"READ" or "VERIFY" mode with unrecognised chips. This mode assumes a 512K ROM
|
||||
is fitted; smaller ROMs will be treated as a 512K ROM with the data repated
|
||||
multiple times -- with a 256K chip the data is repeated twice, four times for a
|
||||
128K chip, etc.
|
||||
|
||||
One of the following optional command line arguments may be specified at the
|
||||
end of the command line to force FLASH4 to use a particular method to access
|
||||
the flash ROM chip:
|
||||
|
||||
BIOS interfaces:
|
||||
/ROMWBW For ROMWBW BIOS version 2.6 and later
|
||||
/ROMWBWOLD For ROMWBW BIOS version 2.5 and earlier
|
||||
/UNABIOS For UNA BIOS
|
||||
|
||||
Direct hardware interfaces:
|
||||
/Z180DMA For Z180 DMA
|
||||
/P112 For DX-Designs P112
|
||||
/N8VEMSBC For N8VEM SBC (v1, v2), Zeta (v1) SBC
|
||||
/ROMWBW
|
||||
/UNABIOS
|
||||
/Z180DMA
|
||||
|
||||
If no option is specified FLASH4 attempts to determine the best available
|
||||
method automatically.
|
||||
@@ -1,42 +0,0 @@
|
||||
***********************************************************************
|
||||
*** ***
|
||||
*** R o m W B W ***
|
||||
*** ***
|
||||
*** Z80/Z180 System Software ***
|
||||
*** ***
|
||||
***********************************************************************
|
||||
|
||||
This directory ("Doc") is part of the RomWBW System Software
|
||||
distribution archive. It contains documentation for components of
|
||||
the system.
|
||||
|
||||
CPM Manual:
|
||||
|
||||
The original DRI CP/M 2.x Operating System Manual. This should be
|
||||
considered the primary reference for system operation. The section
|
||||
on CP/M 2 Alteration can be ignored since this work has already been
|
||||
completed as part of the RomWBW distribution.
|
||||
|
||||
FDisk Manual:
|
||||
|
||||
The operational manual for John Coffman's hard disk partitioning
|
||||
program. This program is included in RomWBW as FDISK80.
|
||||
|
||||
RomWBW Architecture:
|
||||
|
||||
Document describing the architecture of the RomWBW HBIOS. It
|
||||
includes reference information for the HBIOS calls.
|
||||
|
||||
ZCPR Manual:
|
||||
|
||||
ZCPR is the command proccessor portion of Z-System. This is the
|
||||
manual for ZCPR 1.x as included in RomWBW. The installation
|
||||
instructions can be ignored since that work has already been
|
||||
completed as part of the RomWBW distribution.
|
||||
|
||||
ZSDOS Manual:
|
||||
|
||||
ZSDOS is the DOS portion of Z-System. This is the manual fo ZSDOS
|
||||
1.x as included in RomWBW. The installation instructions can be
|
||||
ignored since that work has already been completed as part of the
|
||||
RomWBW distribution.
|
||||
BIN
Doc/Reference/cpm22-m.pdf
Normal file
BIN
Doc/Reference/cpm22-m.pdf
Normal file
Binary file not shown.
@@ -1,6 +1,3 @@
|
||||
|
||||
|
||||
|
||||
ZCPR - A Z80 Replacement for the CP/M CCP
|
||||
|
||||
|
||||
@@ -8,7 +5,7 @@
|
||||
|
||||
|
||||
|
||||
\textbf{Documentation on ZCPR - A Z80 Replacement for the CP/M CCP}
|
||||
Documentation on ZCPR - A Z80 Replacement for the CP/M CCP
|
||||
|
||||
|
||||
|
||||
@@ -71,7 +68,7 @@
|
||||
|
||||
|
||||
|
||||
\textbf{Documentation on ZCPR - A Z80 Replacement for the CP/M CCP}
|
||||
Documentation on ZCPR - A Z80 Replacement for the CP/M CCP
|
||||
|
||||
|
||||
|
||||
@@ -241,7 +238,6 @@
|
||||
integration is the placement of the new ZCPR onto disk in the
|
||||
proper place so that it will be loaded with the rest of CP/M on
|
||||
cold boot and executed properly.
|
||||
|
||||
To find the original CCP, you typically have to locate it by
|
||||
its appearance. It is probably stored contiguously on disk, so,
|
||||
once it is found, a sequential overwrite is all that is required.
|
||||
@@ -259,6 +255,7 @@
|
||||
CCP. The CCP will probably start on an even page or half-page
|
||||
address (like 900H, 980H, 1100H, etc).
|
||||
|
||||
|
||||
Page 4
|
||||
|
||||
|
||||
@@ -371,7 +368,7 @@
|
||||
-^C <-- Return to CP/M; I know that CPRLOC will be
|
||||
BD00H and the IMAGE offset is 1100H
|
||||
|
||||
B>ed cpr.asm \{edit ZCPR here and place CPRLOC=BD00H\}#
|
||||
B>ed cpr.asm {edit ZCPR here and place CPRLOC=BD00H}#
|
||||
-- Detail Left Out --
|
||||
|
||||
B>mac cpr $pz sz <-- Now to assemble the CPR
|
||||
@@ -747,7 +744,7 @@
|
||||
To illustrate this command hierarchy search, consider the
|
||||
following examples:
|
||||
|
||||
Example 1: DEFUSR equ 0 \{default user number is 0\}
|
||||
Example 1: DEFUSR equ 0 {default user number is 0}
|
||||
|
||||
B10> <-- User is on Drive B:, User Number 10
|
||||
B10>ASM TEST.BBZ <-- User wishes to assemble TEST.ASM in
|
||||
@@ -813,9 +810,9 @@
|
||||
issued from the console (or Indirect Command File):
|
||||
|
||||
B10>WM TEST2.TXT
|
||||
^ ^ ^-------- File to be edited
|
||||
| +----------- Invoke the WM.COM file (Word Master editor)
|
||||
+--------------- User is on Drive B: in User Area 10
|
||||
\ \ \__ File to be edited
|
||||
\ \__ Invoke the WM.COM file (Word Master editor)
|
||||
\__ User is on Drive B: in User Area 10
|
||||
|
||||
Results:
|
||||
ZCPR searches B: User 10, B: User 0, and A: User 0 for
|
||||
@@ -823,8 +820,8 @@
|
||||
back into B: User 10, and executes it.
|
||||
|
||||
B10>MBASIC
|
||||
^ ^----- Invoke the MBASIC.COM file (MBASIC Interpreter)
|
||||
+--------- User is on Drive B: in User Area 10
|
||||
\ \__ Invoke the MBASIC.COM file (MBASIC Interpreter)
|
||||
\__ User is on Drive B: in User Area 10
|
||||
|
||||
Results:
|
||||
ZCPR searches B: User 10 and B: User 0 for MBASIC.COM;
|
||||
@@ -833,8 +830,8 @@
|
||||
in the previous example.
|
||||
|
||||
B10>TEST
|
||||
^ ^--- Invoke the TEST.COM file (TEST program)
|
||||
+------- User is on Drive B: in User Area 10
|
||||
\ \__ Invoke the TEST.COM file (TEST program)
|
||||
\__ User is on Drive B: in User Area 10
|
||||
|
||||
Results:
|
||||
ZCPR searches B: User 10 for TEST.COM; it finds
|
||||
@@ -843,8 +840,8 @@
|
||||
then loaded and executed as described above.
|
||||
|
||||
B10>TEST2
|
||||
| +--- Invoke the TEST2.COM file (TEST2 program)
|
||||
+------- User is on Drive B: in User Area 10
|
||||
\ \__ Invoke the TEST2.COM file (TEST2 program)
|
||||
\__ User is on Drive B: in User Area 10
|
||||
|
||||
Results:
|
||||
ZCPR searches B: User 10, B: User 0, and A: User 0 for
|
||||
@@ -1381,4 +1378,10 @@
|
||||
|
||||
|
||||
|
||||
Page 21
|
||||
Page 21
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
BIN
Doc/Source/Bank Switched Memory.vsd
Normal file
BIN
Doc/Source/Bank Switched Memory.vsd
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -14,7 +14,7 @@ Beyond the construction and integration of the actual DOS itself, the majority o
|
||||
|
||||
The remainder of this document details the changes I made as I went along. In all cases, my goal was to keep the result as close to the original distribution as possible. I started by copying all of the files from the distribution (contained in zsdos2.zip) into Support\ZSDOS. From there I tested, modified, updated, and customized as documented below. Finally, I cherry picked files that made sense to include on the ZSystem ROM disks.
|
||||
|
||||
1. CLOCKS.DAT has been updated to include the RomWBW clock driver, HBCLK. I have also added the SIMHCLOK clock driver.
|
||||
1. CLOCKS.DAT has been updated to include the N8VEM clock drivers, N8VEMCLK AND N8CLK. I have also added the SIMHCLOK clock driver.
|
||||
|
||||
2. STAMPS.DAT has been replaced with an updated version. The update was called STAMPS11.DAT and was found on the Walnut Creek CP/M CDROM. The original version has a bug that prevents RSX (resident system extension) mode to load properly.
|
||||
|
||||
29
FixPowerShell.cmd
Normal file
29
FixPowerShell.cmd
Normal file
@@ -0,0 +1,29 @@
|
||||
@echo off
|
||||
echo By default, PowerShell is configured to block the
|
||||
echo execution of unsigned scripts on your local system.
|
||||
echo This command file will attempt to modify your
|
||||
echo PowerShell ExecutionPolicy to "Unrestricted"
|
||||
echo which means that local scripts can be run without
|
||||
echo being signed. This is required to use the RomWBW
|
||||
echo build process.
|
||||
echo.
|
||||
PowerShell -command Write-Host "Your PowerShell ExecutionPolicy is currently set to: `'(Get-ExecutionPolicy)`'"
|
||||
echo.
|
||||
echo In order to modify the ExecutionPolicy, this command
|
||||
echo file *MUST* be run with administrator privileges.
|
||||
echo Generally, this means you want to right-click the
|
||||
echo command file called FixPowerShell.cmd and choose
|
||||
echo "Run as Administrator". If you attempt to continue
|
||||
echo without administrator privileges, the modification
|
||||
echo will fail with an error message, but no harm is done.
|
||||
echo.
|
||||
choice /m "Do you want to proceed"
|
||||
if errorlevel 2 goto :eof
|
||||
echo.
|
||||
echo Attempting to change Execution Policy...
|
||||
echo.
|
||||
PowerShell Set-ExecutionPolicy Unrestricted
|
||||
echo.
|
||||
PowerShell -command Write-Host "Your new PowerShell ExecutionPolicy is now set to: `'(Get-ExecutionPolicy)`'"
|
||||
echo.
|
||||
pause
|
||||
BIN
Hardware/ParPortProp/ParPortProp.eeprom
Normal file
BIN
Hardware/ParPortProp/ParPortProp.eeprom
Normal file
Binary file not shown.
Binary file not shown.
@@ -122,18 +122,19 @@ PUB clrbtm(ColorVal) | i
|
||||
repeat i from 36 to rows - 1 'was 35
|
||||
colors[i] := $0000 + ColorVal
|
||||
|
||||
PUB cls1(VerStr) | i
|
||||
PUB cls1(c,screencolor,pcport,ascii,CR) | i,x,y
|
||||
|
||||
longfill(@screen[0], $20202020, chars / 4)
|
||||
|
||||
clrbtm(TURQUOISE)
|
||||
|
||||
inverse := 1
|
||||
statprint(36, 0, VerStr)
|
||||
inverse := 0
|
||||
|
||||
repeat i from 37 to (rows - 1)
|
||||
statprint(i,0, string(" "))
|
||||
statprint(36,0, string(" N8VEM ParPortProp | RomWBW v0.92"))
|
||||
inverse := 0
|
||||
statprint(37,0, string(" "))
|
||||
statprint(38,0, string(" "))
|
||||
statprint(39,0, string(" "))
|
||||
|
||||
|
||||
{{
|
||||
@@ -151,7 +152,7 @@ PUB cls1(VerStr) | i
|
||||
yloc :=36
|
||||
loc := xloc + yloc*cols
|
||||
inverse := 1
|
||||
str(string(" "))
|
||||
str(string(" propIO V 0.91 "))
|
||||
inverse := 0
|
||||
str(string("Baud Rate: "))
|
||||
i:= BR[6]
|
||||
@@ -214,7 +215,7 @@ PUB clsupdate(c,screencolor,PCPORT,ascii,CR) | i,x,y,locold
|
||||
yloc :=36
|
||||
loc := xloc + yloc*cols
|
||||
inverse := 1
|
||||
str(string(" "))
|
||||
str(string(" propIO V 0.81 "))
|
||||
inverse := 0
|
||||
xloc := 0
|
||||
yloc :=37
|
||||
@@ -25,9 +25,6 @@ CON
|
||||
ERR_3v3_NOT_SUPPORTED = -2
|
||||
ERR_OCR_FAILED = -3
|
||||
ERR_BLOCK_NOT_LONG_ALIGNED = -4
|
||||
ERR_CRC_ONOFF_FAILED = -5
|
||||
ERR_STATUS_FAILED = -6
|
||||
ERR_CSD_FAILED = -7
|
||||
'...
|
||||
' These errors are for the assembly engine...they are negated inside, and need to be <= 511
|
||||
ERR_ASM_NO_READ_TOKEN = 100
|
||||
@@ -61,17 +58,14 @@ CON
|
||||
' buffer size for my debug cmd log
|
||||
'LOG_SIZE = 256<<1
|
||||
|
||||
|
||||
{
|
||||
VAR
|
||||
'long SPI_engine_cog
|
||||
'' these are used for interfacing with the assembly engine | temporary initialization usage
|
||||
'long SPI_command ' "t", "r", "w", 0 =>done, <0 => error | pin mask
|
||||
'long SPI_block_index ' which 512-byte block to read/write | cnt at init
|
||||
'long SPI_buffer_address ' where to get/put the data in Hub RAM | unused
|
||||
|
||||
'long SPI_capacity
|
||||
'byte SPI_csdbuf[16]
|
||||
|
||||
long SPI_engine_cog
|
||||
' these are used for interfacing with the assembly engine | temporary initialization usage
|
||||
long SPI_command ' "t", "r", "w", 0 =>done, <0 => error | pin mask
|
||||
long SPI_block_index ' which 512-byte block to read/write | cnt at init
|
||||
long SPI_buffer_address ' where to get/put the data in Hub RAM | unused
|
||||
'}
|
||||
DAT
|
||||
'' I'm placing these variables in a DAT section to make this driver a singleton.
|
||||
'' If for some reason you really need more than one driver (e.g. if you have more
|
||||
@@ -82,9 +76,6 @@ SPI_command long 0 ' "t", "r", "w", 0 =>done, <0 => error
|
||||
SPI_block_index long 0 ' which 512-byte block to read/write | cnt at init
|
||||
SPI_buffer_address long 0 ' where to get/put the data in Hub RAM | unused
|
||||
|
||||
SPI_capacity long 0
|
||||
SPI_csdbuf byte 0 [16]
|
||||
|
||||
{
|
||||
VAR
|
||||
' for debug ONLY
|
||||
@@ -124,12 +115,6 @@ PUB writeblock( block_index, buffer_address )
|
||||
if SPI_command < 0
|
||||
abort SPI_command
|
||||
|
||||
PUB getcapacity
|
||||
Result := SPI_capacity
|
||||
|
||||
PUB getcsd( buffer_address )
|
||||
bytemove(buffer_address, @SPI_csdbuf, 16)
|
||||
|
||||
PUB get_seconds
|
||||
if SPI_engine_cog == 0
|
||||
abort ERR_SPI_ENGINE_NOT_RUNNING
|
||||
@@ -154,8 +139,6 @@ PUB start_explicit( DO, CLK, DI, CS ) : card_type | tmp, i
|
||||
}}
|
||||
' Start from scratch
|
||||
stop
|
||||
' Reset card capacity
|
||||
SPI_capacity := 0
|
||||
' clear my log buffer
|
||||
{
|
||||
bytefill( @log_cmd_resp, 0, LOG_SIZE+1 )
|
||||
@@ -234,48 +217,10 @@ PUB start_explicit( DO, CLK, DI, CS ) : card_type | tmp, i
|
||||
repeat while send_cmd_slow( CMD1, 0, $F9 )
|
||||
' some SD or MMC cards may have the wrong block size, set it here
|
||||
send_cmd_slow( CMD16, 512, $15 )
|
||||
|
||||
' card is mounted, make sure the CRC is turned off
|
||||
if send_cmd_slow( CMD59, 0, $91 ) <> 0
|
||||
crash( ERR_CRC_ONOFF_FAILED )
|
||||
|
||||
' check card status
|
||||
if send_cmd_slow ( CMD13, 0, $FF) <> 0
|
||||
crash( ERR_STATUS_FAILED )
|
||||
read_slow ' swallow second byte of status
|
||||
|
||||
' get card capacity
|
||||
if send_cmd_slow ( CMD9, 0, $FF) <> 0
|
||||
crash( ERR_CSD_FAILED )
|
||||
i := 32 ' arbitrary timeout
|
||||
repeat while (read_slow <> $FE)
|
||||
if i == 0
|
||||
crash( ERR_CSD_FAILED )
|
||||
repeat i from 0 to 15 ' 16 bytes of CSD data
|
||||
SPI_csdbuf[i] := read_slow
|
||||
read_slow ' discard CRC - first byte
|
||||
read_slow ' discard CRC - second byte
|
||||
|
||||
case (card_type)
|
||||
type_MMC, type_SD:
|
||||
tmp := SPI_csdbuf[9]
|
||||
tmp := (tmp << 8) | SPI_csdbuf[10]
|
||||
i := ((tmp >> 7) & $07) ' c_size_mult
|
||||
tmp := SPI_csdbuf[5]
|
||||
i += tmp & $0F ' mask out read_bl_len and add to c_size_mult
|
||||
tmp := SPI_csdbuf[6] & $03
|
||||
tmp := (tmp << 8) | SPI_csdbuf[7]
|
||||
tmp := (tmp << 8) | SPI_csdbuf[8]
|
||||
tmp := (tmp >> 6) ' c_size
|
||||
SPI_capacity := ((tmp + 1) << (2 + i)) >> 9
|
||||
type_SDHC:
|
||||
tmp := SPI_csdbuf[7] & $3F
|
||||
tmp := (tmp << 8) | SPI_csdbuf[8]
|
||||
tmp := (tmp << 8) | SPI_csdbuf[9]
|
||||
SPI_capacity := (tmp + 1) * 1024
|
||||
other:
|
||||
SPI_capacity := 0
|
||||
|
||||
send_cmd_slow( CMD59, 0, $91 )
|
||||
' check the status
|
||||
'send_cmd_slow( CMD13, 0, $0D )
|
||||
' done with the SPI bus for now
|
||||
outa |= maskCS
|
||||
' set my counter modes for super fast SPI operation
|
||||
BIN
Hardware/ParPortProp/TstPPP.com
Normal file
BIN
Hardware/ParPortProp/TstPPP.com
Normal file
Binary file not shown.
BIN
Hardware/PropIO/PropIO.eeprom
Normal file
BIN
Hardware/PropIO/PropIO.eeprom
Normal file
Binary file not shown.
BIN
Hardware/PropIO/Spin/Keyboard.spin
Normal file
BIN
Hardware/PropIO/Spin/Keyboard.spin
Normal file
Binary file not shown.
BIN
Hardware/PropIO/Spin/Parallax Serial Terminal.spin
Normal file
BIN
Hardware/PropIO/Spin/Parallax Serial Terminal.spin
Normal file
Binary file not shown.
Binary file not shown.
704
Hardware/PropIO/Spin/VGA_1024.spin
Normal file
704
Hardware/PropIO/Spin/VGA_1024.spin
Normal file
@@ -0,0 +1,704 @@
|
||||
'' VGA_1024.spin
|
||||
''
|
||||
'' MODIFIED BY VINCE BRIEL FOR POCKETERM FEATURES
|
||||
'' MODIIFED BY JEFF LEDGER / AKA OLDBITCOLLECTOR
|
||||
''
|
||||
|
||||
CON
|
||||
cols = 80 '128 ' number of screen columns
|
||||
lcols = cols / 4 ' number of long in columns
|
||||
rows = 40 '64 ' number of screen rows
|
||||
chars = rows*cols ' number of screen characters
|
||||
esc = $CB ' keyboard esc char
|
||||
rowsnow = 36 ' adjusted for split screen effect
|
||||
maxChars = rowsnow*cols ' adjusted value for split screen effect
|
||||
lastChar = maxChars / 4 ' last screen position in longs adjusted for split
|
||||
lastLine = (rowsnow - 1) * cols ' character position of last row
|
||||
cols1 = 81 ' adjusted value for 80th character
|
||||
TURQUOISE = $29
|
||||
|
||||
OBJ
|
||||
vga : "vga_Hires_Text"
|
||||
|
||||
VAR
|
||||
byte screen[chars] ' screen character buffer
|
||||
byte tmpl[cols] ' temporary line buffer
|
||||
word colors[rows] ' color specs for each screen row (see ColorPtr description above)
|
||||
byte cursor[6] ' cursor info array (see CursorPtr description above)
|
||||
long sync, loc, xloc, yloc ' sync used by VGA routine, others are local screen pointers
|
||||
long kbdreq ' global val of kbdflag
|
||||
long BR[8]
|
||||
long Brate
|
||||
byte inverse
|
||||
byte invs
|
||||
byte state ' Current state of state machine
|
||||
word pos ' Current Position on the screen
|
||||
word oldpos ' Previous location of cursor before update
|
||||
word regionTop, regionBot ' Scroll region top/bottom
|
||||
long arg0 ' First argument of escape sequence
|
||||
long arg1 ' Second argument of escape sequence
|
||||
byte lastc ' Last displayed char
|
||||
word statpos
|
||||
long vgabasepin
|
||||
|
||||
PUB start(BasePin) | i, char
|
||||
vgabasepin := BasePin
|
||||
|
||||
''init screen colors to gold on blue
|
||||
repeat i from 0 to rows - 1
|
||||
colors[i] := $08F0 '$2804 (if you want cyan on blue)
|
||||
|
||||
''init cursor attributes
|
||||
cursor[2] := %110 ' init cursor to underscore with slow blink
|
||||
BR[0]:=300
|
||||
BR[1]:=1200
|
||||
BR[2]:=2400
|
||||
BR[3]:=4800
|
||||
BR[4]:=9600
|
||||
BR[5]:=19200
|
||||
BR[6]:=38400
|
||||
BR[7]:=57600
|
||||
BR[8]:=115200
|
||||
xloc := cursor[0] := 0
|
||||
yloc := cursor[1] := 0
|
||||
loc := xloc + yloc*cols
|
||||
|
||||
pos := 0
|
||||
regionTop := 0
|
||||
regionBot := 35 * cols
|
||||
state := 0
|
||||
statpos := 37 * cols
|
||||
|
||||
PUB vidon
|
||||
if (!vga.start(vgabasepin, @screen, @colors, @cursor, @sync))
|
||||
return false
|
||||
|
||||
waitcnt(clkfreq * 1 + cnt) 'wait 1 second for cogs to start
|
||||
|
||||
|
||||
PUB vidoff
|
||||
vga.stop
|
||||
|
||||
|
||||
PUB inv(c)
|
||||
inverse:=c
|
||||
|
||||
PUB color(colorVal) | i
|
||||
repeat i from 0 to rows - 1
|
||||
colors[i] := $0000 | colorVal
|
||||
|
||||
PUB cursorset(c) | i
|
||||
i:=%000
|
||||
if c == 1
|
||||
i:= %001
|
||||
if c == 2
|
||||
i:= %010
|
||||
if c == 3
|
||||
i:= %011
|
||||
if c == 4
|
||||
i:= %101
|
||||
if c == 5
|
||||
i:= %110
|
||||
if c == 6
|
||||
i:= %111
|
||||
if c == 7
|
||||
i:= %000
|
||||
cursor[2] := i
|
||||
|
||||
PUB bin(value, digits)
|
||||
|
||||
'' Print a binary number, specify number of digits
|
||||
|
||||
repeat while digits > 32
|
||||
outc("0")
|
||||
digits--
|
||||
|
||||
value <<= 32 - digits
|
||||
|
||||
repeat digits
|
||||
outc((value <-= 1) & 1 + "0")
|
||||
|
||||
|
||||
PUB clrbtm(ColorVal) | i
|
||||
repeat i from 36 to rows - 1 'was 35
|
||||
colors[i] := $0000 + ColorVal
|
||||
|
||||
PUB cls1(c,screencolor,pcport,ascii,CR) | i,x,y
|
||||
|
||||
longfill(@screen[0], $20202020, chars / 4)
|
||||
|
||||
clrbtm(TURQUOISE)
|
||||
|
||||
inverse := 1
|
||||
|
||||
statprint(36,0, string(" N8VEM PropIO | RomWBW v0.94"))
|
||||
inverse := 0
|
||||
statprint(37,0, string(" "))
|
||||
statprint(38,0, string(" "))
|
||||
statprint(39,0, string(" "))
|
||||
|
||||
|
||||
{{
|
||||
x :=xloc
|
||||
y := yloc
|
||||
invs := inverse
|
||||
''clrbtm(TURQUOISE)
|
||||
longfill(@screen, $20202020, chars/4)
|
||||
xloc := 0
|
||||
yloc :=0
|
||||
loc := xloc + yloc*cols
|
||||
repeat 80
|
||||
outc(32)
|
||||
xloc := 0
|
||||
yloc :=36
|
||||
loc := xloc + yloc*cols
|
||||
inverse := 1
|
||||
str(string(" propIO V 0.91 "))
|
||||
inverse := 0
|
||||
str(string("Baud Rate: "))
|
||||
i:= BR[6]
|
||||
dec(i)
|
||||
str(string(" "))
|
||||
xloc := 18
|
||||
loc := xloc + yloc*cols
|
||||
str(string("Color "))
|
||||
str(string("PC Port: "))
|
||||
if pcport == 1
|
||||
str(string("OFF "))
|
||||
if pcport == 0
|
||||
str(string("ON "))
|
||||
str(string(" Force 7 bit: "))
|
||||
if ascii == 0
|
||||
str(string("NO "))
|
||||
if ascii == 1
|
||||
str(string("YES "))
|
||||
str(string(" Cursor CR W/LF: "))
|
||||
if CR == 1
|
||||
str(string("YES"))
|
||||
if CR == 0
|
||||
str(string("NO "))
|
||||
outc(13)
|
||||
outc(10)
|
||||
|
||||
inverse:=1
|
||||
xloc := 6
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F1"))
|
||||
xloc := 19
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F2"))
|
||||
xloc := 30
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F3"))
|
||||
xloc := 46
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F4"))
|
||||
xloc := 58
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F5"))
|
||||
xloc := 70
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F6"))
|
||||
inverse := invs
|
||||
xloc := cursor[0] := x 'right & left was 0
|
||||
yloc := cursor[1] := y 'from top was 1
|
||||
loc := xloc + yloc*cols
|
||||
}}
|
||||
|
||||
PUB clsupdate(c,screencolor,PCPORT,ascii,CR) | i,x,y,locold
|
||||
|
||||
invs := inverse
|
||||
locold := loc
|
||||
x := xloc
|
||||
y := yloc
|
||||
''(TURQUOISE)
|
||||
xloc := 0
|
||||
yloc :=36
|
||||
loc := xloc + yloc*cols
|
||||
inverse := 1
|
||||
str(string(" propIO V 0.81 "))
|
||||
inverse := 0
|
||||
xloc := 0
|
||||
yloc :=37
|
||||
loc := xloc + yloc*cols
|
||||
str(string("Baud Rate: "))
|
||||
i:= BR[6]
|
||||
dec(i)
|
||||
str(string(" "))
|
||||
xloc := 18
|
||||
loc := xloc + yloc*cols
|
||||
|
||||
str(string("Color "))
|
||||
str(string("PC Port: "))
|
||||
if pcport == 1
|
||||
str(string("OFF "))
|
||||
if pcport == 0
|
||||
str(string("ON "))
|
||||
str(string(" Force 7 bit: "))
|
||||
if ascii == 0
|
||||
str(string("NO "))
|
||||
if ascii == 1
|
||||
str(string("YES "))
|
||||
str(string(" Cursor CR W/LF: "))
|
||||
if CR == 1
|
||||
str(string("YES"))
|
||||
if CR == 0
|
||||
str(string("NO "))
|
||||
xloc := 0
|
||||
yloc :=38
|
||||
loc := xloc + yloc*cols
|
||||
inverse:=1
|
||||
xloc := 6
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F1"))
|
||||
xloc := 19
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F2"))
|
||||
xloc := 30
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F3"))
|
||||
xloc := 46
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F4"))
|
||||
xloc := 58
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F5"))
|
||||
xloc := 70
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F6"))
|
||||
inverse := invs
|
||||
xloc := cursor[0] := x
|
||||
yloc := cursor[1] := y
|
||||
' loc := xloc + yloc*cols
|
||||
loc := locold
|
||||
|
||||
PUB dec(value) | i
|
||||
|
||||
'' Print a decimal number
|
||||
|
||||
if value < 0
|
||||
-value
|
||||
outc("-")
|
||||
|
||||
i := 1_000_000_000
|
||||
|
||||
repeat 10
|
||||
if value => i
|
||||
outc(value/i + "0")
|
||||
value //= i
|
||||
result~~
|
||||
elseif result or i == 1
|
||||
outc("0")
|
||||
i /= 10
|
||||
|
||||
PUB hex(value, digits)
|
||||
|
||||
'' Print a hexadecimal number, specify number of digits
|
||||
|
||||
repeat while digits > 8
|
||||
outc("0")
|
||||
digits--
|
||||
|
||||
value <<= (8 - digits) << 2
|
||||
|
||||
repeat digits
|
||||
outc(lookupz((value <-= 4) & $f : "0".."9", "A".."F"))
|
||||
|
||||
|
||||
PUB str(string_ptr)
|
||||
|
||||
'' Print a zero terminated string
|
||||
|
||||
repeat strsize(string_ptr)
|
||||
process_char(byte[string_ptr++])
|
||||
|
||||
PUB statprint(r, c, str1) | x, ptr
|
||||
|
||||
ptr := r * cols + c
|
||||
repeat x from 0 to STRSIZE(str1) - 1
|
||||
putc(ptr++, BYTE[str1 + x])
|
||||
|
||||
PUB statnum(r, c, num1) | i, ptr
|
||||
|
||||
ptr := r * cols + c
|
||||
|
||||
if num1 < 0
|
||||
-num1
|
||||
putc(ptr++,"-")
|
||||
|
||||
i := 1_000_000_000
|
||||
|
||||
repeat 10
|
||||
if num1 => i
|
||||
putc(ptr++, (num1/i +"0"))
|
||||
num1 //= i
|
||||
result~~
|
||||
elseif result or i == 1
|
||||
putc(ptr++, "0")
|
||||
i /= 10
|
||||
|
||||
PUB putc(position, c)
|
||||
if inverse
|
||||
c |= $80
|
||||
screen[position] := c
|
||||
|
||||
PUB cls
|
||||
longfill (@screen, $20202020, lastChar)
|
||||
|
||||
PUB fullcls
|
||||
longfill(@screen, $20202020, 800)
|
||||
|
||||
PUB setInverse(val)
|
||||
inverse := val
|
||||
|
||||
PUB setInv(c)
|
||||
if c == 7
|
||||
setInverse(1)
|
||||
else
|
||||
setInverse(0)
|
||||
|
||||
PUB clEOL(position) | count
|
||||
count := cols - (position // cols)
|
||||
bytefill(@screen + position, $20, count)
|
||||
|
||||
PUB clBOL(position) | count
|
||||
count := position // cols
|
||||
bytefill(@screen + position - count, $20, count)
|
||||
|
||||
PUB delLine(position) | src, count
|
||||
position -= position // cols
|
||||
|
||||
src := position + cols
|
||||
|
||||
count := (maxChars - src) / 4
|
||||
|
||||
if count > 0
|
||||
longmove(@screen + position, @screen + src, count)
|
||||
|
||||
longfill(@screen + lastLine, $20202020, lcols)
|
||||
|
||||
PUB clEOS(position)
|
||||
cleol(position)
|
||||
position += cols - (position // cols)
|
||||
repeat while position < maxChars
|
||||
longfill(@screen + position, $20202020, lcols)
|
||||
pos += cols
|
||||
|
||||
PUB setCursorPos(position)
|
||||
cursor[0] := position // cols
|
||||
cursor[1] := position / cols
|
||||
|
||||
PUB insLine(position) | base, nxt
|
||||
base := position - (position // cols)
|
||||
position := lastLine
|
||||
repeat while position > base
|
||||
nxt := position - cols
|
||||
longmove(@screen + position, @screen + nxt, lcols)
|
||||
position := nxt
|
||||
clEOL(base)
|
||||
|
||||
PUB insChar(position) | count
|
||||
count := (cols - (position // cols)) - 1
|
||||
bytemove(@tmpl, @screen + position, count)
|
||||
screen[position] := " "
|
||||
bytemove(@screen + position + 1, @tmpl, count)
|
||||
|
||||
PUB delChar(position) | count
|
||||
count := (cols - (position // cols)) - 1
|
||||
bytemove(@screen + position, @screen + position + 1, count)
|
||||
screen[position + count] := " "
|
||||
|
||||
PRI inRegion : answer
|
||||
answer := (pos => regionTop) AND (pos < regionBot)
|
||||
|
||||
PRI scrollUp
|
||||
delLine(regionTop)
|
||||
if regionBot < maxChars
|
||||
insLine(regionBot)
|
||||
|
||||
PRI scrollDown
|
||||
if regionBot < maxChars
|
||||
delLine(regionBot)
|
||||
insLine(regionTop)
|
||||
|
||||
PRI ansi(c) | x, defVal
|
||||
|
||||
state := 0
|
||||
|
||||
if (c <> "r") AND (c <> "J") AND (c <> "m") AND (c <> "K")
|
||||
if arg0 == -1
|
||||
arg0 := 1
|
||||
if arg1 == -1
|
||||
arg1 := 1
|
||||
|
||||
case c
|
||||
"@":
|
||||
repeat while arg0-- > 0
|
||||
insChar(pos)
|
||||
|
||||
"b":
|
||||
repeat while arg0-- > 0
|
||||
outc(lastc)
|
||||
|
||||
"d":
|
||||
if (arg0 < 1) OR (arg0 > rows)
|
||||
arg0 := rows
|
||||
pos := ((arg0 - 1) * cols) + (pos // cols)
|
||||
|
||||
"m":
|
||||
setInv(arg0)
|
||||
if arg1 <> -1
|
||||
setInv(arg1)
|
||||
|
||||
"r":
|
||||
if arg0 < 1
|
||||
arg0 := 1
|
||||
elseif arg0 > cols
|
||||
arg0 := cols
|
||||
if arg1 < 1
|
||||
arg1 := 1
|
||||
elseif arg1 > cols
|
||||
arg1 := cols
|
||||
if arg1 < arg0
|
||||
arg1 := arg0
|
||||
|
||||
regionTop := (arg0 - 1) * cols
|
||||
regionBot := arg1 * cols
|
||||
pos := 0
|
||||
|
||||
"A":
|
||||
repeat while arg0-- > 0
|
||||
pos -= cols
|
||||
if pos < 0
|
||||
pos += cols
|
||||
return
|
||||
|
||||
"B":
|
||||
repeat while arg0-- > 0
|
||||
pos += cols
|
||||
if pos => maxChars
|
||||
pos -= cols
|
||||
return
|
||||
|
||||
"C":
|
||||
repeat while arg0-- > 0
|
||||
pos += 1
|
||||
if pos => maxChars
|
||||
pos -= 1
|
||||
return
|
||||
|
||||
"D":
|
||||
repeat while arg0-- > 0
|
||||
pos -= 1
|
||||
if pos < 0
|
||||
pos := 0
|
||||
return
|
||||
|
||||
"G":
|
||||
if (arg0 < 1) OR (arg0 > cols)
|
||||
arg0 := cols
|
||||
pos := (pos - (pos // cols)) + (arg0 - 1)
|
||||
|
||||
"H", "f":
|
||||
if arg0 =< 0
|
||||
arg0 := 1
|
||||
if arg1 =< 0
|
||||
arg1 := 1
|
||||
pos := (cols * (arg0 - 1)) + (arg1 - 1)
|
||||
if pos < 0
|
||||
pos := 0
|
||||
if pos => maxChars
|
||||
pos := maxChars - 1
|
||||
|
||||
"J":
|
||||
if arg0 == 1
|
||||
clBOL(pos)
|
||||
x := pos - cols
|
||||
x -= x // cols
|
||||
repeat while x => 0
|
||||
clEOL(x)
|
||||
x -= cols
|
||||
return
|
||||
|
||||
if arg0 == 2
|
||||
pos := 0
|
||||
|
||||
clEOL(pos)
|
||||
x := pos + cols
|
||||
x -= (x // cols)
|
||||
repeat while x < maxChars
|
||||
clEOL(x)
|
||||
x += cols
|
||||
|
||||
"K":
|
||||
if arg0 == -1
|
||||
clEOL(pos)
|
||||
elseif arg0 == 1
|
||||
clBOL(pos)
|
||||
else
|
||||
clEOL(pos - (pos // cols))
|
||||
|
||||
"L":
|
||||
if inRegion
|
||||
repeat while arg0-- > 0
|
||||
if regionBot < maxChars
|
||||
delLine(regionBot)
|
||||
insLine(pos)
|
||||
|
||||
"M":
|
||||
if inRegion
|
||||
repeat while arg0-- > 0
|
||||
delLine(pos)
|
||||
if regionBot < maxChars
|
||||
insLine(regionBot)
|
||||
|
||||
"P":
|
||||
repeat while arg0--
|
||||
delChar(pos)
|
||||
|
||||
PRI outc(c)
|
||||
|
||||
putc(pos++, lastc := c)
|
||||
if pos == regionBot
|
||||
scrollUp
|
||||
pos -= cols
|
||||
elseif pos == maxChars
|
||||
pos := lastLine
|
||||
|
||||
PUB process_char(c)
|
||||
|
||||
case state
|
||||
|
||||
0:
|
||||
if c > 127
|
||||
c := $20
|
||||
|
||||
if c => $20
|
||||
outc(c)
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
if c == $1B
|
||||
state := 1
|
||||
return
|
||||
|
||||
if c == $0D
|
||||
pos := pos - (pos // cols)
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
if c == $0A
|
||||
if inRegion
|
||||
pos += cols
|
||||
if pos => regionBot
|
||||
scrollUp
|
||||
pos -= cols
|
||||
else
|
||||
pos += cols
|
||||
if pos => maxChars
|
||||
pos -= cols
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
if c == 9
|
||||
pos += (8 - (pos // 8))
|
||||
|
||||
if pos => maxChars
|
||||
pos := lastLine
|
||||
delLine(0)
|
||||
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
if c == 8
|
||||
if pos > 0
|
||||
pos -= 1
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
1:
|
||||
case c
|
||||
"[":
|
||||
arg0 := arg1 := -1
|
||||
state := 2
|
||||
return
|
||||
|
||||
"P":
|
||||
pos += cols
|
||||
if pos => maxChars
|
||||
pos -= cols
|
||||
|
||||
"K":
|
||||
if pos > 0
|
||||
pos -= 1
|
||||
|
||||
"H":
|
||||
pos -= cols
|
||||
if pos < 0
|
||||
pos += cols
|
||||
|
||||
"D":
|
||||
if inRegion
|
||||
scrollUp
|
||||
|
||||
"M":
|
||||
if inRegion
|
||||
scrollDown
|
||||
|
||||
"G":
|
||||
pos := 0
|
||||
|
||||
"(":
|
||||
state := 5
|
||||
return
|
||||
|
||||
state := 0
|
||||
return
|
||||
|
||||
2:
|
||||
if (c => "0") AND (c =< "9")
|
||||
if arg0 == -1
|
||||
arg0 := c - "0"
|
||||
else
|
||||
arg0 := (arg0 * 10) + (c - "0")
|
||||
return
|
||||
|
||||
if c == ";"
|
||||
state := 3
|
||||
return
|
||||
|
||||
ansi(c)
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
3:
|
||||
if (c => "0") AND (c =< "9")
|
||||
if arg1 == -1
|
||||
arg1 := c - "0"
|
||||
else
|
||||
arg1 := (arg1 * 10) + (c - "0")
|
||||
return
|
||||
|
||||
if c == ";"
|
||||
state := 4
|
||||
return
|
||||
|
||||
ansi(c)
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
4:
|
||||
if (c => "0") AND (c =< "9")
|
||||
return
|
||||
|
||||
if c == ";"
|
||||
return
|
||||
ansi(c)
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
5:
|
||||
state := 0
|
||||
return
|
||||
|
||||
return
|
||||
BIN
Hardware/PropIO/Spin/VGA_HiRes_Text.spin
Normal file
BIN
Hardware/PropIO/Spin/VGA_HiRes_Text.spin
Normal file
Binary file not shown.
920
Hardware/PropIO/Spin/safe_spi.spin
Normal file
920
Hardware/PropIO/Spin/safe_spi.spin
Normal file
@@ -0,0 +1,920 @@
|
||||
{{
|
||||
SPI interface routines for SD & SDHC & MMC cards
|
||||
|
||||
Jonathan "lonesock" Dummer
|
||||
version 0.3.0 2009 July 19
|
||||
|
||||
Using multiblock SPI mode exclusively.
|
||||
|
||||
This is the "SAFE" version...uses
|
||||
* 1 instruction per bit writes
|
||||
* 2 instructions per bit reads
|
||||
|
||||
For the fsrw project:
|
||||
fsrw.sf.net
|
||||
}}
|
||||
|
||||
CON
|
||||
' possible card types
|
||||
type_MMC = 1
|
||||
type_SD = 2
|
||||
type_SDHC = 3
|
||||
|
||||
' Error codes
|
||||
ERR_CARD_NOT_RESET = -1
|
||||
ERR_3v3_NOT_SUPPORTED = -2
|
||||
ERR_OCR_FAILED = -3
|
||||
ERR_BLOCK_NOT_LONG_ALIGNED = -4
|
||||
'...
|
||||
' These errors are for the assembly engine...they are negated inside, and need to be <= 511
|
||||
ERR_ASM_NO_READ_TOKEN = 100
|
||||
ERR_ASM_BLOCK_NOT_WRITTEN = 101
|
||||
' NOTE: errors -128 to -255 are reserved for reporting R1 response errors
|
||||
'...
|
||||
ERR_SPI_ENGINE_NOT_RUNNING = -999
|
||||
ERR_CARD_BUSY_TIMEOUT = -1000
|
||||
|
||||
' SDHC/SD/MMC command set for SPI
|
||||
CMD0 = $40+0 ' GO_IDLE_STATE
|
||||
CMD1 = $40+1 ' SEND_OP_COND (MMC)
|
||||
ACMD41 = $C0+41 ' SEND_OP_COND (SDC)
|
||||
CMD8 = $40+8 ' SEND_IF_COND
|
||||
CMD9 = $40+9 ' SEND_CSD
|
||||
CMD10 = $40+10 ' SEND_CID
|
||||
CMD12 = $40+12 ' STOP_TRANSMISSION
|
||||
CMD13 = $40+13 ' SEND_STATUS
|
||||
ACMD13 = $C0+13 ' SD_STATUS (SDC)
|
||||
CMD16 = $40+16 ' SET_BLOCKLEN
|
||||
CMD17 = $40+17 ' READ_SINGLE_BLOCK
|
||||
CMD18 = $40+18 ' READ_MULTIPLE_BLOCK
|
||||
CMD23 = $40+23 ' SET_BLOCK_COUNT (MMC)
|
||||
ACMD23 = $C0+23 ' SET_WR_BLK_ERASE_COUNT (SDC)
|
||||
CMD24 = $40+24 ' WRITE_BLOCK
|
||||
CMD25 = $40+25 ' WRITE_MULTIPLE_BLOCK
|
||||
CMD55 = $40+55 ' APP_CMD
|
||||
CMD58 = $40+58 ' READ_OCR
|
||||
CMD59 = $40+59 ' CRC_ON_OFF
|
||||
|
||||
' buffer size for my debug cmd log
|
||||
'LOG_SIZE = 256<<1
|
||||
|
||||
{
|
||||
VAR
|
||||
long SPI_engine_cog
|
||||
' these are used for interfacing with the assembly engine | temporary initialization usage
|
||||
long SPI_command ' "t", "r", "w", 0 =>done, <0 => error | pin mask
|
||||
long SPI_block_index ' which 512-byte block to read/write | cnt at init
|
||||
long SPI_buffer_address ' where to get/put the data in Hub RAM | unused
|
||||
'}
|
||||
DAT
|
||||
'' I'm placing these variables in a DAT section to make this driver a singleton.
|
||||
'' If for some reason you really need more than one driver (e.g. if you have more
|
||||
'' than a single SD socket), move these back into VAR.
|
||||
SPI_engine_cog long 0
|
||||
' these are used for interfacing with the assembly engine | temporary initialization usage
|
||||
SPI_command long 0 ' "t", "r", "w", 0 =>done, <0 => error | unused
|
||||
SPI_block_index long 0 ' which 512-byte block to read/write | cnt at init
|
||||
SPI_buffer_address long 0 ' where to get/put the data in Hub RAM | unused
|
||||
|
||||
{
|
||||
VAR
|
||||
' for debug ONLY
|
||||
byte log_cmd_resp[LOG_SIZE+1]
|
||||
PUB get_log_pointer
|
||||
return @log_cmd_resp
|
||||
'}
|
||||
|
||||
PUB start( basepin )
|
||||
{{
|
||||
This is a compatibility wrapper, and requires that the pins be
|
||||
both consecutive, and in the order DO CLK DI CS.
|
||||
}}
|
||||
return start_explicit( basepin, basepin+1, basepin+2, basepin+3 )
|
||||
|
||||
PUB readblock( block_index, buffer_address )
|
||||
if SPI_engine_cog == 0
|
||||
abort ERR_SPI_ENGINE_NOT_RUNNING
|
||||
if (buffer_address & 3)
|
||||
abort ERR_BLOCK_NOT_LONG_ALIGNED
|
||||
SPI_block_index := block_index
|
||||
SPI_buffer_address := buffer_address
|
||||
SPI_command := "r"
|
||||
repeat while SPI_command == "r"
|
||||
if SPI_command < 0
|
||||
abort SPI_command
|
||||
|
||||
PUB writeblock( block_index, buffer_address )
|
||||
if SPI_engine_cog == 0
|
||||
abort ERR_SPI_ENGINE_NOT_RUNNING
|
||||
if (buffer_address & 3)
|
||||
abort ERR_BLOCK_NOT_LONG_ALIGNED
|
||||
SPI_block_index := block_index
|
||||
SPI_buffer_address := buffer_address
|
||||
SPI_command := "w"
|
||||
repeat while SPI_command == "w"
|
||||
if SPI_command < 0
|
||||
abort SPI_command
|
||||
|
||||
PUB get_seconds
|
||||
if SPI_engine_cog == 0
|
||||
abort ERR_SPI_ENGINE_NOT_RUNNING
|
||||
SPI_command := "t"
|
||||
repeat while SPI_command == "t"
|
||||
' secods are in SPI_block_index, remainder is in SPI_buffer_address
|
||||
return SPI_block_index
|
||||
|
||||
PUB get_milliseconds : ms
|
||||
if SPI_engine_cog == 0
|
||||
abort ERR_SPI_ENGINE_NOT_RUNNING
|
||||
SPI_command := "t"
|
||||
repeat while SPI_command == "t"
|
||||
' secods are in SPI_block_index, remainder is in SPI_buffer_address
|
||||
ms := SPI_block_index * 1000
|
||||
ms += SPI_buffer_address * 1000 / clkfreq
|
||||
|
||||
PUB start_explicit( DO, CLK, DI, CS ) : card_type | tmp, i
|
||||
{{
|
||||
Do all of the card initialization in SPIN, then hand off the pin
|
||||
information to the assembly cog for hot SPI block R/W action!
|
||||
}}
|
||||
' Start from scratch
|
||||
stop
|
||||
' clear my log buffer
|
||||
{
|
||||
bytefill( @log_cmd_resp, 0, LOG_SIZE+1 )
|
||||
dbg_ptr := @log_cmd_resp
|
||||
dbg_end := dbg_ptr + LOG_SIZE
|
||||
'}
|
||||
' wait ~4 milliseconds
|
||||
waitcnt( 500 + (clkfreq>>8) + cnt )
|
||||
' (start with cog variables, _BEFORE_ loading the cog)
|
||||
pinDO := DO
|
||||
maskDO := |< DO
|
||||
pinCLK := CLK
|
||||
pinDI := DI
|
||||
maskDI := |< DI
|
||||
maskCS := |< CS
|
||||
adrShift := 9 ' block = 512 * index, and 512 = 1<<9
|
||||
' pass the output pin mask via the command register
|
||||
maskAll := maskCS | (|<pinCLK) | maskDI
|
||||
dira |= maskAll
|
||||
' get the card in a ready state: set DI and CS high, send => 74 clocks
|
||||
outa |= maskAll
|
||||
repeat 4096
|
||||
outa[CLK]~~
|
||||
outa[CLK]~
|
||||
' time-hack
|
||||
SPI_block_index := cnt
|
||||
' reset the card
|
||||
tmp~
|
||||
repeat i from 0 to 9
|
||||
if tmp <> 1
|
||||
tmp := send_cmd_slow( CMD0, 0, $95 )
|
||||
if (tmp & 4)
|
||||
' the card said CMD0 ("go idle") was invalid, so we're possibly stuck in read or write mode
|
||||
if i & 1
|
||||
' exit multiblock read mode
|
||||
repeat 4
|
||||
read_32_slow ' these extra clocks are required for some MMC cards
|
||||
send_slow( $FD, 8 ) ' stop token
|
||||
read_32_slow
|
||||
repeat while read_slow <> $FF
|
||||
else
|
||||
' exit multiblock read mode
|
||||
send_cmd_slow( CMD12, 0, $61 )
|
||||
if tmp <> 1
|
||||
' the reset command failed!
|
||||
crash( ERR_CARD_NOT_RESET )
|
||||
' Is this a SD type 2 card?
|
||||
if send_cmd_slow( CMD8, $1AA, $87 ) == 1
|
||||
' Type2 SD, check to see if it's a SDHC card
|
||||
tmp := read_32_slow
|
||||
' check the supported voltage
|
||||
if (tmp & $1FF) <> $1AA
|
||||
crash( ERR_3v3_NOT_SUPPORTED )
|
||||
' try to initialize the type 2 card with the High Capacity bit
|
||||
repeat while send_cmd_slow( ACMD41, |<30, $77 )
|
||||
' the card is initialized, let's read back the High Capacity bit
|
||||
if send_cmd_slow( CMD58, 0, $FD ) <> 0
|
||||
crash( ERR_OCR_FAILED )
|
||||
' get back the data
|
||||
tmp := read_32_slow
|
||||
' check the bit
|
||||
if tmp & |<30
|
||||
card_type := type_SDHC
|
||||
adrShift := 0
|
||||
else
|
||||
card_type := type_SD
|
||||
else
|
||||
' Either a type 1 SD card, or it's MMC, try SD 1st
|
||||
if send_cmd_slow( ACMD41, 0, $E5 ) < 2
|
||||
' this is a type 1 SD card (1 means busy, 0 means done initializing)
|
||||
card_type := type_SD
|
||||
repeat while send_cmd_slow( ACMD41, 0, $E5 )
|
||||
else
|
||||
' mark that it's MMC, and try to initialize
|
||||
card_type := type_MMC
|
||||
repeat while send_cmd_slow( CMD1, 0, $F9 )
|
||||
' some SD or MMC cards may have the wrong block size, set it here
|
||||
send_cmd_slow( CMD16, 512, $15 )
|
||||
' card is mounted, make sure the CRC is turned off
|
||||
send_cmd_slow( CMD59, 0, $91 )
|
||||
' check the status
|
||||
'send_cmd_slow( CMD13, 0, $0D )
|
||||
' done with the SPI bus for now
|
||||
outa |= maskCS
|
||||
' set my counter modes for super fast SPI operation
|
||||
' writing: NCO single-ended mode, output on DI
|
||||
writeMode := (%00100 << 26) | (DI << 0)
|
||||
' reading
|
||||
'readMode := (%11000 << 26) | (DO << 0) | (CLK << 9)
|
||||
' clock
|
||||
'clockLineMode := (%00110 << 26) | (CLK << 0) ' DUTY, 25% duty cycle
|
||||
' clock
|
||||
clockLineMode := (%00100 << 26) | (CLK << 0) ' NCO, 50% duty cycle
|
||||
' how many bytes (8 clocks, >>3) fit into 1/2 of a second (>>1), 4 clocks per instruction (>>2)?
|
||||
N_in8_500ms := clkfreq >> constant(1+2+3)
|
||||
' how long should we wait before auto-exiting any multiblock mode?
|
||||
idle_limit := 125 ' ms, NEVER make this > 1000
|
||||
idle_limit := clkfreq / (1000 / idle_limit) ' convert to counts
|
||||
' Hand off control to the assembly engine's cog
|
||||
bufAdr := @SPI_buffer_address
|
||||
sdAdr := @SPI_block_index
|
||||
SPI_command := 0 ' just make sure it's not 1
|
||||
' start my driver cog and wait till I hear back that it's done
|
||||
SPI_engine_cog := cognew( @SPI_engine_entry, @SPI_command ) + 1
|
||||
if( SPI_engine_cog == 0 )
|
||||
crash( ERR_SPI_ENGINE_NOT_RUNNING )
|
||||
repeat while SPI_command <> -1
|
||||
' and we no longer need to control any pins from here
|
||||
dira &= !maskAll
|
||||
' the return variable is card_type
|
||||
|
||||
PUB release
|
||||
{{
|
||||
I do not want to abort if the cog is not
|
||||
running, as this is called from stop, which
|
||||
is called from start/ [8^)
|
||||
}}
|
||||
if SPI_engine_cog
|
||||
SPI_command := "z"
|
||||
repeat while SPI_command == "z"
|
||||
|
||||
PUB stop
|
||||
{{
|
||||
kill the assembly driver cog.
|
||||
}}
|
||||
release
|
||||
if SPI_engine_cog
|
||||
cogstop( SPI_engine_cog~ - 1 )
|
||||
|
||||
PRI crash( abort_code )
|
||||
{{
|
||||
In case of Bad Things(TM) happening,
|
||||
exit as gracefully as possible.
|
||||
}}
|
||||
' and we no longer need to control any pins from here
|
||||
dira &= !maskAll
|
||||
' and report our error
|
||||
abort abort_code
|
||||
|
||||
PRI send_cmd_slow( cmd, val, crc ) : reply | time_stamp
|
||||
{{
|
||||
Send down a command and return the reply.
|
||||
Note: slow is an understatement!
|
||||
Note: this uses the assembly DAT variables for pin IDs,
|
||||
which means that if you run this multiple times (say for
|
||||
multiple SD cards), these values will change for each one.
|
||||
But this is OK as all of these functions will be called
|
||||
during the initialization only, before the PASM engine is
|
||||
running.
|
||||
}}
|
||||
' if this is an application specific command, handle it
|
||||
if (cmd & $80)
|
||||
' ACMD<n> is the command sequense of CMD55-CMD<n>
|
||||
cmd &= $7F
|
||||
reply := send_cmd_slow( CMD55, 0, $65 )
|
||||
if (reply > 1)
|
||||
return reply
|
||||
' the CS line needs to go low during this operation
|
||||
outa |= maskCS
|
||||
outa &= !maskCS
|
||||
' give the card a few cocks to finish whatever it was doing
|
||||
read_32_slow
|
||||
' send the command byte
|
||||
send_slow( cmd, 8 )
|
||||
' send the value long
|
||||
send_slow( val, 32 )
|
||||
' send the CRC byte
|
||||
send_slow( crc, 8 )
|
||||
' is this a CMD12?, if so, stuff byte
|
||||
if cmd == CMD12
|
||||
read_slow
|
||||
' read back the response (spec declares 1-8 reads max for SD, MMC is 0-8)
|
||||
time_stamp := 9
|
||||
repeat
|
||||
reply := read_slow
|
||||
while( reply & $80 ) and ( time_stamp-- )
|
||||
' done, and 'reply' is already pre-loaded
|
||||
{
|
||||
if dbg_ptr < (dbg_end-1)
|
||||
byte[dbg_ptr++] := cmd
|
||||
byte[dbg_ptr++] := reply
|
||||
if (cmd&63) == 13
|
||||
' get the second byte
|
||||
byte[dbg_ptr++] := cmd
|
||||
byte[dbg_ptr++] := read_slow
|
||||
'}
|
||||
|
||||
PRI send_slow( value, bits_to_send )
|
||||
value ><= bits_to_send
|
||||
repeat bits_to_send
|
||||
outa[pinCLK]~
|
||||
outa[pinDI] := value
|
||||
value >>= 1
|
||||
outa[pinCLK]~~
|
||||
|
||||
PRI read_32_slow : r
|
||||
repeat 4
|
||||
r <<= 8
|
||||
r |= read_slow
|
||||
|
||||
PRI read_slow : r
|
||||
{{
|
||||
Read back 8 bits from the card
|
||||
}}
|
||||
' we need the DI line high so a read can occur
|
||||
outa[pinDI]~~
|
||||
' get 8 bits (remember, r is initialized to 0 by SPIN)
|
||||
repeat 8
|
||||
outa[pinCLK]~
|
||||
outa[pinCLK]~~
|
||||
r += r + ina[pinDO]
|
||||
' error check
|
||||
if( (cnt - SPI_block_index) > (clkfreq << 2) )
|
||||
crash( ERR_CARD_BUSY_TIMEOUT )
|
||||
|
||||
DAT
|
||||
{{
|
||||
This is the assembly engine for doing fast block
|
||||
reads and writes. This is *ALL* it does!
|
||||
}}
|
||||
ORG 0
|
||||
SPI_engine_entry
|
||||
' Counter A drives data out
|
||||
mov ctra,writeMode
|
||||
' Counter B will always drive my clock line
|
||||
mov ctrb,clockLineMode
|
||||
' set our output pins to match the pin mask
|
||||
mov dira,maskAll
|
||||
' handshake that we now control the pins
|
||||
neg user_request,#1
|
||||
wrlong user_request,par
|
||||
' start my seconds' counter here
|
||||
mov last_time,cnt
|
||||
|
||||
waiting_for_command
|
||||
' update my seconds counter, but also track the idle
|
||||
' time so we can to release the card after timeout.
|
||||
call #handle_time
|
||||
' read the command, and make sure it's from the user (> 0)
|
||||
rdlong user_request,par
|
||||
cmps user_request,#0 wz,wc
|
||||
if_be jmp #waiting_for_command
|
||||
' handle our card based commands
|
||||
cmp user_request,#"r" wz
|
||||
if_z jmp #read_ahead
|
||||
cmp user_request,#"w" wz
|
||||
if_z jmp #write_behind
|
||||
cmp user_request,#"z" wz
|
||||
if_z jmp #release_card
|
||||
' time requests are handled differently
|
||||
cmp user_request,#"t" wz ' time
|
||||
if_z wrlong seconds,sdAdr ' seconds goes into the SD index register
|
||||
if_z wrlong dtime,bufAdr ' the remainder goes into the buffer address register
|
||||
' in all other cases, clear the user's request
|
||||
mov user_request,#0
|
||||
wrlong user_request,par
|
||||
jmp #waiting_for_command
|
||||
|
||||
|
||||
release_card
|
||||
mov user_cmd,#"z" ' request a release
|
||||
neg lastIndexPlus,#1 ' reset the last block index
|
||||
neg user_idx,#1 ' and make this match it
|
||||
call #handle_command
|
||||
mov user_request,user_cmd
|
||||
wrlong user_request,par
|
||||
jmp #waiting_for_command
|
||||
|
||||
read_ahead
|
||||
rdlong user_idx,sdAdr
|
||||
' if the correct block is not already loaded, load it
|
||||
mov tmp1,user_idx
|
||||
add tmp1,#1
|
||||
cmp tmp1,lastIndexPlus wz
|
||||
if_z cmp lastCommand,#"r" wz
|
||||
if_z jmp #:get_on_with_it
|
||||
mov user_cmd,#"r"
|
||||
call #handle_command
|
||||
:get_on_with_it
|
||||
' copy the data up into Hub RAM
|
||||
movi transfer_long,#%000010_000 'set to wrlong
|
||||
call #hub_cog_transfer
|
||||
' signify that the data is ready, Spin can continue
|
||||
mov user_request,user_cmd
|
||||
wrlong user_request,par
|
||||
' request the next block
|
||||
mov user_cmd,#"r"
|
||||
add user_idx,#1
|
||||
call #handle_command
|
||||
' done
|
||||
jmp #waiting_for_command
|
||||
|
||||
write_behind
|
||||
rdlong user_idx,sdAdr
|
||||
' copy data in from Hub RAM
|
||||
movi transfer_long,#%000010_001 'set to rdlong
|
||||
call #hub_cog_transfer
|
||||
' signify that we have the data, Spin can continue
|
||||
mov user_request,user_cmd
|
||||
wrlong user_request,par
|
||||
' write out the block
|
||||
mov user_cmd,#"w"
|
||||
call #handle_command
|
||||
' done
|
||||
jmp #waiting_for_command
|
||||
|
||||
{{
|
||||
Set user_cmd and user_idx before calling this
|
||||
}}
|
||||
handle_command
|
||||
' Can we stay in the old mode? (address = old_address+1) && (old mode == new_mode)
|
||||
cmp lastIndexPlus,user_idx wz
|
||||
if_z cmp user_cmd,lastCommand wz
|
||||
if_z jmp #:execute_block_command
|
||||
' we fell through, must exit the old mode! (except if the old mode was "release")
|
||||
cmp lastCommand,#"w" wz
|
||||
if_z call #stop_mb_write
|
||||
cmp lastCommand,#"r" wz
|
||||
if_z call #stop_mb_read
|
||||
' and start up the new mode!
|
||||
cmp user_cmd,#"w" wz
|
||||
if_z call #start_mb_write
|
||||
cmp user_cmd,#"r" wz
|
||||
if_z call #start_mb_read
|
||||
cmp user_cmd,#"z" wz
|
||||
if_z call #release_DO
|
||||
:execute_block_command
|
||||
' track the (new) last index and command
|
||||
mov lastIndexPlus,user_idx
|
||||
add lastIndexPlus,#1
|
||||
mov lastCommand,user_cmd
|
||||
' do the block read or write or terminate!
|
||||
cmp user_cmd,#"w" wz
|
||||
if_z call #write_single_block
|
||||
cmp user_cmd,#"r" wz
|
||||
if_z call #read_single_block
|
||||
cmp user_cmd,#"z" wz
|
||||
if_z mov user_cmd,#0
|
||||
' done
|
||||
handle_command_ret
|
||||
ret
|
||||
|
||||
{=== these PASM functions get me in and out of multiblock mode ===}
|
||||
release_DO
|
||||
' we're already out of multiblock mode, so
|
||||
' deselect the card and send out some clocks
|
||||
or outa,maskCS
|
||||
call #in8
|
||||
call #in8
|
||||
' if you are using pull-up resistors, and need all
|
||||
' lines tristated, then uncomment the following line.
|
||||
' for Cluso99
|
||||
'mov dira,#0
|
||||
release_DO_ret
|
||||
ret
|
||||
|
||||
start_mb_read
|
||||
movi block_cmd,#CMD18<<1
|
||||
call #send_SPI_command_fast
|
||||
start_mb_read_ret
|
||||
ret
|
||||
|
||||
stop_mb_read
|
||||
movi block_cmd,#CMD12<<1
|
||||
call #send_SPI_command_fast
|
||||
call #busy_fast
|
||||
stop_mb_read_ret
|
||||
ret
|
||||
|
||||
start_mb_write
|
||||
movi block_cmd,#CMD25<<1
|
||||
call #send_SPI_command_fast
|
||||
start_mb_write_ret
|
||||
ret
|
||||
|
||||
stop_mb_write
|
||||
call #busy_fast
|
||||
' only some cards need these extra clocks
|
||||
mov tmp1,#16
|
||||
:loopity
|
||||
call #in8
|
||||
djnz tmp1,#:loopity
|
||||
' done with hack
|
||||
movi phsa,#$FD<<1
|
||||
call #out8
|
||||
call #in8 ' stuff byte
|
||||
call #busy_fast
|
||||
stop_mb_write_ret
|
||||
ret
|
||||
|
||||
send_SPI_command_fast
|
||||
' make sure we have control of the output lines
|
||||
mov dira,maskAll
|
||||
' make sure the CS line transitions low
|
||||
or outa,maskCS
|
||||
andn outa,maskCS
|
||||
' 8 clocks
|
||||
call #in8
|
||||
' send the data
|
||||
mov phsa,block_cmd ' do which ever block command this is (already in the top 8 bits)
|
||||
call #out8 ' write the byte
|
||||
mov phsa,user_idx ' read in the desired block index
|
||||
shl phsa,adrShift ' this will multiply by 512 (bytes/sector) for MMC and SD
|
||||
call #out8 ' move out the 1st MSB '
|
||||
rol phsa,#1
|
||||
call #out8 ' move out the 1st MSB '
|
||||
rol phsa,#1
|
||||
call #out8 ' move out the 1st MSB '
|
||||
rol phsa,#1
|
||||
call #out8 ' move out the 1st MSB '
|
||||
' bogus CRC value
|
||||
call #in8 ' in8 looks like out8 with $FF
|
||||
' CMD12 requires a stuff byte
|
||||
shr block_cmd,#24
|
||||
cmp block_cmd,#CMD12 wz
|
||||
if_z call #in8 ' 8 clocks
|
||||
' get the response
|
||||
mov tmp1,#9
|
||||
:cmd_response
|
||||
call #in8
|
||||
test readback,#$80 wc,wz
|
||||
if_c djnz tmp1,#:cmd_response
|
||||
if_nz neg user_cmd,readback
|
||||
' done
|
||||
send_SPI_command_fast_ret
|
||||
ret
|
||||
|
||||
|
||||
busy_fast
|
||||
mov tmp1,N_in8_500ms
|
||||
:still_busy
|
||||
call #in8
|
||||
cmp readback,#$FF wz
|
||||
if_nz djnz tmp1,#:still_busy
|
||||
busy_fast_ret
|
||||
ret
|
||||
|
||||
|
||||
out8
|
||||
andn outa,maskDI
|
||||
'movi phsb,#%11_0000000
|
||||
mov phsb,#0
|
||||
movi frqb,#%01_0000000
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
mov frqb,#0
|
||||
' don't shift out the final bit...already sent, but be aware
|
||||
' of this when sending consecutive bytes (send_cmd, for e.g.)
|
||||
out8_ret
|
||||
ret
|
||||
|
||||
{
|
||||
in8
|
||||
or outa,maskDI
|
||||
mov ctra,readMode
|
||||
' Start my clock
|
||||
mov frqa,#1<<7
|
||||
mov phsa,#0
|
||||
movi phsb,#%11_0000000
|
||||
movi frqb,#%01_0000000
|
||||
' keep reading in my value, one bit at a time! (Kuneko - "Wh)
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
mov frqb,#0 ' stop the clock
|
||||
mov readback,phsa
|
||||
mov frqa,#0
|
||||
mov ctra,writeMode
|
||||
in8_ret
|
||||
ret
|
||||
}
|
||||
in8
|
||||
neg phsa,#1' DI high
|
||||
mov readback,#0
|
||||
' set up my clock, and start it
|
||||
movi phsb,#%011_000000
|
||||
movi frqb,#%001_000000
|
||||
' keep reading in my value
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
mov frqb,#0 ' stop the clock
|
||||
rcl readback,#1
|
||||
mov phsa,#0 'DI low
|
||||
in8_ret
|
||||
ret
|
||||
|
||||
|
||||
' this is called more frequently than 1 Hz, and
|
||||
' is only called when the user command is 0.
|
||||
handle_time
|
||||
mov tmp1,cnt ' get the current timestamp
|
||||
add idle_time,tmp1 ' add the current time to my idle time counter
|
||||
sub idle_time,last_time ' subtract the last time from my idle counter (hence delta)
|
||||
add dtime,tmp1 ' add to my accumulator,
|
||||
sub dtime,last_time ' and subtract the old (adding delta)
|
||||
mov last_time,tmp1 ' update my "last timestamp"
|
||||
rdlong tmp1,#0 ' what is the clock frequency?
|
||||
cmpsub dtime,tmp1 wc ' if I have more than a second in my accumulator
|
||||
addx seconds,#0 ' then add it to "seconds"
|
||||
' this part is to auto-release the card after a timeout
|
||||
cmp idle_time,idle_limit wz,wc
|
||||
if_b jmp #handle_time_ret ' don't clear if we haven't hit the limit
|
||||
mov user_cmd,#"z" ' we can't overdo it, the command handler makes sure
|
||||
neg lastIndexPlus,#1 ' reset the last block index
|
||||
neg user_idx,#1 ' and make this match it
|
||||
call #handle_command ' release the card, but don't mess with the user's request register
|
||||
handle_time_ret
|
||||
ret
|
||||
|
||||
hub_cog_transfer
|
||||
' setup for all 4 passes
|
||||
mov ctrb,clockXferMode
|
||||
mov frqb,#1
|
||||
rdlong buf_ptr,bufAdr
|
||||
mov ops_left,#4
|
||||
movd transfer_long,#speed_buf
|
||||
four_transfer_passes
|
||||
' sync to the Hub RAM access
|
||||
rdlong tmp1,tmp1
|
||||
' how many long to move on this pass? (512 bytes / 4)longs / 4 passes
|
||||
mov tmp1,#(512 / 4 / 4)
|
||||
' get my starting address right (phsb is incremented 1 per clock, so 16 each Hub access)
|
||||
mov phsb,buf_ptr
|
||||
' write the longs, stride 4...low 2 bits of phsb are ignored
|
||||
transfer_long
|
||||
rdlong 0-0,phsb
|
||||
add transfer_long,incDest4
|
||||
djnz tmp1,#transfer_long
|
||||
' go back to where I started, but advanced 1 long
|
||||
sub transfer_long,decDestNminus1
|
||||
' offset my Hub pointer by one long per pass
|
||||
add buf_ptr,#4
|
||||
' do all 4 passes
|
||||
djnz ops_left,#four_transfer_passes
|
||||
' restore the counter mode
|
||||
mov frqb,#0
|
||||
mov phsb,#0
|
||||
mov ctrb,clockLineMode
|
||||
hub_cog_transfer_ret
|
||||
ret
|
||||
|
||||
|
||||
read_single_block
|
||||
' where am I sending the data?
|
||||
movd :store_read_long,#speed_buf
|
||||
mov ops_left,#128
|
||||
' wait until the card is ready
|
||||
mov tmp1,N_in8_500ms
|
||||
:get_resp
|
||||
call #in8
|
||||
cmp readback,#$FE wz
|
||||
if_nz djnz tmp1,#:get_resp
|
||||
if_nz neg user_cmd,#ERR_ASM_NO_READ_TOKEN
|
||||
if_nz jmp #read_single_block_ret
|
||||
' set DI high
|
||||
neg phsa,#1
|
||||
' read the data
|
||||
mov ops_left,#128
|
||||
:read_loop
|
||||
mov tmp1,#4
|
||||
movi phsb,#%011_000000
|
||||
:in_byte
|
||||
' Start my clock
|
||||
movi frqb,#%001_000000
|
||||
' keep reading in my value, BACKWARDS! (Brilliant idea by Tom Rokicki!)
|
||||
test maskDO,ina wc
|
||||
rcl readback,#8
|
||||
test maskDO,ina wc
|
||||
muxc readback,#2
|
||||
test maskDO,ina wc
|
||||
muxc readback,#4
|
||||
test maskDO,ina wc
|
||||
muxc readback,#8
|
||||
test maskDO,ina wc
|
||||
muxc readback,#16
|
||||
test maskDO,ina wc
|
||||
muxc readback,#32
|
||||
test maskDO,ina wc
|
||||
muxc readback,#64
|
||||
test maskDO,ina wc
|
||||
mov frqb,#0 ' stop the clock
|
||||
muxc readback,#128
|
||||
' go back for more
|
||||
djnz tmp1,#:in_byte
|
||||
' make it...NOT backwards [8^)
|
||||
rev readback,#0
|
||||
:store_read_long
|
||||
mov 0-0,readback ' due to some counter weirdness, we need this mov
|
||||
add :store_read_long,const512
|
||||
djnz ops_left,#:read_loop
|
||||
|
||||
' set DI low
|
||||
mov phsa,#0
|
||||
|
||||
' now read 2 trailing bytes (CRC)
|
||||
call #in8 ' out8 is 2x faster than in8
|
||||
call #in8 ' and I'm not using the CRC anyway
|
||||
' give an extra 8 clocks in case we pause for a long time
|
||||
call #in8 ' in8 looks like out8($FF)
|
||||
|
||||
' all done successfully
|
||||
mov idle_time,#0
|
||||
mov user_cmd,#0
|
||||
read_single_block_ret
|
||||
ret
|
||||
|
||||
write_single_block
|
||||
' where am I getting the data? (all 512 bytes / 128 longs of it?)
|
||||
movs :write_loop,#speed_buf
|
||||
' read in 512 bytes (128 longs) from Hub RAM and write it to the card
|
||||
mov ops_left,#128
|
||||
' just hold your horses
|
||||
call #busy_fast
|
||||
' $FC for multiblock, $FE for single block
|
||||
movi phsa,#$FC<<1
|
||||
call #out8
|
||||
mov phsb,#0 ' make sure my clock accumulator is right
|
||||
'movi phsb,#%11_0000000
|
||||
:write_loop
|
||||
' read 4 bytes
|
||||
mov phsa,speed_buf
|
||||
add :write_loop,#1
|
||||
' a long in LE order is DCBA
|
||||
rol phsa,#24 ' move A7 into position, so I can do the swizzled version
|
||||
movi frqb,#%010000000 ' start the clock (remember A7 is already in place)
|
||||
rol phsa,#1 ' A7 is going out, at the end of this instr, A6 is in place
|
||||
rol phsa,#1 ' A5
|
||||
rol phsa,#1 ' A4
|
||||
rol phsa,#1 ' A3
|
||||
rol phsa,#1 ' A2
|
||||
rol phsa,#1 ' A1
|
||||
rol phsa,#1 ' A0
|
||||
rol phsa,#17 ' B7
|
||||
rol phsa,#1 ' B6
|
||||
rol phsa,#1 ' B5
|
||||
rol phsa,#1 ' B4
|
||||
rol phsa,#1 ' B3
|
||||
rol phsa,#1 ' B2
|
||||
rol phsa,#1 ' B1
|
||||
rol phsa,#1 ' B0
|
||||
rol phsa,#17 ' C7
|
||||
rol phsa,#1 ' C6
|
||||
rol phsa,#1 ' C5
|
||||
rol phsa,#1 ' C4
|
||||
rol phsa,#1 ' C3
|
||||
rol phsa,#1 ' C2
|
||||
rol phsa,#1 ' C1
|
||||
rol phsa,#1 ' C0
|
||||
rol phsa,#17 ' D7
|
||||
rol phsa,#1 ' D6
|
||||
rol phsa,#1 ' D5
|
||||
rol phsa,#1 ' D4
|
||||
rol phsa,#1 ' D3
|
||||
rol phsa,#1 ' D2
|
||||
rol phsa,#1 ' D1
|
||||
rol phsa,#1 ' D0 will be in place _after_ this instruction
|
||||
mov frqb,#0 ' shuts the clock off, _after_ this instruction
|
||||
djnz ops_left,#:write_loop
|
||||
' write out my two (bogus, using $FF) CRC bytes
|
||||
call #in8
|
||||
call #in8
|
||||
' now read response (I need this response, so can't spoof using out8)
|
||||
call #in8
|
||||
and readback,#$1F
|
||||
cmp readback,#5 wz
|
||||
if_z mov user_cmd,#0 ' great
|
||||
if_nz neg user_cmd,#ERR_ASM_BLOCK_NOT_WRITTEN ' oops
|
||||
' send out another 8 clocks
|
||||
call #in8
|
||||
' all done
|
||||
mov idle_time,#0
|
||||
write_single_block_ret
|
||||
ret
|
||||
|
||||
|
||||
{=== Assembly Interface Variables ===}
|
||||
pinDO long 0 ' pin is controlled by a counter
|
||||
pinCLK long 0 ' pin is controlled by a counter
|
||||
pinDI long 0 ' pin is controlled by a counter
|
||||
maskDO long 0 ' mask for reading the DO line from the card
|
||||
maskDI long 0 ' mask for setting the pin high while reading
|
||||
maskCS long 0 ' mask = (1<<pin), and is controlled directly
|
||||
maskAll long 0
|
||||
adrShift long 9 ' will be 0 for SDHC, 9 for MMC & SD
|
||||
bufAdr long 0 ' where in Hub RAM is the buffer to copy to/from?
|
||||
sdAdr long 0 ' where on the SD card does it read/write?
|
||||
writeMode long 0 ' the counter setup in NCO single ended, clocking data out on pinDI
|
||||
'clockOutMode long 0 ' the counter setup in NCO single ended, driving the clock line on pinCLK
|
||||
N_in8_500ms long 1_000_000 ' used for timeout checking in PASM
|
||||
'readMode long 0
|
||||
clockLineMode long 0
|
||||
clockXferMode long %11111 << 26
|
||||
const512 long 512
|
||||
const1024 long 1024
|
||||
incDest4 long 4 << 9
|
||||
decDestNminus1 long (512 / 4 - 1) << 9
|
||||
|
||||
{=== Initialized PASM Variables ===}
|
||||
seconds long 0
|
||||
dtime long 0
|
||||
idle_time long 0
|
||||
idle_limit long 0
|
||||
|
||||
{=== Multiblock State Machine ===}
|
||||
lastIndexPlus long -1 ' state handler will check against lastIndexPlus, which will not have been -1
|
||||
lastCommand long 0 ' this will never be the last command.
|
||||
|
||||
{=== Debug Logging Pointers ===}
|
||||
{
|
||||
dbg_ptr long 0
|
||||
dbg_end long 0
|
||||
'}
|
||||
|
||||
{=== Assembly Scratch Variables ===}
|
||||
ops_left res 1 ' used as a counter for bytes, words, longs, whatever (start w/ # byte clocks out)
|
||||
readback res 1 ' all reading from the card goes through here
|
||||
tmp1 res 1 ' this may get used in all subroutines...don't use except in lowest
|
||||
user_request res 1 ' the main command variable, read in from Hub: "r"-read single, "w"-write single
|
||||
user_cmd res 1 ' used internally to handle actual commands to be executed
|
||||
user_idx res 1 ' the pointer to the Hub RAM where the data block is/goes
|
||||
block_cmd res 1 ' one of the SD/MMC command codes, no app-specific allowed
|
||||
buf_ptr res 1 ' moving pointer to the Hub RAM buffer
|
||||
last_time res 1 ' tracking the timestamp
|
||||
|
||||
{{
|
||||
496 longs is my total available space in the cog,
|
||||
and I want 128 longs for eventual use as one 512-
|
||||
byte buffer. This gives me a total of 368 longs
|
||||
to use for umount, and a readblock and writeblock
|
||||
for both Hub RAM and Cog buffers.
|
||||
}}
|
||||
speed_buf res 128 ' 512 bytes to be used for read-ahead / write-behind
|
||||
|
||||
'fit 467
|
||||
FIT 496
|
||||
|
||||
'' MIT LICENSE
|
||||
{{
|
||||
' Permission is hereby granted, free of charge, to any person obtaining
|
||||
' a copy of this software and associated documentation files
|
||||
' (the "Software"), to deal in the Software without restriction,
|
||||
' including without limitation the rights to use, copy, modify, merge,
|
||||
' publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
' and to permit persons to whom the Software is furnished to do so,
|
||||
' subject to the following conditions:
|
||||
'
|
||||
' The above copyright notice and this permission notice shall be included
|
||||
' in all copies or substantial portions of the Software.
|
||||
'
|
||||
' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
' EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
' MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
' IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
' CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
' TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
' SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
}}
|
||||
BIN
Hardware/PropIO2/PropIO2.eeprom
Normal file
BIN
Hardware/PropIO2/PropIO2.eeprom
Normal file
Binary file not shown.
1
Hardware/PropIO2/Spin/E555_SPKEngine.spin
Normal file
1
Hardware/PropIO2/Spin/E555_SPKEngine.spin
Normal file
@@ -0,0 +1 @@
|
||||
{{
|
||||
BIN
Hardware/PropIO2/Spin/Keyboard.spin
Normal file
BIN
Hardware/PropIO2/Spin/Keyboard.spin
Normal file
Binary file not shown.
BIN
Hardware/PropIO2/Spin/Parallax Serial Terminal.spin
Normal file
BIN
Hardware/PropIO2/Spin/Parallax Serial Terminal.spin
Normal file
Binary file not shown.
Binary file not shown.
704
Hardware/PropIO2/Spin/VGA_1024.spin
Normal file
704
Hardware/PropIO2/Spin/VGA_1024.spin
Normal file
@@ -0,0 +1,704 @@
|
||||
'' VGA_1024.spin
|
||||
''
|
||||
'' MODIFIED BY VINCE BRIEL FOR POCKETERM FEATURES
|
||||
'' MODIIFED BY JEFF LEDGER / AKA OLDBITCOLLECTOR
|
||||
''
|
||||
|
||||
CON
|
||||
cols = 80 '128 ' number of screen columns
|
||||
lcols = cols / 4 ' number of long in columns
|
||||
rows = 40 '64 ' number of screen rows
|
||||
chars = rows*cols ' number of screen characters
|
||||
esc = $CB ' keyboard esc char
|
||||
rowsnow = 36 ' adjusted for split screen effect
|
||||
maxChars = rowsnow*cols ' adjusted value for split screen effect
|
||||
lastChar = maxChars / 4 ' last screen position in longs adjusted for split
|
||||
lastLine = (rowsnow - 1) * cols ' character position of last row
|
||||
cols1 = 81 ' adjusted value for 80th character
|
||||
TURQUOISE = $29
|
||||
|
||||
OBJ
|
||||
vga : "vga_Hires_Text"
|
||||
|
||||
VAR
|
||||
byte screen[chars] ' screen character buffer
|
||||
byte tmpl[cols] ' temporary line buffer
|
||||
word colors[rows] ' color specs for each screen row (see ColorPtr description above)
|
||||
byte cursor[6] ' cursor info array (see CursorPtr description above)
|
||||
long sync, loc, xloc, yloc ' sync used by VGA routine, others are local screen pointers
|
||||
long kbdreq ' global val of kbdflag
|
||||
long BR[8]
|
||||
long Brate
|
||||
byte inverse
|
||||
byte invs
|
||||
byte state ' Current state of state machine
|
||||
word pos ' Current Position on the screen
|
||||
word oldpos ' Previous location of cursor before update
|
||||
word regionTop, regionBot ' Scroll region top/bottom
|
||||
long arg0 ' First argument of escape sequence
|
||||
long arg1 ' Second argument of escape sequence
|
||||
byte lastc ' Last displayed char
|
||||
word statpos
|
||||
long vgabasepin
|
||||
|
||||
PUB start(BasePin) | i, char
|
||||
vgabasepin := BasePin
|
||||
|
||||
''init screen colors to gold on blue
|
||||
repeat i from 0 to rows - 1
|
||||
colors[i] := $08F0 '$2804 (if you want cyan on blue)
|
||||
|
||||
''init cursor attributes
|
||||
cursor[2] := %110 ' init cursor to underscore with slow blink
|
||||
BR[0]:=300
|
||||
BR[1]:=1200
|
||||
BR[2]:=2400
|
||||
BR[3]:=4800
|
||||
BR[4]:=9600
|
||||
BR[5]:=19200
|
||||
BR[6]:=38400
|
||||
BR[7]:=57600
|
||||
BR[8]:=115200
|
||||
xloc := cursor[0] := 0
|
||||
yloc := cursor[1] := 0
|
||||
loc := xloc + yloc*cols
|
||||
|
||||
pos := 0
|
||||
regionTop := 0
|
||||
regionBot := 35 * cols
|
||||
state := 0
|
||||
statpos := 37 * cols
|
||||
|
||||
PUB vidon
|
||||
if (!vga.start(vgabasepin, @screen, @colors, @cursor, @sync))
|
||||
return false
|
||||
|
||||
waitcnt(clkfreq * 1 + cnt) 'wait 1 second for cogs to start
|
||||
|
||||
|
||||
PUB vidoff
|
||||
vga.stop
|
||||
|
||||
|
||||
PUB inv(c)
|
||||
inverse:=c
|
||||
|
||||
PUB color(colorVal) | i
|
||||
repeat i from 0 to rows - 1
|
||||
colors[i] := $0000 | colorVal
|
||||
|
||||
PUB cursorset(c) | i
|
||||
i:=%000
|
||||
if c == 1
|
||||
i:= %001
|
||||
if c == 2
|
||||
i:= %010
|
||||
if c == 3
|
||||
i:= %011
|
||||
if c == 4
|
||||
i:= %101
|
||||
if c == 5
|
||||
i:= %110
|
||||
if c == 6
|
||||
i:= %111
|
||||
if c == 7
|
||||
i:= %000
|
||||
cursor[2] := i
|
||||
|
||||
PUB bin(value, digits)
|
||||
|
||||
'' Print a binary number, specify number of digits
|
||||
|
||||
repeat while digits > 32
|
||||
outc("0")
|
||||
digits--
|
||||
|
||||
value <<= 32 - digits
|
||||
|
||||
repeat digits
|
||||
outc((value <-= 1) & 1 + "0")
|
||||
|
||||
|
||||
PUB clrbtm(ColorVal) | i
|
||||
repeat i from 36 to rows - 1 'was 35
|
||||
colors[i] := $0000 + ColorVal
|
||||
|
||||
PUB cls1(c,screencolor,pcport,ascii,CR) | i,x,y
|
||||
|
||||
longfill(@screen[0], $20202020, chars / 4)
|
||||
|
||||
clrbtm(TURQUOISE)
|
||||
|
||||
inverse := 1
|
||||
|
||||
statprint(36,0, string(" N8VEM PropIO V2 | RomWBW v0.94"))
|
||||
inverse := 0
|
||||
statprint(37,0, string(" "))
|
||||
statprint(38,0, string(" "))
|
||||
statprint(39,0, string(" "))
|
||||
|
||||
|
||||
{{
|
||||
x :=xloc
|
||||
y := yloc
|
||||
invs := inverse
|
||||
''clrbtm(TURQUOISE)
|
||||
longfill(@screen, $20202020, chars/4)
|
||||
xloc := 0
|
||||
yloc :=0
|
||||
loc := xloc + yloc*cols
|
||||
repeat 80
|
||||
outc(32)
|
||||
xloc := 0
|
||||
yloc :=36
|
||||
loc := xloc + yloc*cols
|
||||
inverse := 1
|
||||
str(string(" propIO V 0.91 "))
|
||||
inverse := 0
|
||||
str(string("Baud Rate: "))
|
||||
i:= BR[6]
|
||||
dec(i)
|
||||
str(string(" "))
|
||||
xloc := 18
|
||||
loc := xloc + yloc*cols
|
||||
str(string("Color "))
|
||||
str(string("PC Port: "))
|
||||
if pcport == 1
|
||||
str(string("OFF "))
|
||||
if pcport == 0
|
||||
str(string("ON "))
|
||||
str(string(" Force 7 bit: "))
|
||||
if ascii == 0
|
||||
str(string("NO "))
|
||||
if ascii == 1
|
||||
str(string("YES "))
|
||||
str(string(" Cursor CR W/LF: "))
|
||||
if CR == 1
|
||||
str(string("YES"))
|
||||
if CR == 0
|
||||
str(string("NO "))
|
||||
outc(13)
|
||||
outc(10)
|
||||
|
||||
inverse:=1
|
||||
xloc := 6
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F1"))
|
||||
xloc := 19
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F2"))
|
||||
xloc := 30
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F3"))
|
||||
xloc := 46
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F4"))
|
||||
xloc := 58
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F5"))
|
||||
xloc := 70
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F6"))
|
||||
inverse := invs
|
||||
xloc := cursor[0] := x 'right & left was 0
|
||||
yloc := cursor[1] := y 'from top was 1
|
||||
loc := xloc + yloc*cols
|
||||
}}
|
||||
|
||||
PUB clsupdate(c,screencolor,PCPORT,ascii,CR) | i,x,y,locold
|
||||
|
||||
invs := inverse
|
||||
locold := loc
|
||||
x := xloc
|
||||
y := yloc
|
||||
''(TURQUOISE)
|
||||
xloc := 0
|
||||
yloc :=36
|
||||
loc := xloc + yloc*cols
|
||||
inverse := 1
|
||||
str(string(" propIO V 0.81 "))
|
||||
inverse := 0
|
||||
xloc := 0
|
||||
yloc :=37
|
||||
loc := xloc + yloc*cols
|
||||
str(string("Baud Rate: "))
|
||||
i:= BR[6]
|
||||
dec(i)
|
||||
str(string(" "))
|
||||
xloc := 18
|
||||
loc := xloc + yloc*cols
|
||||
|
||||
str(string("Color "))
|
||||
str(string("PC Port: "))
|
||||
if pcport == 1
|
||||
str(string("OFF "))
|
||||
if pcport == 0
|
||||
str(string("ON "))
|
||||
str(string(" Force 7 bit: "))
|
||||
if ascii == 0
|
||||
str(string("NO "))
|
||||
if ascii == 1
|
||||
str(string("YES "))
|
||||
str(string(" Cursor CR W/LF: "))
|
||||
if CR == 1
|
||||
str(string("YES"))
|
||||
if CR == 0
|
||||
str(string("NO "))
|
||||
xloc := 0
|
||||
yloc :=38
|
||||
loc := xloc + yloc*cols
|
||||
inverse:=1
|
||||
xloc := 6
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F1"))
|
||||
xloc := 19
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F2"))
|
||||
xloc := 30
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F3"))
|
||||
xloc := 46
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F4"))
|
||||
xloc := 58
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F5"))
|
||||
xloc := 70
|
||||
loc := xloc + yloc*cols
|
||||
str(string("F6"))
|
||||
inverse := invs
|
||||
xloc := cursor[0] := x
|
||||
yloc := cursor[1] := y
|
||||
' loc := xloc + yloc*cols
|
||||
loc := locold
|
||||
|
||||
PUB dec(value) | i
|
||||
|
||||
'' Print a decimal number
|
||||
|
||||
if value < 0
|
||||
-value
|
||||
outc("-")
|
||||
|
||||
i := 1_000_000_000
|
||||
|
||||
repeat 10
|
||||
if value => i
|
||||
outc(value/i + "0")
|
||||
value //= i
|
||||
result~~
|
||||
elseif result or i == 1
|
||||
outc("0")
|
||||
i /= 10
|
||||
|
||||
PUB hex(value, digits)
|
||||
|
||||
'' Print a hexadecimal number, specify number of digits
|
||||
|
||||
repeat while digits > 8
|
||||
outc("0")
|
||||
digits--
|
||||
|
||||
value <<= (8 - digits) << 2
|
||||
|
||||
repeat digits
|
||||
outc(lookupz((value <-= 4) & $f : "0".."9", "A".."F"))
|
||||
|
||||
|
||||
PUB str(string_ptr)
|
||||
|
||||
'' Print a zero terminated string
|
||||
|
||||
repeat strsize(string_ptr)
|
||||
process_char(byte[string_ptr++])
|
||||
|
||||
PUB statprint(r, c, str1) | x, ptr
|
||||
|
||||
ptr := r * cols + c
|
||||
repeat x from 0 to STRSIZE(str1) - 1
|
||||
putc(ptr++, BYTE[str1 + x])
|
||||
|
||||
PUB statnum(r, c, num1) | i, ptr
|
||||
|
||||
ptr := r * cols + c
|
||||
|
||||
if num1 < 0
|
||||
-num1
|
||||
putc(ptr++,"-")
|
||||
|
||||
i := 1_000_000_000
|
||||
|
||||
repeat 10
|
||||
if num1 => i
|
||||
putc(ptr++, (num1/i +"0"))
|
||||
num1 //= i
|
||||
result~~
|
||||
elseif result or i == 1
|
||||
putc(ptr++, "0")
|
||||
i /= 10
|
||||
|
||||
PUB putc(position, c)
|
||||
if inverse
|
||||
c |= $80
|
||||
screen[position] := c
|
||||
|
||||
PUB cls
|
||||
longfill (@screen, $20202020, lastChar)
|
||||
|
||||
PUB fullcls
|
||||
longfill(@screen, $20202020, 800)
|
||||
|
||||
PUB setInverse(val)
|
||||
inverse := val
|
||||
|
||||
PUB setInv(c)
|
||||
if c == 7
|
||||
setInverse(1)
|
||||
else
|
||||
setInverse(0)
|
||||
|
||||
PUB clEOL(position) | count
|
||||
count := cols - (position // cols)
|
||||
bytefill(@screen + position, $20, count)
|
||||
|
||||
PUB clBOL(position) | count
|
||||
count := position // cols
|
||||
bytefill(@screen + position - count, $20, count)
|
||||
|
||||
PUB delLine(position) | src, count
|
||||
position -= position // cols
|
||||
|
||||
src := position + cols
|
||||
|
||||
count := (maxChars - src) / 4
|
||||
|
||||
if count > 0
|
||||
longmove(@screen + position, @screen + src, count)
|
||||
|
||||
longfill(@screen + lastLine, $20202020, lcols)
|
||||
|
||||
PUB clEOS(position)
|
||||
cleol(position)
|
||||
position += cols - (position // cols)
|
||||
repeat while position < maxChars
|
||||
longfill(@screen + position, $20202020, lcols)
|
||||
pos += cols
|
||||
|
||||
PUB setCursorPos(position)
|
||||
cursor[0] := position // cols
|
||||
cursor[1] := position / cols
|
||||
|
||||
PUB insLine(position) | base, nxt
|
||||
base := position - (position // cols)
|
||||
position := lastLine
|
||||
repeat while position > base
|
||||
nxt := position - cols
|
||||
longmove(@screen + position, @screen + nxt, lcols)
|
||||
position := nxt
|
||||
clEOL(base)
|
||||
|
||||
PUB insChar(position) | count
|
||||
count := (cols - (position // cols)) - 1
|
||||
bytemove(@tmpl, @screen + position, count)
|
||||
screen[position] := " "
|
||||
bytemove(@screen + position + 1, @tmpl, count)
|
||||
|
||||
PUB delChar(position) | count
|
||||
count := (cols - (position // cols)) - 1
|
||||
bytemove(@screen + position, @screen + position + 1, count)
|
||||
screen[position + count] := " "
|
||||
|
||||
PRI inRegion : answer
|
||||
answer := (pos => regionTop) AND (pos < regionBot)
|
||||
|
||||
PRI scrollUp
|
||||
delLine(regionTop)
|
||||
if regionBot < maxChars
|
||||
insLine(regionBot)
|
||||
|
||||
PRI scrollDown
|
||||
if regionBot < maxChars
|
||||
delLine(regionBot)
|
||||
insLine(regionTop)
|
||||
|
||||
PRI ansi(c) | x, defVal
|
||||
|
||||
state := 0
|
||||
|
||||
if (c <> "r") AND (c <> "J") AND (c <> "m") AND (c <> "K")
|
||||
if arg0 == -1
|
||||
arg0 := 1
|
||||
if arg1 == -1
|
||||
arg1 := 1
|
||||
|
||||
case c
|
||||
"@":
|
||||
repeat while arg0-- > 0
|
||||
insChar(pos)
|
||||
|
||||
"b":
|
||||
repeat while arg0-- > 0
|
||||
outc(lastc)
|
||||
|
||||
"d":
|
||||
if (arg0 < 1) OR (arg0 > rows)
|
||||
arg0 := rows
|
||||
pos := ((arg0 - 1) * cols) + (pos // cols)
|
||||
|
||||
"m":
|
||||
setInv(arg0)
|
||||
if arg1 <> -1
|
||||
setInv(arg1)
|
||||
|
||||
"r":
|
||||
if arg0 < 1
|
||||
arg0 := 1
|
||||
elseif arg0 > cols
|
||||
arg0 := cols
|
||||
if arg1 < 1
|
||||
arg1 := 1
|
||||
elseif arg1 > cols
|
||||
arg1 := cols
|
||||
if arg1 < arg0
|
||||
arg1 := arg0
|
||||
|
||||
regionTop := (arg0 - 1) * cols
|
||||
regionBot := arg1 * cols
|
||||
pos := 0
|
||||
|
||||
"A":
|
||||
repeat while arg0-- > 0
|
||||
pos -= cols
|
||||
if pos < 0
|
||||
pos += cols
|
||||
return
|
||||
|
||||
"B":
|
||||
repeat while arg0-- > 0
|
||||
pos += cols
|
||||
if pos => maxChars
|
||||
pos -= cols
|
||||
return
|
||||
|
||||
"C":
|
||||
repeat while arg0-- > 0
|
||||
pos += 1
|
||||
if pos => maxChars
|
||||
pos -= 1
|
||||
return
|
||||
|
||||
"D":
|
||||
repeat while arg0-- > 0
|
||||
pos -= 1
|
||||
if pos < 0
|
||||
pos := 0
|
||||
return
|
||||
|
||||
"G":
|
||||
if (arg0 < 1) OR (arg0 > cols)
|
||||
arg0 := cols
|
||||
pos := (pos - (pos // cols)) + (arg0 - 1)
|
||||
|
||||
"H", "f":
|
||||
if arg0 =< 0
|
||||
arg0 := 1
|
||||
if arg1 =< 0
|
||||
arg1 := 1
|
||||
pos := (cols * (arg0 - 1)) + (arg1 - 1)
|
||||
if pos < 0
|
||||
pos := 0
|
||||
if pos => maxChars
|
||||
pos := maxChars - 1
|
||||
|
||||
"J":
|
||||
if arg0 == 1
|
||||
clBOL(pos)
|
||||
x := pos - cols
|
||||
x -= x // cols
|
||||
repeat while x => 0
|
||||
clEOL(x)
|
||||
x -= cols
|
||||
return
|
||||
|
||||
if arg0 == 2
|
||||
pos := 0
|
||||
|
||||
clEOL(pos)
|
||||
x := pos + cols
|
||||
x -= (x // cols)
|
||||
repeat while x < maxChars
|
||||
clEOL(x)
|
||||
x += cols
|
||||
|
||||
"K":
|
||||
if arg0 == -1
|
||||
clEOL(pos)
|
||||
elseif arg0 == 1
|
||||
clBOL(pos)
|
||||
else
|
||||
clEOL(pos - (pos // cols))
|
||||
|
||||
"L":
|
||||
if inRegion
|
||||
repeat while arg0-- > 0
|
||||
if regionBot < maxChars
|
||||
delLine(regionBot)
|
||||
insLine(pos)
|
||||
|
||||
"M":
|
||||
if inRegion
|
||||
repeat while arg0-- > 0
|
||||
delLine(pos)
|
||||
if regionBot < maxChars
|
||||
insLine(regionBot)
|
||||
|
||||
"P":
|
||||
repeat while arg0--
|
||||
delChar(pos)
|
||||
|
||||
PRI outc(c)
|
||||
|
||||
putc(pos++, lastc := c)
|
||||
if pos == regionBot
|
||||
scrollUp
|
||||
pos -= cols
|
||||
elseif pos == maxChars
|
||||
pos := lastLine
|
||||
|
||||
PUB process_char(c)
|
||||
|
||||
case state
|
||||
|
||||
0:
|
||||
if c > 127
|
||||
c := $20
|
||||
|
||||
if c => $20
|
||||
outc(c)
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
if c == $1B
|
||||
state := 1
|
||||
return
|
||||
|
||||
if c == $0D
|
||||
pos := pos - (pos // cols)
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
if c == $0A
|
||||
if inRegion
|
||||
pos += cols
|
||||
if pos => regionBot
|
||||
scrollUp
|
||||
pos -= cols
|
||||
else
|
||||
pos += cols
|
||||
if pos => maxChars
|
||||
pos -= cols
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
if c == 9
|
||||
pos += (8 - (pos // 8))
|
||||
|
||||
if pos => maxChars
|
||||
pos := lastLine
|
||||
delLine(0)
|
||||
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
if c == 8
|
||||
if pos > 0
|
||||
pos -= 1
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
1:
|
||||
case c
|
||||
"[":
|
||||
arg0 := arg1 := -1
|
||||
state := 2
|
||||
return
|
||||
|
||||
"P":
|
||||
pos += cols
|
||||
if pos => maxChars
|
||||
pos -= cols
|
||||
|
||||
"K":
|
||||
if pos > 0
|
||||
pos -= 1
|
||||
|
||||
"H":
|
||||
pos -= cols
|
||||
if pos < 0
|
||||
pos += cols
|
||||
|
||||
"D":
|
||||
if inRegion
|
||||
scrollUp
|
||||
|
||||
"M":
|
||||
if inRegion
|
||||
scrollDown
|
||||
|
||||
"G":
|
||||
pos := 0
|
||||
|
||||
"(":
|
||||
state := 5
|
||||
return
|
||||
|
||||
state := 0
|
||||
return
|
||||
|
||||
2:
|
||||
if (c => "0") AND (c =< "9")
|
||||
if arg0 == -1
|
||||
arg0 := c - "0"
|
||||
else
|
||||
arg0 := (arg0 * 10) + (c - "0")
|
||||
return
|
||||
|
||||
if c == ";"
|
||||
state := 3
|
||||
return
|
||||
|
||||
ansi(c)
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
3:
|
||||
if (c => "0") AND (c =< "9")
|
||||
if arg1 == -1
|
||||
arg1 := c - "0"
|
||||
else
|
||||
arg1 := (arg1 * 10) + (c - "0")
|
||||
return
|
||||
|
||||
if c == ";"
|
||||
state := 4
|
||||
return
|
||||
|
||||
ansi(c)
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
4:
|
||||
if (c => "0") AND (c =< "9")
|
||||
return
|
||||
|
||||
if c == ";"
|
||||
return
|
||||
ansi(c)
|
||||
setCursorPos(pos)
|
||||
return
|
||||
|
||||
5:
|
||||
state := 0
|
||||
return
|
||||
|
||||
return
|
||||
BIN
Hardware/PropIO2/Spin/VGA_HiRes_Text.spin
Normal file
BIN
Hardware/PropIO2/Spin/VGA_HiRes_Text.spin
Normal file
Binary file not shown.
920
Hardware/PropIO2/Spin/safe_spi.spin
Normal file
920
Hardware/PropIO2/Spin/safe_spi.spin
Normal file
@@ -0,0 +1,920 @@
|
||||
{{
|
||||
SPI interface routines for SD & SDHC & MMC cards
|
||||
|
||||
Jonathan "lonesock" Dummer
|
||||
version 0.3.0 2009 July 19
|
||||
|
||||
Using multiblock SPI mode exclusively.
|
||||
|
||||
This is the "SAFE" version...uses
|
||||
* 1 instruction per bit writes
|
||||
* 2 instructions per bit reads
|
||||
|
||||
For the fsrw project:
|
||||
fsrw.sf.net
|
||||
}}
|
||||
|
||||
CON
|
||||
' possible card types
|
||||
type_MMC = 1
|
||||
type_SD = 2
|
||||
type_SDHC = 3
|
||||
|
||||
' Error codes
|
||||
ERR_CARD_NOT_RESET = -1
|
||||
ERR_3v3_NOT_SUPPORTED = -2
|
||||
ERR_OCR_FAILED = -3
|
||||
ERR_BLOCK_NOT_LONG_ALIGNED = -4
|
||||
'...
|
||||
' These errors are for the assembly engine...they are negated inside, and need to be <= 511
|
||||
ERR_ASM_NO_READ_TOKEN = 100
|
||||
ERR_ASM_BLOCK_NOT_WRITTEN = 101
|
||||
' NOTE: errors -128 to -255 are reserved for reporting R1 response errors
|
||||
'...
|
||||
ERR_SPI_ENGINE_NOT_RUNNING = -999
|
||||
ERR_CARD_BUSY_TIMEOUT = -1000
|
||||
|
||||
' SDHC/SD/MMC command set for SPI
|
||||
CMD0 = $40+0 ' GO_IDLE_STATE
|
||||
CMD1 = $40+1 ' SEND_OP_COND (MMC)
|
||||
ACMD41 = $C0+41 ' SEND_OP_COND (SDC)
|
||||
CMD8 = $40+8 ' SEND_IF_COND
|
||||
CMD9 = $40+9 ' SEND_CSD
|
||||
CMD10 = $40+10 ' SEND_CID
|
||||
CMD12 = $40+12 ' STOP_TRANSMISSION
|
||||
CMD13 = $40+13 ' SEND_STATUS
|
||||
ACMD13 = $C0+13 ' SD_STATUS (SDC)
|
||||
CMD16 = $40+16 ' SET_BLOCKLEN
|
||||
CMD17 = $40+17 ' READ_SINGLE_BLOCK
|
||||
CMD18 = $40+18 ' READ_MULTIPLE_BLOCK
|
||||
CMD23 = $40+23 ' SET_BLOCK_COUNT (MMC)
|
||||
ACMD23 = $C0+23 ' SET_WR_BLK_ERASE_COUNT (SDC)
|
||||
CMD24 = $40+24 ' WRITE_BLOCK
|
||||
CMD25 = $40+25 ' WRITE_MULTIPLE_BLOCK
|
||||
CMD55 = $40+55 ' APP_CMD
|
||||
CMD58 = $40+58 ' READ_OCR
|
||||
CMD59 = $40+59 ' CRC_ON_OFF
|
||||
|
||||
' buffer size for my debug cmd log
|
||||
'LOG_SIZE = 256<<1
|
||||
|
||||
{
|
||||
VAR
|
||||
long SPI_engine_cog
|
||||
' these are used for interfacing with the assembly engine | temporary initialization usage
|
||||
long SPI_command ' "t", "r", "w", 0 =>done, <0 => error | pin mask
|
||||
long SPI_block_index ' which 512-byte block to read/write | cnt at init
|
||||
long SPI_buffer_address ' where to get/put the data in Hub RAM | unused
|
||||
'}
|
||||
DAT
|
||||
'' I'm placing these variables in a DAT section to make this driver a singleton.
|
||||
'' If for some reason you really need more than one driver (e.g. if you have more
|
||||
'' than a single SD socket), move these back into VAR.
|
||||
SPI_engine_cog long 0
|
||||
' these are used for interfacing with the assembly engine | temporary initialization usage
|
||||
SPI_command long 0 ' "t", "r", "w", 0 =>done, <0 => error | unused
|
||||
SPI_block_index long 0 ' which 512-byte block to read/write | cnt at init
|
||||
SPI_buffer_address long 0 ' where to get/put the data in Hub RAM | unused
|
||||
|
||||
{
|
||||
VAR
|
||||
' for debug ONLY
|
||||
byte log_cmd_resp[LOG_SIZE+1]
|
||||
PUB get_log_pointer
|
||||
return @log_cmd_resp
|
||||
'}
|
||||
|
||||
PUB start( basepin )
|
||||
{{
|
||||
This is a compatibility wrapper, and requires that the pins be
|
||||
both consecutive, and in the order DO CLK DI CS.
|
||||
}}
|
||||
return start_explicit( basepin, basepin+1, basepin+2, basepin+3 )
|
||||
|
||||
PUB readblock( block_index, buffer_address )
|
||||
if SPI_engine_cog == 0
|
||||
abort ERR_SPI_ENGINE_NOT_RUNNING
|
||||
if (buffer_address & 3)
|
||||
abort ERR_BLOCK_NOT_LONG_ALIGNED
|
||||
SPI_block_index := block_index
|
||||
SPI_buffer_address := buffer_address
|
||||
SPI_command := "r"
|
||||
repeat while SPI_command == "r"
|
||||
if SPI_command < 0
|
||||
abort SPI_command
|
||||
|
||||
PUB writeblock( block_index, buffer_address )
|
||||
if SPI_engine_cog == 0
|
||||
abort ERR_SPI_ENGINE_NOT_RUNNING
|
||||
if (buffer_address & 3)
|
||||
abort ERR_BLOCK_NOT_LONG_ALIGNED
|
||||
SPI_block_index := block_index
|
||||
SPI_buffer_address := buffer_address
|
||||
SPI_command := "w"
|
||||
repeat while SPI_command == "w"
|
||||
if SPI_command < 0
|
||||
abort SPI_command
|
||||
|
||||
PUB get_seconds
|
||||
if SPI_engine_cog == 0
|
||||
abort ERR_SPI_ENGINE_NOT_RUNNING
|
||||
SPI_command := "t"
|
||||
repeat while SPI_command == "t"
|
||||
' secods are in SPI_block_index, remainder is in SPI_buffer_address
|
||||
return SPI_block_index
|
||||
|
||||
PUB get_milliseconds : ms
|
||||
if SPI_engine_cog == 0
|
||||
abort ERR_SPI_ENGINE_NOT_RUNNING
|
||||
SPI_command := "t"
|
||||
repeat while SPI_command == "t"
|
||||
' secods are in SPI_block_index, remainder is in SPI_buffer_address
|
||||
ms := SPI_block_index * 1000
|
||||
ms += SPI_buffer_address * 1000 / clkfreq
|
||||
|
||||
PUB start_explicit( DO, CLK, DI, CS ) : card_type | tmp, i
|
||||
{{
|
||||
Do all of the card initialization in SPIN, then hand off the pin
|
||||
information to the assembly cog for hot SPI block R/W action!
|
||||
}}
|
||||
' Start from scratch
|
||||
stop
|
||||
' clear my log buffer
|
||||
{
|
||||
bytefill( @log_cmd_resp, 0, LOG_SIZE+1 )
|
||||
dbg_ptr := @log_cmd_resp
|
||||
dbg_end := dbg_ptr + LOG_SIZE
|
||||
'}
|
||||
' wait ~4 milliseconds
|
||||
waitcnt( 500 + (clkfreq>>8) + cnt )
|
||||
' (start with cog variables, _BEFORE_ loading the cog)
|
||||
pinDO := DO
|
||||
maskDO := |< DO
|
||||
pinCLK := CLK
|
||||
pinDI := DI
|
||||
maskDI := |< DI
|
||||
maskCS := |< CS
|
||||
adrShift := 9 ' block = 512 * index, and 512 = 1<<9
|
||||
' pass the output pin mask via the command register
|
||||
maskAll := maskCS | (|<pinCLK) | maskDI
|
||||
dira |= maskAll
|
||||
' get the card in a ready state: set DI and CS high, send => 74 clocks
|
||||
outa |= maskAll
|
||||
repeat 4096
|
||||
outa[CLK]~~
|
||||
outa[CLK]~
|
||||
' time-hack
|
||||
SPI_block_index := cnt
|
||||
' reset the card
|
||||
tmp~
|
||||
repeat i from 0 to 9
|
||||
if tmp <> 1
|
||||
tmp := send_cmd_slow( CMD0, 0, $95 )
|
||||
if (tmp & 4)
|
||||
' the card said CMD0 ("go idle") was invalid, so we're possibly stuck in read or write mode
|
||||
if i & 1
|
||||
' exit multiblock read mode
|
||||
repeat 4
|
||||
read_32_slow ' these extra clocks are required for some MMC cards
|
||||
send_slow( $FD, 8 ) ' stop token
|
||||
read_32_slow
|
||||
repeat while read_slow <> $FF
|
||||
else
|
||||
' exit multiblock read mode
|
||||
send_cmd_slow( CMD12, 0, $61 )
|
||||
if tmp <> 1
|
||||
' the reset command failed!
|
||||
crash( ERR_CARD_NOT_RESET )
|
||||
' Is this a SD type 2 card?
|
||||
if send_cmd_slow( CMD8, $1AA, $87 ) == 1
|
||||
' Type2 SD, check to see if it's a SDHC card
|
||||
tmp := read_32_slow
|
||||
' check the supported voltage
|
||||
if (tmp & $1FF) <> $1AA
|
||||
crash( ERR_3v3_NOT_SUPPORTED )
|
||||
' try to initialize the type 2 card with the High Capacity bit
|
||||
repeat while send_cmd_slow( ACMD41, |<30, $77 )
|
||||
' the card is initialized, let's read back the High Capacity bit
|
||||
if send_cmd_slow( CMD58, 0, $FD ) <> 0
|
||||
crash( ERR_OCR_FAILED )
|
||||
' get back the data
|
||||
tmp := read_32_slow
|
||||
' check the bit
|
||||
if tmp & |<30
|
||||
card_type := type_SDHC
|
||||
adrShift := 0
|
||||
else
|
||||
card_type := type_SD
|
||||
else
|
||||
' Either a type 1 SD card, or it's MMC, try SD 1st
|
||||
if send_cmd_slow( ACMD41, 0, $E5 ) < 2
|
||||
' this is a type 1 SD card (1 means busy, 0 means done initializing)
|
||||
card_type := type_SD
|
||||
repeat while send_cmd_slow( ACMD41, 0, $E5 )
|
||||
else
|
||||
' mark that it's MMC, and try to initialize
|
||||
card_type := type_MMC
|
||||
repeat while send_cmd_slow( CMD1, 0, $F9 )
|
||||
' some SD or MMC cards may have the wrong block size, set it here
|
||||
send_cmd_slow( CMD16, 512, $15 )
|
||||
' card is mounted, make sure the CRC is turned off
|
||||
send_cmd_slow( CMD59, 0, $91 )
|
||||
' check the status
|
||||
'send_cmd_slow( CMD13, 0, $0D )
|
||||
' done with the SPI bus for now
|
||||
outa |= maskCS
|
||||
' set my counter modes for super fast SPI operation
|
||||
' writing: NCO single-ended mode, output on DI
|
||||
writeMode := (%00100 << 26) | (DI << 0)
|
||||
' reading
|
||||
'readMode := (%11000 << 26) | (DO << 0) | (CLK << 9)
|
||||
' clock
|
||||
'clockLineMode := (%00110 << 26) | (CLK << 0) ' DUTY, 25% duty cycle
|
||||
' clock
|
||||
clockLineMode := (%00100 << 26) | (CLK << 0) ' NCO, 50% duty cycle
|
||||
' how many bytes (8 clocks, >>3) fit into 1/2 of a second (>>1), 4 clocks per instruction (>>2)?
|
||||
N_in8_500ms := clkfreq >> constant(1+2+3)
|
||||
' how long should we wait before auto-exiting any multiblock mode?
|
||||
idle_limit := 125 ' ms, NEVER make this > 1000
|
||||
idle_limit := clkfreq / (1000 / idle_limit) ' convert to counts
|
||||
' Hand off control to the assembly engine's cog
|
||||
bufAdr := @SPI_buffer_address
|
||||
sdAdr := @SPI_block_index
|
||||
SPI_command := 0 ' just make sure it's not 1
|
||||
' start my driver cog and wait till I hear back that it's done
|
||||
SPI_engine_cog := cognew( @SPI_engine_entry, @SPI_command ) + 1
|
||||
if( SPI_engine_cog == 0 )
|
||||
crash( ERR_SPI_ENGINE_NOT_RUNNING )
|
||||
repeat while SPI_command <> -1
|
||||
' and we no longer need to control any pins from here
|
||||
dira &= !maskAll
|
||||
' the return variable is card_type
|
||||
|
||||
PUB release
|
||||
{{
|
||||
I do not want to abort if the cog is not
|
||||
running, as this is called from stop, which
|
||||
is called from start/ [8^)
|
||||
}}
|
||||
if SPI_engine_cog
|
||||
SPI_command := "z"
|
||||
repeat while SPI_command == "z"
|
||||
|
||||
PUB stop
|
||||
{{
|
||||
kill the assembly driver cog.
|
||||
}}
|
||||
release
|
||||
if SPI_engine_cog
|
||||
cogstop( SPI_engine_cog~ - 1 )
|
||||
|
||||
PRI crash( abort_code )
|
||||
{{
|
||||
In case of Bad Things(TM) happening,
|
||||
exit as gracefully as possible.
|
||||
}}
|
||||
' and we no longer need to control any pins from here
|
||||
dira &= !maskAll
|
||||
' and report our error
|
||||
abort abort_code
|
||||
|
||||
PRI send_cmd_slow( cmd, val, crc ) : reply | time_stamp
|
||||
{{
|
||||
Send down a command and return the reply.
|
||||
Note: slow is an understatement!
|
||||
Note: this uses the assembly DAT variables for pin IDs,
|
||||
which means that if you run this multiple times (say for
|
||||
multiple SD cards), these values will change for each one.
|
||||
But this is OK as all of these functions will be called
|
||||
during the initialization only, before the PASM engine is
|
||||
running.
|
||||
}}
|
||||
' if this is an application specific command, handle it
|
||||
if (cmd & $80)
|
||||
' ACMD<n> is the command sequense of CMD55-CMD<n>
|
||||
cmd &= $7F
|
||||
reply := send_cmd_slow( CMD55, 0, $65 )
|
||||
if (reply > 1)
|
||||
return reply
|
||||
' the CS line needs to go low during this operation
|
||||
outa |= maskCS
|
||||
outa &= !maskCS
|
||||
' give the card a few cocks to finish whatever it was doing
|
||||
read_32_slow
|
||||
' send the command byte
|
||||
send_slow( cmd, 8 )
|
||||
' send the value long
|
||||
send_slow( val, 32 )
|
||||
' send the CRC byte
|
||||
send_slow( crc, 8 )
|
||||
' is this a CMD12?, if so, stuff byte
|
||||
if cmd == CMD12
|
||||
read_slow
|
||||
' read back the response (spec declares 1-8 reads max for SD, MMC is 0-8)
|
||||
time_stamp := 9
|
||||
repeat
|
||||
reply := read_slow
|
||||
while( reply & $80 ) and ( time_stamp-- )
|
||||
' done, and 'reply' is already pre-loaded
|
||||
{
|
||||
if dbg_ptr < (dbg_end-1)
|
||||
byte[dbg_ptr++] := cmd
|
||||
byte[dbg_ptr++] := reply
|
||||
if (cmd&63) == 13
|
||||
' get the second byte
|
||||
byte[dbg_ptr++] := cmd
|
||||
byte[dbg_ptr++] := read_slow
|
||||
'}
|
||||
|
||||
PRI send_slow( value, bits_to_send )
|
||||
value ><= bits_to_send
|
||||
repeat bits_to_send
|
||||
outa[pinCLK]~
|
||||
outa[pinDI] := value
|
||||
value >>= 1
|
||||
outa[pinCLK]~~
|
||||
|
||||
PRI read_32_slow : r
|
||||
repeat 4
|
||||
r <<= 8
|
||||
r |= read_slow
|
||||
|
||||
PRI read_slow : r
|
||||
{{
|
||||
Read back 8 bits from the card
|
||||
}}
|
||||
' we need the DI line high so a read can occur
|
||||
outa[pinDI]~~
|
||||
' get 8 bits (remember, r is initialized to 0 by SPIN)
|
||||
repeat 8
|
||||
outa[pinCLK]~
|
||||
outa[pinCLK]~~
|
||||
r += r + ina[pinDO]
|
||||
' error check
|
||||
if( (cnt - SPI_block_index) > (clkfreq << 2) )
|
||||
crash( ERR_CARD_BUSY_TIMEOUT )
|
||||
|
||||
DAT
|
||||
{{
|
||||
This is the assembly engine for doing fast block
|
||||
reads and writes. This is *ALL* it does!
|
||||
}}
|
||||
ORG 0
|
||||
SPI_engine_entry
|
||||
' Counter A drives data out
|
||||
mov ctra,writeMode
|
||||
' Counter B will always drive my clock line
|
||||
mov ctrb,clockLineMode
|
||||
' set our output pins to match the pin mask
|
||||
mov dira,maskAll
|
||||
' handshake that we now control the pins
|
||||
neg user_request,#1
|
||||
wrlong user_request,par
|
||||
' start my seconds' counter here
|
||||
mov last_time,cnt
|
||||
|
||||
waiting_for_command
|
||||
' update my seconds counter, but also track the idle
|
||||
' time so we can to release the card after timeout.
|
||||
call #handle_time
|
||||
' read the command, and make sure it's from the user (> 0)
|
||||
rdlong user_request,par
|
||||
cmps user_request,#0 wz,wc
|
||||
if_be jmp #waiting_for_command
|
||||
' handle our card based commands
|
||||
cmp user_request,#"r" wz
|
||||
if_z jmp #read_ahead
|
||||
cmp user_request,#"w" wz
|
||||
if_z jmp #write_behind
|
||||
cmp user_request,#"z" wz
|
||||
if_z jmp #release_card
|
||||
' time requests are handled differently
|
||||
cmp user_request,#"t" wz ' time
|
||||
if_z wrlong seconds,sdAdr ' seconds goes into the SD index register
|
||||
if_z wrlong dtime,bufAdr ' the remainder goes into the buffer address register
|
||||
' in all other cases, clear the user's request
|
||||
mov user_request,#0
|
||||
wrlong user_request,par
|
||||
jmp #waiting_for_command
|
||||
|
||||
|
||||
release_card
|
||||
mov user_cmd,#"z" ' request a release
|
||||
neg lastIndexPlus,#1 ' reset the last block index
|
||||
neg user_idx,#1 ' and make this match it
|
||||
call #handle_command
|
||||
mov user_request,user_cmd
|
||||
wrlong user_request,par
|
||||
jmp #waiting_for_command
|
||||
|
||||
read_ahead
|
||||
rdlong user_idx,sdAdr
|
||||
' if the correct block is not already loaded, load it
|
||||
mov tmp1,user_idx
|
||||
add tmp1,#1
|
||||
cmp tmp1,lastIndexPlus wz
|
||||
if_z cmp lastCommand,#"r" wz
|
||||
if_z jmp #:get_on_with_it
|
||||
mov user_cmd,#"r"
|
||||
call #handle_command
|
||||
:get_on_with_it
|
||||
' copy the data up into Hub RAM
|
||||
movi transfer_long,#%000010_000 'set to wrlong
|
||||
call #hub_cog_transfer
|
||||
' signify that the data is ready, Spin can continue
|
||||
mov user_request,user_cmd
|
||||
wrlong user_request,par
|
||||
' request the next block
|
||||
mov user_cmd,#"r"
|
||||
add user_idx,#1
|
||||
call #handle_command
|
||||
' done
|
||||
jmp #waiting_for_command
|
||||
|
||||
write_behind
|
||||
rdlong user_idx,sdAdr
|
||||
' copy data in from Hub RAM
|
||||
movi transfer_long,#%000010_001 'set to rdlong
|
||||
call #hub_cog_transfer
|
||||
' signify that we have the data, Spin can continue
|
||||
mov user_request,user_cmd
|
||||
wrlong user_request,par
|
||||
' write out the block
|
||||
mov user_cmd,#"w"
|
||||
call #handle_command
|
||||
' done
|
||||
jmp #waiting_for_command
|
||||
|
||||
{{
|
||||
Set user_cmd and user_idx before calling this
|
||||
}}
|
||||
handle_command
|
||||
' Can we stay in the old mode? (address = old_address+1) && (old mode == new_mode)
|
||||
cmp lastIndexPlus,user_idx wz
|
||||
if_z cmp user_cmd,lastCommand wz
|
||||
if_z jmp #:execute_block_command
|
||||
' we fell through, must exit the old mode! (except if the old mode was "release")
|
||||
cmp lastCommand,#"w" wz
|
||||
if_z call #stop_mb_write
|
||||
cmp lastCommand,#"r" wz
|
||||
if_z call #stop_mb_read
|
||||
' and start up the new mode!
|
||||
cmp user_cmd,#"w" wz
|
||||
if_z call #start_mb_write
|
||||
cmp user_cmd,#"r" wz
|
||||
if_z call #start_mb_read
|
||||
cmp user_cmd,#"z" wz
|
||||
if_z call #release_DO
|
||||
:execute_block_command
|
||||
' track the (new) last index and command
|
||||
mov lastIndexPlus,user_idx
|
||||
add lastIndexPlus,#1
|
||||
mov lastCommand,user_cmd
|
||||
' do the block read or write or terminate!
|
||||
cmp user_cmd,#"w" wz
|
||||
if_z call #write_single_block
|
||||
cmp user_cmd,#"r" wz
|
||||
if_z call #read_single_block
|
||||
cmp user_cmd,#"z" wz
|
||||
if_z mov user_cmd,#0
|
||||
' done
|
||||
handle_command_ret
|
||||
ret
|
||||
|
||||
{=== these PASM functions get me in and out of multiblock mode ===}
|
||||
release_DO
|
||||
' we're already out of multiblock mode, so
|
||||
' deselect the card and send out some clocks
|
||||
or outa,maskCS
|
||||
call #in8
|
||||
call #in8
|
||||
' if you are using pull-up resistors, and need all
|
||||
' lines tristated, then uncomment the following line.
|
||||
' for Cluso99
|
||||
'mov dira,#0
|
||||
release_DO_ret
|
||||
ret
|
||||
|
||||
start_mb_read
|
||||
movi block_cmd,#CMD18<<1
|
||||
call #send_SPI_command_fast
|
||||
start_mb_read_ret
|
||||
ret
|
||||
|
||||
stop_mb_read
|
||||
movi block_cmd,#CMD12<<1
|
||||
call #send_SPI_command_fast
|
||||
call #busy_fast
|
||||
stop_mb_read_ret
|
||||
ret
|
||||
|
||||
start_mb_write
|
||||
movi block_cmd,#CMD25<<1
|
||||
call #send_SPI_command_fast
|
||||
start_mb_write_ret
|
||||
ret
|
||||
|
||||
stop_mb_write
|
||||
call #busy_fast
|
||||
' only some cards need these extra clocks
|
||||
mov tmp1,#16
|
||||
:loopity
|
||||
call #in8
|
||||
djnz tmp1,#:loopity
|
||||
' done with hack
|
||||
movi phsa,#$FD<<1
|
||||
call #out8
|
||||
call #in8 ' stuff byte
|
||||
call #busy_fast
|
||||
stop_mb_write_ret
|
||||
ret
|
||||
|
||||
send_SPI_command_fast
|
||||
' make sure we have control of the output lines
|
||||
mov dira,maskAll
|
||||
' make sure the CS line transitions low
|
||||
or outa,maskCS
|
||||
andn outa,maskCS
|
||||
' 8 clocks
|
||||
call #in8
|
||||
' send the data
|
||||
mov phsa,block_cmd ' do which ever block command this is (already in the top 8 bits)
|
||||
call #out8 ' write the byte
|
||||
mov phsa,user_idx ' read in the desired block index
|
||||
shl phsa,adrShift ' this will multiply by 512 (bytes/sector) for MMC and SD
|
||||
call #out8 ' move out the 1st MSB '
|
||||
rol phsa,#1
|
||||
call #out8 ' move out the 1st MSB '
|
||||
rol phsa,#1
|
||||
call #out8 ' move out the 1st MSB '
|
||||
rol phsa,#1
|
||||
call #out8 ' move out the 1st MSB '
|
||||
' bogus CRC value
|
||||
call #in8 ' in8 looks like out8 with $FF
|
||||
' CMD12 requires a stuff byte
|
||||
shr block_cmd,#24
|
||||
cmp block_cmd,#CMD12 wz
|
||||
if_z call #in8 ' 8 clocks
|
||||
' get the response
|
||||
mov tmp1,#9
|
||||
:cmd_response
|
||||
call #in8
|
||||
test readback,#$80 wc,wz
|
||||
if_c djnz tmp1,#:cmd_response
|
||||
if_nz neg user_cmd,readback
|
||||
' done
|
||||
send_SPI_command_fast_ret
|
||||
ret
|
||||
|
||||
|
||||
busy_fast
|
||||
mov tmp1,N_in8_500ms
|
||||
:still_busy
|
||||
call #in8
|
||||
cmp readback,#$FF wz
|
||||
if_nz djnz tmp1,#:still_busy
|
||||
busy_fast_ret
|
||||
ret
|
||||
|
||||
|
||||
out8
|
||||
andn outa,maskDI
|
||||
'movi phsb,#%11_0000000
|
||||
mov phsb,#0
|
||||
movi frqb,#%01_0000000
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
rol phsa,#1
|
||||
mov frqb,#0
|
||||
' don't shift out the final bit...already sent, but be aware
|
||||
' of this when sending consecutive bytes (send_cmd, for e.g.)
|
||||
out8_ret
|
||||
ret
|
||||
|
||||
{
|
||||
in8
|
||||
or outa,maskDI
|
||||
mov ctra,readMode
|
||||
' Start my clock
|
||||
mov frqa,#1<<7
|
||||
mov phsa,#0
|
||||
movi phsb,#%11_0000000
|
||||
movi frqb,#%01_0000000
|
||||
' keep reading in my value, one bit at a time! (Kuneko - "Wh)
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
shr frqa,#1
|
||||
mov frqb,#0 ' stop the clock
|
||||
mov readback,phsa
|
||||
mov frqa,#0
|
||||
mov ctra,writeMode
|
||||
in8_ret
|
||||
ret
|
||||
}
|
||||
in8
|
||||
neg phsa,#1' DI high
|
||||
mov readback,#0
|
||||
' set up my clock, and start it
|
||||
movi phsb,#%011_000000
|
||||
movi frqb,#%001_000000
|
||||
' keep reading in my value
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
rcl readback,#1
|
||||
test maskDO,ina wc
|
||||
mov frqb,#0 ' stop the clock
|
||||
rcl readback,#1
|
||||
mov phsa,#0 'DI low
|
||||
in8_ret
|
||||
ret
|
||||
|
||||
|
||||
' this is called more frequently than 1 Hz, and
|
||||
' is only called when the user command is 0.
|
||||
handle_time
|
||||
mov tmp1,cnt ' get the current timestamp
|
||||
add idle_time,tmp1 ' add the current time to my idle time counter
|
||||
sub idle_time,last_time ' subtract the last time from my idle counter (hence delta)
|
||||
add dtime,tmp1 ' add to my accumulator,
|
||||
sub dtime,last_time ' and subtract the old (adding delta)
|
||||
mov last_time,tmp1 ' update my "last timestamp"
|
||||
rdlong tmp1,#0 ' what is the clock frequency?
|
||||
cmpsub dtime,tmp1 wc ' if I have more than a second in my accumulator
|
||||
addx seconds,#0 ' then add it to "seconds"
|
||||
' this part is to auto-release the card after a timeout
|
||||
cmp idle_time,idle_limit wz,wc
|
||||
if_b jmp #handle_time_ret ' don't clear if we haven't hit the limit
|
||||
mov user_cmd,#"z" ' we can't overdo it, the command handler makes sure
|
||||
neg lastIndexPlus,#1 ' reset the last block index
|
||||
neg user_idx,#1 ' and make this match it
|
||||
call #handle_command ' release the card, but don't mess with the user's request register
|
||||
handle_time_ret
|
||||
ret
|
||||
|
||||
hub_cog_transfer
|
||||
' setup for all 4 passes
|
||||
mov ctrb,clockXferMode
|
||||
mov frqb,#1
|
||||
rdlong buf_ptr,bufAdr
|
||||
mov ops_left,#4
|
||||
movd transfer_long,#speed_buf
|
||||
four_transfer_passes
|
||||
' sync to the Hub RAM access
|
||||
rdlong tmp1,tmp1
|
||||
' how many long to move on this pass? (512 bytes / 4)longs / 4 passes
|
||||
mov tmp1,#(512 / 4 / 4)
|
||||
' get my starting address right (phsb is incremented 1 per clock, so 16 each Hub access)
|
||||
mov phsb,buf_ptr
|
||||
' write the longs, stride 4...low 2 bits of phsb are ignored
|
||||
transfer_long
|
||||
rdlong 0-0,phsb
|
||||
add transfer_long,incDest4
|
||||
djnz tmp1,#transfer_long
|
||||
' go back to where I started, but advanced 1 long
|
||||
sub transfer_long,decDestNminus1
|
||||
' offset my Hub pointer by one long per pass
|
||||
add buf_ptr,#4
|
||||
' do all 4 passes
|
||||
djnz ops_left,#four_transfer_passes
|
||||
' restore the counter mode
|
||||
mov frqb,#0
|
||||
mov phsb,#0
|
||||
mov ctrb,clockLineMode
|
||||
hub_cog_transfer_ret
|
||||
ret
|
||||
|
||||
|
||||
read_single_block
|
||||
' where am I sending the data?
|
||||
movd :store_read_long,#speed_buf
|
||||
mov ops_left,#128
|
||||
' wait until the card is ready
|
||||
mov tmp1,N_in8_500ms
|
||||
:get_resp
|
||||
call #in8
|
||||
cmp readback,#$FE wz
|
||||
if_nz djnz tmp1,#:get_resp
|
||||
if_nz neg user_cmd,#ERR_ASM_NO_READ_TOKEN
|
||||
if_nz jmp #read_single_block_ret
|
||||
' set DI high
|
||||
neg phsa,#1
|
||||
' read the data
|
||||
mov ops_left,#128
|
||||
:read_loop
|
||||
mov tmp1,#4
|
||||
movi phsb,#%011_000000
|
||||
:in_byte
|
||||
' Start my clock
|
||||
movi frqb,#%001_000000
|
||||
' keep reading in my value, BACKWARDS! (Brilliant idea by Tom Rokicki!)
|
||||
test maskDO,ina wc
|
||||
rcl readback,#8
|
||||
test maskDO,ina wc
|
||||
muxc readback,#2
|
||||
test maskDO,ina wc
|
||||
muxc readback,#4
|
||||
test maskDO,ina wc
|
||||
muxc readback,#8
|
||||
test maskDO,ina wc
|
||||
muxc readback,#16
|
||||
test maskDO,ina wc
|
||||
muxc readback,#32
|
||||
test maskDO,ina wc
|
||||
muxc readback,#64
|
||||
test maskDO,ina wc
|
||||
mov frqb,#0 ' stop the clock
|
||||
muxc readback,#128
|
||||
' go back for more
|
||||
djnz tmp1,#:in_byte
|
||||
' make it...NOT backwards [8^)
|
||||
rev readback,#0
|
||||
:store_read_long
|
||||
mov 0-0,readback ' due to some counter weirdness, we need this mov
|
||||
add :store_read_long,const512
|
||||
djnz ops_left,#:read_loop
|
||||
|
||||
' set DI low
|
||||
mov phsa,#0
|
||||
|
||||
' now read 2 trailing bytes (CRC)
|
||||
call #in8 ' out8 is 2x faster than in8
|
||||
call #in8 ' and I'm not using the CRC anyway
|
||||
' give an extra 8 clocks in case we pause for a long time
|
||||
call #in8 ' in8 looks like out8($FF)
|
||||
|
||||
' all done successfully
|
||||
mov idle_time,#0
|
||||
mov user_cmd,#0
|
||||
read_single_block_ret
|
||||
ret
|
||||
|
||||
write_single_block
|
||||
' where am I getting the data? (all 512 bytes / 128 longs of it?)
|
||||
movs :write_loop,#speed_buf
|
||||
' read in 512 bytes (128 longs) from Hub RAM and write it to the card
|
||||
mov ops_left,#128
|
||||
' just hold your horses
|
||||
call #busy_fast
|
||||
' $FC for multiblock, $FE for single block
|
||||
movi phsa,#$FC<<1
|
||||
call #out8
|
||||
mov phsb,#0 ' make sure my clock accumulator is right
|
||||
'movi phsb,#%11_0000000
|
||||
:write_loop
|
||||
' read 4 bytes
|
||||
mov phsa,speed_buf
|
||||
add :write_loop,#1
|
||||
' a long in LE order is DCBA
|
||||
rol phsa,#24 ' move A7 into position, so I can do the swizzled version
|
||||
movi frqb,#%010000000 ' start the clock (remember A7 is already in place)
|
||||
rol phsa,#1 ' A7 is going out, at the end of this instr, A6 is in place
|
||||
rol phsa,#1 ' A5
|
||||
rol phsa,#1 ' A4
|
||||
rol phsa,#1 ' A3
|
||||
rol phsa,#1 ' A2
|
||||
rol phsa,#1 ' A1
|
||||
rol phsa,#1 ' A0
|
||||
rol phsa,#17 ' B7
|
||||
rol phsa,#1 ' B6
|
||||
rol phsa,#1 ' B5
|
||||
rol phsa,#1 ' B4
|
||||
rol phsa,#1 ' B3
|
||||
rol phsa,#1 ' B2
|
||||
rol phsa,#1 ' B1
|
||||
rol phsa,#1 ' B0
|
||||
rol phsa,#17 ' C7
|
||||
rol phsa,#1 ' C6
|
||||
rol phsa,#1 ' C5
|
||||
rol phsa,#1 ' C4
|
||||
rol phsa,#1 ' C3
|
||||
rol phsa,#1 ' C2
|
||||
rol phsa,#1 ' C1
|
||||
rol phsa,#1 ' C0
|
||||
rol phsa,#17 ' D7
|
||||
rol phsa,#1 ' D6
|
||||
rol phsa,#1 ' D5
|
||||
rol phsa,#1 ' D4
|
||||
rol phsa,#1 ' D3
|
||||
rol phsa,#1 ' D2
|
||||
rol phsa,#1 ' D1
|
||||
rol phsa,#1 ' D0 will be in place _after_ this instruction
|
||||
mov frqb,#0 ' shuts the clock off, _after_ this instruction
|
||||
djnz ops_left,#:write_loop
|
||||
' write out my two (bogus, using $FF) CRC bytes
|
||||
call #in8
|
||||
call #in8
|
||||
' now read response (I need this response, so can't spoof using out8)
|
||||
call #in8
|
||||
and readback,#$1F
|
||||
cmp readback,#5 wz
|
||||
if_z mov user_cmd,#0 ' great
|
||||
if_nz neg user_cmd,#ERR_ASM_BLOCK_NOT_WRITTEN ' oops
|
||||
' send out another 8 clocks
|
||||
call #in8
|
||||
' all done
|
||||
mov idle_time,#0
|
||||
write_single_block_ret
|
||||
ret
|
||||
|
||||
|
||||
{=== Assembly Interface Variables ===}
|
||||
pinDO long 0 ' pin is controlled by a counter
|
||||
pinCLK long 0 ' pin is controlled by a counter
|
||||
pinDI long 0 ' pin is controlled by a counter
|
||||
maskDO long 0 ' mask for reading the DO line from the card
|
||||
maskDI long 0 ' mask for setting the pin high while reading
|
||||
maskCS long 0 ' mask = (1<<pin), and is controlled directly
|
||||
maskAll long 0
|
||||
adrShift long 9 ' will be 0 for SDHC, 9 for MMC & SD
|
||||
bufAdr long 0 ' where in Hub RAM is the buffer to copy to/from?
|
||||
sdAdr long 0 ' where on the SD card does it read/write?
|
||||
writeMode long 0 ' the counter setup in NCO single ended, clocking data out on pinDI
|
||||
'clockOutMode long 0 ' the counter setup in NCO single ended, driving the clock line on pinCLK
|
||||
N_in8_500ms long 1_000_000 ' used for timeout checking in PASM
|
||||
'readMode long 0
|
||||
clockLineMode long 0
|
||||
clockXferMode long %11111 << 26
|
||||
const512 long 512
|
||||
const1024 long 1024
|
||||
incDest4 long 4 << 9
|
||||
decDestNminus1 long (512 / 4 - 1) << 9
|
||||
|
||||
{=== Initialized PASM Variables ===}
|
||||
seconds long 0
|
||||
dtime long 0
|
||||
idle_time long 0
|
||||
idle_limit long 0
|
||||
|
||||
{=== Multiblock State Machine ===}
|
||||
lastIndexPlus long -1 ' state handler will check against lastIndexPlus, which will not have been -1
|
||||
lastCommand long 0 ' this will never be the last command.
|
||||
|
||||
{=== Debug Logging Pointers ===}
|
||||
{
|
||||
dbg_ptr long 0
|
||||
dbg_end long 0
|
||||
'}
|
||||
|
||||
{=== Assembly Scratch Variables ===}
|
||||
ops_left res 1 ' used as a counter for bytes, words, longs, whatever (start w/ # byte clocks out)
|
||||
readback res 1 ' all reading from the card goes through here
|
||||
tmp1 res 1 ' this may get used in all subroutines...don't use except in lowest
|
||||
user_request res 1 ' the main command variable, read in from Hub: "r"-read single, "w"-write single
|
||||
user_cmd res 1 ' used internally to handle actual commands to be executed
|
||||
user_idx res 1 ' the pointer to the Hub RAM where the data block is/goes
|
||||
block_cmd res 1 ' one of the SD/MMC command codes, no app-specific allowed
|
||||
buf_ptr res 1 ' moving pointer to the Hub RAM buffer
|
||||
last_time res 1 ' tracking the timestamp
|
||||
|
||||
{{
|
||||
496 longs is my total available space in the cog,
|
||||
and I want 128 longs for eventual use as one 512-
|
||||
byte buffer. This gives me a total of 368 longs
|
||||
to use for umount, and a readblock and writeblock
|
||||
for both Hub RAM and Cog buffers.
|
||||
}}
|
||||
speed_buf res 128 ' 512 bytes to be used for read-ahead / write-behind
|
||||
|
||||
'fit 467
|
||||
FIT 496
|
||||
|
||||
'' MIT LICENSE
|
||||
{{
|
||||
' Permission is hereby granted, free of charge, to any person obtaining
|
||||
' a copy of this software and associated documentation files
|
||||
' (the "Software"), to deal in the Software without restriction,
|
||||
' including without limitation the rights to use, copy, modify, merge,
|
||||
' publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
' and to permit persons to whom the Software is furnished to do so,
|
||||
' subject to the following conditions:
|
||||
'
|
||||
' The above copyright notice and this permission notice shall be included
|
||||
' in all copies or substantial portions of the Software.
|
||||
'
|
||||
' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
' EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
' MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
' IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
' CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
' TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
' SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
}}
|
||||
@@ -7,6 +7,8 @@ Contents
|
||||
|
||||
VDU\vdu.rom: ROM image for VDU onboard EPROM
|
||||
|
||||
Prop\PropIO.eeprom: PropIO firmware for use with RomWBW
|
||||
Prop\PropIO2.eeprom: PropIO V2 firmware for use with RomWBW
|
||||
Prop\ParPortProp.eeprom: ParPortProp firmware for use with RomWBW
|
||||
PropIO\PropIO.eeprom: PropIO firmware for use with RomWBW
|
||||
|
||||
PropIO2\PropIO2.eeprom: PropIO V2 firmware for use with RomWBW
|
||||
|
||||
ParPortProp\ParPortProp.eeprom: ParPortProp firmware for use with RomWBW
|
||||
1
Images/BuildFD.cmd
Normal file
1
Images/BuildFD.cmd
Normal file
@@ -0,0 +1 @@
|
||||
@PowerShell .\BuildFD.ps1 %*
|
||||
@@ -1,6 +1,6 @@
|
||||
$ErrorAction = 'Stop'
|
||||
|
||||
$CpmToolsPath = '../..\Tools\cpmtools'
|
||||
$CpmToolsPath = '..\Tools\cpmtools'
|
||||
|
||||
$env:PATH = $CpmToolsPath + ';' + $env:PATH
|
||||
|
||||
@@ -16,9 +16,9 @@ for ($Dsk=0; $Dsk -lt 2; $Dsk++)
|
||||
copy Blank.tmp fd${Dsk}.img
|
||||
for ($Usr=0; $Usr -lt 16; $Usr++)
|
||||
{
|
||||
if (Test-Path ("fd${Dsk}/u${Usr}/*"))
|
||||
if (Test-Path ("Source/fd${Dsk}/u${Usr}/*"))
|
||||
{
|
||||
$Cmd = "cpmcp -f wbw_fd144 fd${Dsk}.img fd${Dsk}/u${Usr}/*.* ${Usr}:"
|
||||
$Cmd = "cpmcp -f wbw_fd144 fd${Dsk}.img Source/fd${Dsk}/u${Usr}/*.* ${Usr}:"
|
||||
$Cmd
|
||||
Invoke-Expression $Cmd
|
||||
}
|
||||
@@ -26,7 +26,7 @@ for ($Dsk=0; $Dsk -lt 2; $Dsk++)
|
||||
}
|
||||
|
||||
"Moving images into output directory..."
|
||||
&$env:COMSPEC /c move fd*.img ..\..\Binary\
|
||||
&$env:COMSPEC /c move fd*.img ..\Output\
|
||||
|
||||
Remove-Item *.tmp
|
||||
|
||||
1
Images/BuildHD.cmd
Normal file
1
Images/BuildHD.cmd
Normal file
@@ -0,0 +1 @@
|
||||
@PowerShell .\BuildHD.ps1 %*
|
||||
@@ -1,6 +1,6 @@
|
||||
$ErrorAction = 'Stop'
|
||||
|
||||
$CpmToolsPath = '../../Tools/cpmtools'
|
||||
$CpmToolsPath = '../Tools/cpmtools'
|
||||
|
||||
$env:PATH = $CpmToolsPath + ';' + $env:PATH
|
||||
|
||||
@@ -19,9 +19,9 @@ for ($Dsk=0; $Dsk -lt 2; $Dsk++)
|
||||
copy Blank.tmp slice${Slice}.tmp
|
||||
for ($Usr=0; $Usr -lt 16; $Usr++)
|
||||
{
|
||||
if (Test-Path ("hd${Dsk}/s${Slice}/u${Usr}/*"))
|
||||
if (Test-Path ("Source/hd${Dsk}/s${Slice}/u${Usr}/*"))
|
||||
{
|
||||
$Cmd = "cpmcp -f wbw_hd0 slice${Slice}.tmp hd${Dsk}/s${Slice}/u${Usr}/*.* ${Usr}:"
|
||||
$Cmd = "cpmcp -f wbw_hd0 slice${Slice}.tmp Source/hd${Dsk}/s${Slice}/u${Usr}/*.* ${Usr}:"
|
||||
$Cmd
|
||||
Invoke-Expression $Cmd
|
||||
}
|
||||
@@ -29,7 +29,7 @@ for ($Dsk=0; $Dsk -lt 2; $Dsk++)
|
||||
}
|
||||
|
||||
"Combining slices into final disk image hd${Dsk}..."
|
||||
&$env:COMSPEC /c copy /b slice*.tmp ..\..\Binary\hd${Dsk}.img
|
||||
&$env:COMSPEC /c copy /b slice*.tmp ..\Output\hd${Dsk}.img
|
||||
|
||||
Remove-Item slice*.tmp
|
||||
}
|
||||
2
Images/Clean.cmd
Normal file
2
Images/Clean.cmd
Normal file
@@ -0,0 +1,2 @@
|
||||
@echo off
|
||||
if exist *.tmp del *.tmp /Q
|
||||
29
Images/FixPowerShell.cmd
Normal file
29
Images/FixPowerShell.cmd
Normal file
@@ -0,0 +1,29 @@
|
||||
@echo off
|
||||
echo By default, PowerShell is configured to block the
|
||||
echo execution of unsigned scripts on your local system.
|
||||
echo This command file will attempt to modify your
|
||||
echo PowerShell ExecutionPolicy to "RemoteSigned"
|
||||
echo which means that local scripts can be run without
|
||||
echo being signed. This is required to use the RomWBW
|
||||
echo build process.
|
||||
echo.
|
||||
PowerShell -command Write-Host "Your PowerShell ExecutionPolicy is currently set to: `'(Get-ExecutionPolicy)`'"
|
||||
echo.
|
||||
echo In order to modify the ExecutionPolicy, this command
|
||||
echo file *MUST* be run with administrator privileges.
|
||||
echo Generally, this means you want to right-click the
|
||||
echo command file called FixPowerShell.cmd and choose
|
||||
echo "Run as Administrator". If you attempt to continue
|
||||
echo without administrator privileges, the modification
|
||||
echo will fail with an error message, but no harm is done.
|
||||
echo.
|
||||
choice /m "Do you want to proceed"
|
||||
if errorlevel 2 goto :eof
|
||||
echo.
|
||||
echo Attempting to change Execution Policy...
|
||||
echo.
|
||||
PowerShell Set-ExecutionPolicy RemoteSigned
|
||||
echo.
|
||||
PowerShell -command Write-Host "Your new PowerShell ExecutionPolicy is now set to: `'(Get-ExecutionPolicy)`'"
|
||||
echo.
|
||||
pause
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user