commit 5295ea4d583a4b09a273b34acc0694fb8072247d
Author: Gerd Beuster <gerd@frombelow.net>
Date: Sat, 29 Oct 2022 16:35:03 +0200
Initial version
Diffstat:
33 files changed, 5301 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,9 @@
+**.bin
+**.out
+**.vcd
+src/tools/*.dat
+src/roms/*.dat
+src/roms/*.s
+src/tools/opcodes.pl
+case/dst/stl/*.stl
+case/dst/svg/*.svg
diff --git a/.gitmodules b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "case/lasercut"]
+ path = case/lasercut
+ url = https://github.com/bmsleight/lasercut.git
diff --git a/COPYING b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU 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 <https://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
+<https://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
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/README b/README
@@ -0,0 +1 @@
+See doc/README.md
diff --git a/board/circuit.fzz b/board/circuit.fzz
Binary files differ.
diff --git a/case/Makefile b/case/Makefile
@@ -0,0 +1,23 @@
+SVG=acryl_top_plate.svg matrix_back.svg control_panel.svg \
+ box_left_side.svg box_right_side.svg box_front.svg box_back.svg \
+ bottom_screw_mount_front.svg bottom_screw_mount_back.svg box_bottom.svg
+STL=circuit_board_holder.stl icestick_base.stl icestick_strap.stl
+
+DST_STL=./dst/stl
+DST_SVG=./dst/svg
+
+ALL_TARGETS=$(addprefix $(DST_STL)/, $(STL)) $(addprefix $(DST_SVG)/, $(SVG))
+
+
+all: $(SVG) $(STL)
+
+%.svg: case.scad
+ openscad -o $(DST_SVG)/$@ -D "mode=\"`basename -s .svg $@`\"" ./case.scad
+
+%.stl: case.scad
+ openscad -o $(DST_STL)/$@ -D "mode=\"`basename -s .stl $@`\"" ./case.scad
+
+clean:
+ rm -f $(DST_SVG)/*.svg $(DST_STL)/*.gcode $(DST_STL)/*.g3drem $(DST_STL)/*.stl
+
+.phony: all clean
diff --git a/case/case.scad b/case/case.scad
@@ -0,0 +1,542 @@
+/*
+ * Copyright 2022 Gerd Beuster (gerd@frombelow.net). This design is
+ * free under the GNU GPL v3 license or any later version. See
+ * COPYING in the root directory for details.
+ */
+
+include <lasercut/lasercut.scad>
+
+$fn=30;
+
+// Thickness of boards
+board_thickness = 4;
+// Width and depth of LED matrix
+matrix_side = 160;
+matrix_height = 2;
+// Additional border of back plate of LED matrix.
+matrix_back_border = 20;
+matrix_back_side = matrix_side + matrix_back_border*2;
+// Distance from side of LED matrix back plate to screw holes
+matrix_back_screw_holes_distance = matrix_back_border / 2;
+// Diameter of holes to screw matrix back screw to acryl plate
+matrix_back_screw_hole = 4;
+// Screw holes for bottom plate are somewhat larger, because
+// we use claw nuts
+bottom_screw_hole = 5;
+// Depth of control panel
+panel_depth = 60;
+// Diameter of holes for switches
+switch = 6.6;
+// Diameter of holes for dial
+dial = 6.6;
+// Diameter of holes for push buttons
+button = 7.2;
+// Hole for USB connector
+usb_width = 18;
+usb_height = 13;
+// Diameter of hole for power supply
+power_supply = 8;
+
+box_height = 60;
+// Distance from floor to bottom panel
+bottom_panel_height = 5;
+
+// Circuit board
+circuit_board_width = 145;
+circuit_board_depth = 65;
+circuit_board_height = 1;
+// Icestick
+icestick_base_width = 80;
+icestick_base_depth = 25;
+icestick_base_height = 4;
+icestick_strap_width = 20;
+icestick_strap_depth = 60;
+icestick_strap_height = 2;
+
+module matrix() {
+ translate([matrix_back_border,
+ matrix_back_border,
+ board_thickness])
+ cube([matrix_side, matrix_side, 2]);
+}
+
+// The LED matrix is fit in between the acryl plate on top
+// and the back plate below. These three plates are hold
+// together by screws. The acryl plate and the back plate (but
+// not the LED matrix itself) need screw holes.
+module acryl_plate_holder_screw_holes() {
+ // Screw holes in four corners
+ union () {
+ translate([matrix_back_border/2,
+ matrix_back_border/2,
+ 0])
+ cylinder(h=board_thickness, d=matrix_back_screw_hole,
+ center=false);
+ translate([matrix_back_side-matrix_back_border/2,
+ matrix_back_border/2,
+ 0])
+ cylinder(h=board_thickness, d=matrix_back_screw_hole,
+ center=false);
+ translate([matrix_back_border/2,
+ matrix_back_side-matrix_back_border/2,
+ 0])
+ cylinder(h=board_thickness, d=matrix_back_screw_hole,
+ center=false);
+ translate([matrix_back_side-matrix_back_border/2,
+ matrix_back_side-matrix_back_border/2,
+ 0])
+ cylinder(h=board_thickness, d=matrix_back_screw_hole,
+ center=false);
+ }
+}
+
+module matrix_back() {
+ difference() {
+ lasercutoutSquare(thickness=board_thickness,
+ x=matrix_back_side, y=matrix_back_side,
+ finger_joints=[
+ [UP, 0, 4],
+ [LEFT, 1, 4],
+ [RIGHT, 0, 4]
+ ]);
+ // Cutout for power supply
+ { translate([matrix_back_side-matrix_back_border*2-25,
+ matrix_back_side-matrix_back_border*2-30, 0])
+ cube([15, 20, board_thickness]);
+ }
+ acryl_plate_holder_screw_holes();
+ }
+}
+
+module acryl_top_plate() {
+ translate([0, 0, matrix_height+board_thickness]) {
+ difference () {
+ cube([matrix_back_side, matrix_back_side, board_thickness]);
+ acryl_plate_holder_screw_holes();
+ }
+ }
+ }
+
+module box_left_side() {
+ difference () {
+ translate([-board_thickness,
+ -panel_depth,
+ board_thickness*2+matrix_height]) {
+ rotate([0, 90, 0]) {
+ lasercutoutSquare(thickness=board_thickness,
+ x=box_height,
+ y=matrix_side+matrix_back_border*2+panel_depth,
+ finger_joints=[
+ [UP, 1, 2],
+ [DOWN, 0, 2],
+ ]);
+ }
+ }
+ union () {
+ // Cutout for fingers
+ matrix_back();
+ control_panel();
+ bottom_screw_mount_front();
+ bottom_screw_mount_back();
+ }
+ }
+}
+
+module box_right_side() {
+ difference () {
+ translate([matrix_back_side,
+ -panel_depth,
+ board_thickness*2+matrix_height]) {
+ rotate([0, 90, 0]) {
+ lasercutoutSquare(thickness=board_thickness,
+ x=box_height,
+ y=matrix_side+matrix_back_border*2+panel_depth,
+ finger_joints=[
+ [UP, 1, 2],
+ [DOWN, 0, 2],
+ ]);
+ }
+ }
+ union () {
+ // Cutout for fingers
+ matrix_back();
+ control_panel();
+ bottom_screw_mount_front();
+ bottom_screw_mount_back();
+ // Cutout for USB connector
+ translate([matrix_back_side,
+ circuit_board_depth+usb_width*2,
+ -box_height+usb_height+bottom_panel_height+1]) {
+ cube([board_thickness, usb_width, usb_height]);
+ }
+ }
+ }
+}
+
+module box_front() {
+ difference () {
+ translate([-board_thickness,
+ -panel_depth,
+ board_thickness*2+matrix_height]) {
+ rotate([90, 90, 0]) {
+ lasercutoutSquare(thickness=board_thickness,
+ x=box_height,
+ y=matrix_back_side+board_thickness*2,
+ finger_joints=[
+ ]);
+ }
+ }
+ // Cutout for fingers
+ union () {
+ box_left_side();
+ box_right_side();
+ control_panel();
+ bottom_screw_mount_front();
+ }
+ }
+}
+
+module box_back() {
+ difference () {
+ translate([-board_thickness,
+ matrix_side+matrix_back_border*2+board_thickness,
+ board_thickness*2+matrix_height]) {
+ rotate([90, 90, 0]) {
+ lasercutoutSquare(thickness=board_thickness,
+ x=box_height,
+ y=matrix_back_side+board_thickness*2,
+ finger_joints=[
+ ]);
+ }
+ }
+ // Cutout for fingers
+ union () {
+ box_left_side();
+ box_right_side();
+ matrix_back();
+ bottom_screw_mount_back();
+ }
+ }
+}
+
+
+module control_panel() {
+ translate([0, -panel_depth, matrix_height+board_thickness]) {
+ difference() {
+ lasercutoutSquare(thickness=board_thickness,
+ x=matrix_back_side, y=panel_depth,
+ finger_joints=[
+ [LEFT, 0, 2],
+ [RIGHT, 1, 2],
+ [DOWN, 0, 4]
+ ]);
+ // Reset Button
+ translate([matrix_back_side/10*(1-.2),
+ panel_depth/4*(3.2-.2),
+ 0 ])
+ cylinder(h=board_thickness, d=button,
+ center=false);
+ // Speed dial
+ translate([matrix_back_side/10*(2-.2),
+ panel_depth/4*(3.2-.2),
+ 0 ])
+ cylinder(h=board_thickness, d=dial,
+ center=false);
+ // Run/Single/Enter switch
+ translate([matrix_back_side/10*(3-.2),
+ panel_depth/4*(3.2-.2),
+ 0 ])
+ cylinder(h=board_thickness, d=switch,
+ center=false);
+ // Step Button
+ translate([matrix_back_side/10*(4-.2),
+ panel_depth/4*(3.2-.2),
+ 0 ])
+ cylinder(h=board_thickness, d=button,
+ center=false);
+ // Skip Button
+ translate([matrix_back_side/10*(5-.2),
+ panel_depth/4*(3.2-.2),
+ 0 ])
+ cylinder(h=board_thickness, d=button,
+ center=false);
+ // Data switches
+ for(p = [2-.2:9-.2]) {
+ translate([matrix_back_side/10*p,
+ panel_depth/4*(.8+.2),
+ 0 ]) {
+ cylinder(h=board_thickness, d=switch,
+ center=false);
+ }
+ }
+ }
+ }
+}
+
+
+module bottom_screw_mount_front() {
+ translate([0, -panel_depth, -box_height+board_thickness*3.5+bottom_panel_height]) {
+ difference() {
+ lasercutoutSquare(thickness=board_thickness,
+ x=matrix_back_side, y=matrix_back_border,
+ finger_joints=[
+ [DOWN, 0, 4],
+ [LEFT, 1, 2],
+ [RIGHT, 0, 2]
+ ]);
+ translate([matrix_back_border/2, matrix_back_border/2, 0])
+ cylinder(h=board_thickness, d=bottom_screw_hole,
+ center=false);
+ translate([matrix_back_side-matrix_back_border/2, matrix_back_border/2, 0])
+ cylinder(h=board_thickness, d=bottom_screw_hole,
+ center=false);
+ }
+ }
+
+}
+
+module bottom_screw_mount_back() {
+ translate([0, matrix_side+matrix_back_border, -box_height+board_thickness*3.5+bottom_panel_height]) {
+ difference() {
+ lasercutoutSquare(thickness=board_thickness,
+ x=matrix_back_side, y=matrix_back_border,
+ finger_joints=[
+ [UP, 0, 4],
+ [LEFT, 1, 2],
+ [RIGHT, 0, 2]
+ ]);
+ translate([matrix_back_border/2, matrix_back_border/2, 0])
+ cylinder(h=board_thickness, d=bottom_screw_hole,
+ center=false);
+ translate([matrix_back_side-matrix_back_border/2, matrix_back_border/2, 0])
+ cylinder(h=board_thickness, d=bottom_screw_hole,
+ center=false);
+ }
+ }
+
+}
+
+module box_bottom() {
+ difference() {
+ translate([0, -panel_depth, -box_height+2.5*board_thickness+bottom_panel_height]) {
+ difference() {
+ // Plate
+ cube([matrix_back_side, matrix_side+panel_depth+matrix_back_border*2, board_thickness]);
+ // Screw holes for bottom
+ translate([matrix_back_border/2, matrix_back_border/2, 0])
+ cylinder(h=board_thickness, d=bottom_screw_hole,
+ center=false);
+ translate([matrix_back_side-matrix_back_border/2, matrix_back_border/2, 0])
+ cylinder(h=board_thickness, d=bottom_screw_hole,
+ center=false);
+ translate([matrix_back_border/2,
+ matrix_side+panel_depth+matrix_back_border*1.5, 0])
+ cylinder(h=board_thickness, d=bottom_screw_hole,
+ center=false);
+ translate([matrix_back_side-matrix_back_border/2,
+ matrix_side+panel_depth+matrix_back_border*1.5, 0])
+ cylinder(h=board_thickness, d=bottom_screw_hole,
+ center=false);
+ }
+ }
+ // Screw holes for circuit holder and icestick
+ circuit_board_holder_mount_holes();
+ icestick_strap_mount_holes();
+ }
+}
+
+module circuit_board_vitamin() {
+ translate([(matrix_back_side-circuit_board_width)/2,
+ 0,
+ -box_height+bottom_panel_height+board_thickness*3+matrix_height]) {
+ cube([circuit_board_width, circuit_board_depth, circuit_board_height]);
+ }
+}
+
+module circuit_board_holder_mount_holes() {
+ translate([(matrix_back_side-circuit_board_width)/2-10,
+ -10,
+ -box_height+bottom_panel_height+board_thickness*3+matrix_height]) {
+ translate([10, 5, -board_thickness]) {
+ cylinder(h=2+board_thickness, d=matrix_back_screw_hole, center=false);
+ }
+ translate([10, circuit_board_depth+15, -board_thickness]) {
+ cylinder(h=2+board_thickness, d=matrix_back_screw_hole, center=false);
+ }
+ }
+ translate([(matrix_back_side+circuit_board_width)/2-10,
+ -10,
+ -box_height+bottom_panel_height+board_thickness*3+matrix_height]) {
+ translate([10, 5, -board_thickness]) {
+ cylinder(h=2+board_thickness, d=matrix_back_screw_hole, center=false);
+ }
+ translate([10, circuit_board_depth+15, -board_thickness]) {
+ cylinder(h=2+board_thickness, d=matrix_back_screw_hole, center=false);
+ }
+ }
+}
+
+module circuit_board_holder() {
+ difference() {
+ // From left and right holders ...
+ union() {
+ // Left holder
+ translate([(matrix_back_side-circuit_board_width)/2-10,
+ -10,
+ -box_height+bottom_panel_height+board_thickness*3+matrix_height]) {
+ cube([20, circuit_board_depth+20, 2]);
+ }
+ // Right holder
+ translate([(matrix_back_side+circuit_board_width)/2-10,
+ -10,
+ -box_height+bottom_panel_height+board_thickness*3+matrix_height]) {
+ cube([20, circuit_board_depth+20, 2]);
+ }
+ }
+ union () {
+ // ... remove mount holes ...
+ circuit_board_holder_mount_holes();
+ // ... remove the edges of the circuit board
+ circuit_board_vitamin();
+ }
+ }
+}
+
+module icestick_base() {
+ translate([matrix_back_side-icestick_base_width-20,
+ circuit_board_depth+usb_width*2,
+ -box_height+bottom_panel_height+board_thickness*3+matrix_height]) {
+ cube([icestick_base_width, usb_width, icestick_base_height]);
+ }
+};
+
+module icestick_strap() {
+ difference() {
+ translate([matrix_back_side-icestick_strap_width*2,
+ circuit_board_depth+usb_width*2.5-icestick_strap_depth/2,
+ -box_height+bottom_panel_height+board_thickness*3+matrix_height]) {
+ cube([icestick_strap_width, icestick_strap_depth, icestick_strap_height]);
+ }
+ icestick_strap_mount_holes();
+ }
+};
+
+module icestick_strap_mount_holes() {
+ translate([matrix_back_side-icestick_strap_width*1.5,
+ circuit_board_depth+usb_width*2.5-icestick_strap_depth/2.5,
+ -box_height+bottom_panel_height+board_thickness*2+matrix_height]) {
+ cylinder(h=board_thickness+icestick_strap_height, d=matrix_back_screw_hole, center=false);
+ }
+ translate([matrix_back_side-icestick_strap_width*1.5,
+ circuit_board_depth+usb_width*2.5+icestick_strap_depth/2.5,
+ -box_height+bottom_panel_height+board_thickness*2+matrix_height]) {
+ cylinder(h=board_thickness+icestick_strap_height, d=matrix_back_screw_hole, center=false);
+ }
+};
+
+mode = "all";
+// mode = "acryl_top_plate";
+// mode = "matrix";
+// mode = "matrix_back";
+// mode = "control_panel";
+// mode = "box_left_side";
+// mode = "box_right_side";
+// mode = "box_front";
+// mode = "box_back";
+// mode = "bottom_screw_mount_front";
+// mode = "bottom_screw_mount_back";
+// mode = "box_bottom";
+// mode = "circuit_board_holder";
+// mode = "icestick_base";
+// mode = "icestick_strap";
+
+
+if (mode == "all") {
+ acryl_top_plate();
+ matrix();
+ matrix_back();
+ control_panel();
+ box_left_side();
+ box_right_side();
+ box_front();
+ box_back();
+ bottom_screw_mount_front();
+ bottom_screw_mount_back();
+ box_bottom();
+ circuit_board_holder();
+ icestick_base();
+ icestick_strap();
+}
+
+if (mode == "acryl_top_plate") {
+ projection()
+ acryl_top_plate();
+}
+if (mode == "matrix") {
+ projection()
+ matrix();
+}
+if (mode == "matrix_back") {
+ projection()
+ matrix_back();
+}
+if (mode == "control_panel") {
+ projection()
+ control_panel();
+}
+if (mode == "box_left_side") {
+ projection()
+ rotate([0, 90, 0])
+ box_left_side();
+}
+if (mode == "box_right_side") {
+ projection()
+ rotate([0, -90, 0])
+ box_right_side();
+}
+if (mode == "box_front") {
+ projection()
+ rotate([-90, 0, 0])
+ box_front();
+}
+if (mode == "box_back") {
+ projection()
+ rotate([90, 0, 0])
+ box_back();
+}
+if (mode == "bottom_screw_mount_front") {
+ projection()
+ bottom_screw_mount_front();
+}
+if (mode == "bottom_screw_mount_back") {
+ projection()
+ bottom_screw_mount_back();
+}
+if (mode == "box_bottom") {
+ projection()
+ rotate([180, 0, 0])
+ box_bottom();
+}
+if (mode == "circuit_board_holder") {
+ circuit_board_holder();
+}
+if (mode == "icestick_base") {
+ icestick_base();
+}
+if (mode == "icestick_strap") {
+ icestick_strap();
+}
+
+// Acryl top plates with markings for LED matrix. We use this as a
+// template to add labels to the top plate.
+/*
+projection()
+difference() {
+ acryl_top_plate();
+ union() {
+ matrix();
+ translate([0,0,2]) matrix();
+ translate([0,0,4]) matrix();
+ }
+}
+*/
diff --git a/case/dst/labeled/box_right_side/box_right_side.svg b/case/dst/labeled/box_right_side/box_right_side.svg
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="268mm"
+ height="60mm"
+ viewBox="-10 -204 268 60"
+ version="1.1"
+ id="svg88"
+ sodipodi:docname="box_right_side.svg"
+ inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata94">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>OpenSCAD Model</dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs92" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1502"
+ inkscape:window-height="938"
+ id="namedview90"
+ showgrid="false"
+ inkscape:zoom="0.62618858"
+ inkscape:cx="456.73142"
+ inkscape:cy="217.98545"
+ inkscape:window-x="1970"
+ inkscape:window-y="27"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="layer2"
+ inkscape:pagecheckerboard="0"
+ inkscape:document-units="mm" />
+ <title
+ id="title84">OpenSCAD Model</title>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="Cut"
+ style="display:inline">
+ <path
+ d="m -5.714743,-188.70912 v 15 h -4 v 15 h 4 v 2 h 5 v 4 h -5 v 9 H 254.28526 v -15 h 4 v -15 h -4 v -15 h 4 v -15 H 54.285257 v 4 h -15 v -4 h -15 v 4 h -15 v -4 h -19 v 15 z m 250.000003,32 h 5 v 4 h -5 z m -10,0 h 5 v 4 h -5 z m -30,-41 h 25 v 4 h -25 z m -50,0 h 25 v 4 h -25 z m 1,32 h 18 v 13 h -18 z m -51,-32 h 25 v 4 h -25 z m -50.000003,0 h 25 v 4 h -25 z m -50,41 h 5 v 4 h -5 z"
+ stroke="#000000"
+ fill="#d3d3d3"
+ stroke-width="0.5"
+ id="path601" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Labels"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;line-height:58.1025px;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="14.26072"
+ y="-152.9451"
+ id="text351"><tspan
+ sodipodi:role="line"
+ id="tspan349"
+ x="14.26072"
+ y="-152.9451"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">© 2022 Gerd Beuster</tspan></text>
+ </g>
+</svg>
diff --git a/case/dst/labeled/box_right_side/polarity/polarity.svg b/case/dst/labeled/box_right_side/polarity/polarity.svg
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="210mm"
+ height="297mm"
+ viewBox="0 0 210 297"
+ version="1.1"
+ id="svg8"
+ inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
+ sodipodi:docname="polarity.svg">
+ <defs
+ id="defs2" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="5.6"
+ inkscape:cx="298.76497"
+ inkscape:cy="995.68575"
+ inkscape:document-units="mm"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:window-width="1920"
+ inkscape:window-height="1141"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:snap-to-guides="false"
+ inkscape:snap-grids="false"
+ inkscape:snap-others="false"
+ inkscape:snap-nodes="false">
+ <sodipodi:guide
+ position="76.776414,257.85063"
+ orientation="0,1"
+ id="guide819"
+ inkscape:locked="false" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:58.10250092px;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="61.799107"
+ y="37.89732"
+ id="text817"><tspan
+ sodipodi:role="line"
+ id="tspan815"
+ x="61.799107"
+ y="37.89732"
+ style="stroke-width:0.26458332px">- +</tspan></text>
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="path823"
+ sodipodi:type="arc"
+ sodipodi:cx="62.637741"
+ sodipodi:cy="36.657082"
+ sodipodi:rx="2.279669"
+ sodipodi:ry="2.279669"
+ sodipodi:start="6.1609599"
+ sodipodi:end="6.1600349"
+ sodipodi:open="true"
+ d="m 64.900403,36.379141 a 2.279669,2.279669 0 0 1 -1.984198,2.540538 2.279669,2.279669 0 0 1 -2.540997,-1.983611 2.279669,2.279669 0 0 1 1.983023,-2.541455 2.279669,2.279669 0 0 1 2.541914,1.982436" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="path823-1"
+ sodipodi:type="arc"
+ sodipodi:cx="79.871094"
+ sodipodi:cy="36.686977"
+ sodipodi:rx="2.279669"
+ sodipodi:ry="2.279669"
+ sodipodi:start="6.1609599"
+ sodipodi:end="6.1600349"
+ sodipodi:open="true"
+ d="m 82.133756,36.409037 a 2.279669,2.279669 0 0 1 -1.984199,2.540538 2.279669,2.279669 0 0 1 -2.540997,-1.983611 2.279669,2.279669 0 0 1 1.983024,-2.541455 2.279669,2.279669 0 0 1 2.541914,1.982435" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.5;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="path823-2"
+ sodipodi:type="arc"
+ sodipodi:cx="71.661575"
+ sodipodi:cy="36.670086"
+ sodipodi:rx="2.279669"
+ sodipodi:ry="2.279669"
+ sodipodi:start="6.1609599"
+ sodipodi:end="6.1600349"
+ sodipodi:open="true"
+ d="m 73.924238,36.392146 a 2.279669,2.279669 0 0 1 -1.984199,2.540538 2.279669,2.279669 0 0 1 -2.540997,-1.983611 2.279669,2.279669 0 0 1 1.983023,-2.541456 2.279669,2.279669 0 0 1 2.541914,1.982436" />
+ <rect
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.1;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="rect855"
+ width="2.1548605"
+ height="5.6794777"
+ x="72.663902"
+ y="33.856441" />
+ <path
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.02973792;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ id="path823-8"
+ sodipodi:type="arc"
+ sodipodi:cx="71.544708"
+ sodipodi:cy="36.579254"
+ sodipodi:rx="0.67792612"
+ sodipodi:ry="0.67792612"
+ sodipodi:start="6.1609599"
+ sodipodi:end="6.1600349"
+ sodipodi:open="true"
+ d="m 72.217577,36.496601 a 0.67792612,0.67792612 0 0 1 -0.59006,0.755503 0.67792612,0.67792612 0 0 1 -0.755639,-0.589885 0.67792612,0.67792612 0 0 1 0.58971,-0.755776 0.67792612,0.67792612 0 0 1 0.755912,0.589535" />
+ <path
+ style="opacity:1;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.45176813;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 77.614899,36.595957 H 71.628232"
+ id="path891"
+ inkscape:connector-curvature="0" />
+ <path
+ style="opacity:1;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 69.402894,36.605179 h -4.50182"
+ id="path891-6"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:58.10250092px;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="60.661377"
+ y="43.404289"
+ id="text910"><tspan
+ sodipodi:role="line"
+ id="tspan908"
+ x="60.661377"
+ y="43.404289"
+ style="stroke-width:0.26458332px">3.3 – 15 V</tspan></text>
+ </g>
+</svg>
diff --git a/case/dst/labeled/control_panel/control_panel.svg b/case/dst/labeled/control_panel/control_panel.svg
@@ -0,0 +1,332 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="208mm"
+ height="64mm"
+ viewBox="-4 0 208 64"
+ version="1.1"
+ id="svg6"
+ sodipodi:docname="control_panel.svg"
+ inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata12">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>OpenSCAD Model</dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs10" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1680"
+ inkscape:window-height="986"
+ id="namedview8"
+ showgrid="true"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:zoom="1.352795"
+ inkscape:cx="639.41692"
+ inkscape:cy="212.52297"
+ inkscape:window-x="1920"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ inkscape:pagecheckerboard="0"
+ inkscape:document-units="mm">
+ <inkscape:grid
+ type="xygrid"
+ id="grid822" />
+ <sodipodi:guide
+ position="194.99792,45.772915"
+ orientation="1,0"
+ id="guide80"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="29.104166,56.740934"
+ orientation="0,1"
+ id="guide897"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="79.374999,40.882247"
+ orientation="0,1"
+ id="guide899"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="42.333333,8.4374999"
+ orientation="0,-1"
+ id="guide58"
+ inkscape:locked="false" />
+ </sodipodi:namedview>
+ <title
+ id="title2">OpenSCAD Model</title>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Cuts"
+ style="display:inline">
+ <path
+ d="m 25.11332,60.188897 h 24.999997 v 4 h 25 v -4 h 25.000003 v 4 h 25 v -4 h 25 v 4 h 25 v -4 h 25 v -15 h 4 v -15 h -4 V 15.1889 h 4 v -15 H -3.8866803 v 15 H 0.11331967 V 30.188897 H -3.8866803 v 15 h 3.99999997 v 19 H 25.11332 Z M 75.737017,18.7692 l -0.7362,-0.1565 -0.6875,-0.3061 -0.6089,-0.4424 -0.5036,-0.5593 -0.3763,-0.6518 -0.2325,-0.7157 -0.0787,-0.7485 0.0787,-0.7485 0.2325,-0.7158 0.3763,-0.6517 0.5036,-0.5593 0.6089,-0.4424 0.6875,-0.3061 0.7362,-0.1565 h 0.7526 l 0.7362,0.1565 0.6875,0.3061 0.6089,0.4424 0.5036,0.5593 0.3763,0.6517 0.2325,0.7158 0.0787,0.7485 -0.0787,0.7485 -0.2325,0.7157 -0.3763,0.6518 -0.5036,0.5593 -0.6089,0.4424 -0.6875,0.3061 -0.7362,0.1565 z m 20,0 -0.7362,-0.1565 -0.6875,-0.3061 -0.6089,-0.4424 -0.5036,-0.5593 -0.3763,-0.6518 -0.2325,-0.7157 -0.0787,-0.7485 0.0787,-0.7485 0.2325,-0.7158 0.3763,-0.6517 0.5036,-0.5593 0.6089,-0.4424 0.6875,-0.3061 0.7362,-0.1565 h 0.7526 l 0.7362,0.1565 0.6875,0.3061 0.6089,0.4424 0.5036,0.5593 0.3763,0.6517 0.2325,0.7158 0.0787,0.7485 -0.0787,0.7485 -0.2325,0.7157 -0.3763,0.6518 -0.5036,0.5593 -0.6089,0.4424 -0.6875,0.3061 -0.7362,0.1565 z m -42.2935,-1.6406 -0.3449,-0.5975 -0.2132,-0.6561 -0.0721,-0.6861 0.0721,-0.6861 0.2132,-0.6561 0.3449,-0.5975 0.4617,-0.5127 0.5581,-0.4055 0.6302,-0.2806 0.6748,-0.1434 h 0.6899 l 0.6748,0.1434 0.6303,0.2806 0.5581,0.4055 0.4617,0.5127 0.3449,0.5975 0.2132,0.6561 0.0721,0.6861 -0.0721,0.6861 -0.2132,0.6561 -0.3449,0.5975 -0.4617,0.5127 -0.5581,0.4055 -0.6303,0.2806 -0.6748,0.1434 h -0.6899 l -0.6748,-0.1434 -0.6302,-0.2806 -0.5581,-0.4055 z m 102.324803,31.342197 -0.675,-0.1434 -0.63,-0.2806 -0.558,-0.4055 -0.462,-0.5127 -0.345,-0.5975 -0.213,-0.6561 -0.072,-0.6861 0.072,-0.6861 0.213,-0.6561 0.345,-0.5975 0.462,-0.5127 0.558,-0.4055 0.63,-0.2806 0.675,-0.1434 h 0.69 l 0.675,0.1434 0.63,0.2806 0.558,0.4055 0.462,0.5127 0.345,0.5975 0.213,0.6561 0.072,0.6861 -0.072,0.6861 -0.213,0.6561 -0.345,0.5975 -0.462,0.5127 -0.558,0.4055 -0.63,0.2806 -0.675,0.1434 z m -20,0 -0.675,-0.1434 -0.63,-0.2806 -0.558,-0.4055 -0.462,-0.5127 -0.345,-0.5975 -0.213,-0.6561 -0.072,-0.6861 0.072,-0.6861 0.213,-0.6561 0.345,-0.5975 0.462,-0.5127 0.558,-0.4055 0.63,-0.2806 0.675,-0.1434 h 0.69 l 0.675,0.1434 0.63,0.2806 0.558,0.4055 0.462,0.5127 0.345,0.5975 0.213,0.6561 0.072,0.6861 -0.072,0.6861 -0.213,0.6561 -0.345,0.5975 -0.462,0.5127 -0.558,0.4055 -0.63,0.2806 -0.675,0.1434 z m -20,0 -0.675,-0.1434 -0.63,-0.2806 -0.558,-0.4055 -0.462,-0.5127 -0.345,-0.5975 -0.213,-0.6561 -0.072,-0.6861 0.072,-0.6861 0.213,-0.6561 0.345,-0.5975 0.462,-0.5127 0.558,-0.4055 0.63,-0.2806 0.675,-0.1434 h 0.69 l 0.675,0.1434 0.63,0.2806 0.558,0.4055 0.462,0.5127 0.345,0.5975 0.213,0.6561 0.072,0.6861 -0.072,0.6861 -0.213,0.6561 -0.345,0.5975 -0.462,0.5127 -0.558,0.4055 -0.63,0.2806 -0.675,0.1434 z m -60.000003,0 -0.6748,-0.1434 -0.6302,-0.2806 -0.5581,-0.4055 -0.4617,-0.5127 -0.3449,-0.5975 -0.2132,-0.6561 -0.0721,-0.6861 0.0721,-0.6861 0.2132,-0.6561 0.3449,-0.5975 0.4617,-0.5127 0.5581,-0.4055 0.6302,-0.2806 0.6748,-0.1434 h 0.6899 l 0.6748,0.1434 0.6303,0.2806 0.5581,0.4055 0.4617,0.5127 0.3449,0.5975 0.2132,0.6561 0.0721,0.6861 -0.0721,0.6861 -0.2132,0.6561 -0.3449,0.5975 -0.4617,0.5127 -0.5581,0.4055 -0.6303,0.2806 -0.6748,0.1434 z m 20.0001,0 -0.6749,-0.1434 -0.6302,-0.2806 -0.5581,-0.4055 -0.4617,-0.5127 -0.3449,-0.5975 -0.2132,-0.6561 -0.0721,-0.6861 0.0721,-0.6861 0.2132,-0.6561 0.3449,-0.5975 0.4617,-0.5127 0.5581,-0.4055 0.6302,-0.2806 0.6749,-0.1434 h 0.6898 l 0.6748,0.1434 0.6303,0.2806 0.5581,0.4055 0.4617,0.5127 0.3449,0.5975 0.2132,0.6561 0.0721,0.6861 -0.0721,0.6861 -0.2132,0.6561 -0.3449,0.5975 -0.4617,0.5127 -0.5581,0.4055 -0.6303,0.2806 -0.6748,0.1434 z m 99.999903,0 -0.675,-0.1434 -0.63,-0.2806 -0.558,-0.4055 -0.462,-0.5127 -0.345,-0.5975 -0.213,-0.6561 -0.072,-0.6861 0.072,-0.6861 0.213,-0.6561 0.345,-0.5975 0.462,-0.5127 0.558,-0.4055 0.63,-0.2806 0.675,-0.1434 h 0.69 l 0.675,0.1434 0.63,0.2806 0.558,0.4055 0.462,0.5127 0.345,0.5975 0.213,0.6561 0.072,0.6861 -0.072,0.6861 -0.213,0.6561 -0.345,0.5975 -0.462,0.5127 -0.558,0.4055 -0.63,0.2806 -0.675,0.1434 z m -79.999903,0 -0.6749,-0.1434 -0.6302,-0.2806 -0.5581,-0.4055 -0.4617,-0.5127 -0.3449,-0.5975 -0.2132,-0.6561 -0.0721,-0.6861 0.0721,-0.6861 0.2132,-0.6561 0.3449,-0.5975 0.4617,-0.5127 0.5581,-0.4055 0.6302,-0.2806 0.6749,-0.1434 h 0.6898 l 0.6748,0.1434 0.6303,0.2806 0.5581,0.4055 0.4617,0.5127 0.3449,0.5975 0.2132,0.6561 0.0721,0.6861 -0.0721,0.6861 -0.2132,0.6561 -0.3449,0.5975 -0.4617,0.5127 -0.5581,0.4055 -0.6303,0.2806 -0.6748,0.1434 z m -60.0001,0 -0.6748,-0.1434 -0.6302,-0.2806 -0.5581,-0.4055 -0.4617,-0.5127 -0.3449,-0.5975 -0.2132,-0.6561 -0.0721,-0.6861 0.0721,-0.6861 0.2132,-0.6561 0.3449,-0.5975 0.4617,-0.5127 0.5581,-0.4055 0.6302,-0.2806 0.6748,-0.1434 h 0.6899 l 0.6748,0.1434 0.6303,0.2806 0.5581,0.4055 0.4617,0.5127 0.3449,0.5975 0.2132,0.6561 0.0721,0.6861 -0.0721,0.6861 -0.2132,0.6561 -0.3449,0.5975 -0.4617,0.5127 -0.5581,0.4055 -0.6303,0.2806 -0.6748,0.1434 z M 19.40212,16.6531 l -0.3763,0.6518 -0.5036,0.5593 -0.6089,0.4424 -0.6875,0.3061 -0.7362,0.1565 h -0.7526 l -0.7362,-0.1565 -0.6875,-0.3061 -0.6089,-0.4424 -0.5036,-0.5593 -0.3763,-0.6518 -0.2325,-0.7157 -0.0787,-0.7485 0.0787,-0.7485 0.2325,-0.7158 0.3763,-0.6517 0.5036,-0.5593 0.6089,-0.4424 0.6875,-0.3061 0.7362,-0.1565 h 0.7526 l 0.7362,0.1565 0.6875,0.3061 0.6089,0.4424 0.5036,0.5593 0.3763,0.6517 0.2325,0.7158 0.0787,0.7485 -0.0787,0.7485 z m 13.696497,-2.8064 0.3449,-0.5975 0.4617,-0.5127 0.5581,-0.4055 0.6302,-0.2806 0.6748,-0.1434 h 0.6899 l 0.6748,0.1434 0.6303,0.2806 0.5581,0.4055 0.4617,0.5127 0.3449,0.5975 0.2132,0.6561 0.0721,0.6861 -0.0721,0.6861 -0.2132,0.6561 -0.3449,0.5975 -0.4617,0.5127 -0.5581,0.4055 -0.6303,0.2806 -0.6748,0.1434 h -0.6899 l -0.6748,-0.1434 -0.6302,-0.2806 -0.5581,-0.4055 -0.4617,-0.5127 -0.3449,-0.5975 -0.2132,-0.6561 -0.0721,-0.6861 0.0721,-0.6861 z"
+ stroke="#000000"
+ fill="#d3d3d3"
+ stroke-width="0.5"
+ id="path116" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="Labels"
+ style="display:inline">
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="10.982465"
+ y="7.1965952"
+ id="text851"><tspan
+ sodipodi:role="line"
+ id="tspan849"
+ x="10.982465"
+ y="7.1965952"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">Reset</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="30.483782"
+ y="7.1797137"
+ id="text855"><tspan
+ sodipodi:role="line"
+ id="tspan853"
+ x="30.483782"
+ y="7.1797137"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">Speed</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="52.565861"
+ y="7.1780019"
+ id="text859"><tspan
+ sodipodi:role="line"
+ id="tspan857"
+ x="52.565861"
+ y="7.1780019"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">Run</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="53.047592"
+ y="26.508728"
+ id="text863"><tspan
+ sodipodi:role="line"
+ id="tspan861"
+ x="53.047592"
+ y="26.508728"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">Set</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="61.776833"
+ y="16.893724"
+ id="text871"><tspan
+ sodipodi:role="line"
+ id="tspan869"
+ x="61.776833"
+ y="16.893724"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">Step</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="92.310364"
+ y="26.518877"
+ id="text875"><tspan
+ sodipodi:role="line"
+ id="tspan873"
+ x="92.310364"
+ y="26.518877"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">Skip</tspan></text>
+ <path
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 187.43845,13.880819 c -0.15848,0 -0.29892,0.02544 -0.42065,0.07596 -0.12058,0.04938 -0.21572,0.123852 -0.28577,0.223759 -0.0701,0.09991 -0.11007,0.206304 -0.12041,0.318844 -0.009,0.111391 -0.0139,0.332681 -0.0139,0.664559 v 0.386023 c 0,0.307761 0.005,0.514869 0.0155,0.621667 0.0115,0.106798 0.0494,0.209347 0.11369,0.306958 0.0655,0.09646 0.15808,0.170532 0.27751,0.222209 0.11942,0.05168 0.27273,0.07751 0.45992,0.07751 0.15043,0 0.28175,-0.02239 0.39429,-0.06718 0.11369,-0.04479 0.20286,-0.107716 0.26716,-0.188102 0.0655,-0.08153 0.10549,-0.169786 0.12041,-0.2651 0.0149,-0.09532 0.0222,-0.24041 0.0222,-0.435632 v -0.222209 c 0,-0.164216 -0.0129,-0.294728 -0.0393,-0.391191 -0.0264,-0.09646 -0.0884,-0.179145 -0.18604,-0.248047 -0.0976,-0.0689 -0.21049,-0.103353 -0.33796,-0.103352 -0.10106,0 -0.18586,0.01895 -0.25477,0.05684 -0.0689,0.03675 -0.12098,0.09227 -0.15658,0.166915 v -0.444418 c 0,-0.104501 0.002,-0.173805 0.005,-0.208256 0.003,-0.03445 0.0163,-0.06241 0.0393,-0.08423 0.023,-0.02182 0.0523,-0.03307 0.0879,-0.03307 0.0425,0 0.0761,0.01166 0.10025,0.03462 0.0253,0.02297 0.039,0.05185 0.0413,0.0863 0.003,0.0333 0.005,0.114664 0.005,0.244429 h 0.69556 c 0,-0.174551 -0.0266,-0.319245 -0.0806,-0.434082 -0.054,-0.114836 -0.14355,-0.204007 -0.26872,-0.267167 -0.12517,-0.06316 -0.28537,-0.09457 -0.48059,-0.09457 z m -36.37194,0.0015 -0.83199,2.895947 h 0.5271 l 0.82682,-2.895947 z m 1.39526,0 -0.83199,2.895947 h 0.5271 l 0.82682,-2.895947 z m 22.34334,0 -0.83199,2.895947 h 0.5271 l 0.82682,-2.895947 z m 7.08122,0 c -0.14125,0 -0.26223,0.02239 -0.36328,0.06718 -0.10106,0.04479 -0.18334,0.111161 -0.2465,0.198437 -0.0632,0.08728 -0.10278,0.17593 -0.11886,0.26665 -0.0161,0.08957 -0.0243,0.212793 -0.0243,0.36897 v 0.101286 h 0.62373 v -0.2651 c 0,-0.122875 0.0125,-0.205156 0.0377,-0.246497 0.0264,-0.04134 0.066,-0.06201 0.11886,-0.06201 0.0528,0 0.092,0.01895 0.11731,0.05684 0.0264,0.03675 0.0398,0.09319 0.0398,0.168982 0,0.09876 -0.0431,0.236563 -0.12919,0.413411 -0.085,0.1757 -0.35462,0.6343 -0.80822,1.376144 v 0.397961 h 1.53169 V 16.24915 h -0.76327 c 0.39045,-0.577628 0.62512,-0.955268 0.70435,-1.133264 0.0804,-0.177997 0.12093,-0.346807 0.12093,-0.506429 0,-0.210151 -0.0716,-0.383726 -0.21394,-0.520382 -0.14125,-0.137804 -0.35008,-0.206706 -0.62684,-0.206706 z m 1.77095,0 c -0.14125,0 -0.26223,0.02239 -0.36328,0.06718 -0.10106,0.04479 -0.18334,0.111161 -0.2465,0.198437 -0.0632,0.08728 -0.10278,0.17593 -0.11885,0.26665 -0.0161,0.08957 -0.0243,0.212793 -0.0243,0.36897 v 0.101286 h 0.62373 v -0.2651 c 0,-0.122875 0.0125,-0.205156 0.0377,-0.246497 0.0264,-0.04134 0.066,-0.06201 0.11885,-0.06201 0.0528,0 0.092,0.01895 0.11731,0.05684 0.0264,0.03675 0.0398,0.09319 0.0398,0.168982 0,0.09876 -0.0431,0.236563 -0.12919,0.413411 -0.085,0.1757 -0.35462,0.6343 -0.80822,1.376144 v 0.397961 h 1.53169 V 16.24915 h -0.76326 c 0.39044,-0.577628 0.62511,-0.955268 0.70435,-1.133264 0.0804,-0.177997 0.12092,-0.346807 0.12092,-0.506429 0,-0.210151 -0.0715,-0.383726 -0.21394,-0.520382 -0.14125,-0.137804 -0.35009,-0.206706 -0.62684,-0.206706 z m 1.85674,0 c -0.18719,0 -0.34647,0.03882 -0.47853,0.115756 -0.13091,0.07694 -0.21876,0.178972 -0.26355,0.306441 -0.0436,0.127468 -0.0656,0.319073 -0.0656,0.575158 v 0.973584 c 0,0.196371 0.0138,0.339745 0.0414,0.430465 0.0276,0.08957 0.0741,0.175298 0.13952,0.256832 0.0655,0.08153 0.15331,0.141823 0.26355,0.180867 0.11024,0.0379 0.24845,0.05684 0.41496,0.05684 0.12632,0 0.24093,-0.01854 0.34313,-0.05529 0.10221,-0.03675 0.18914,-0.09704 0.26149,-0.180868 0.0723,-0.08383 0.12017,-0.173805 0.14314,-0.270267 0.023,-0.09646 0.0346,-0.250689 0.0346,-0.461988 v -0.930176 c 0,-0.211299 -0.0113,-0.365007 -0.0331,-0.46147 -0.0207,-0.09646 -0.0607,-0.182992 -0.1204,-0.259933 -0.0597,-0.07694 -0.14969,-0.141995 -0.27027,-0.19482 -0.12058,-0.05397 -0.25758,-0.08113 -0.41031,-0.08113 z m 3.72225,0 -0.83199,2.895947 h 0.5271 l 0.82682,-2.895947 z m -47.101,0.05374 v 2.788514 h 0.69608 v -1.630908 c 0,-0.115985 0.007,-0.1935 0.0222,-0.232544 0.0149,-0.03904 0.0438,-0.05891 0.0863,-0.05891 0.0459,0 0.0752,0.01895 0.0879,0.05684 0.0138,0.0379 0.0207,0.123621 0.0207,0.256832 v 1.60869 h 0.69557 v -1.576131 c 0,-0.214744 -0.009,-0.361965 -0.0289,-0.44235 -0.0184,-0.08153 -0.071,-0.153479 -0.1571,-0.215491 -0.085,-0.06201 -0.18833,-0.09302 -0.31006,-0.09302 -0.0792,0 -0.15371,0.01378 -0.22375,0.04134 -0.0689,0.02756 -0.13304,0.0689 -0.19276,0.124024 v -0.626832 z m 11.62565,0 c -0.15503,0 -0.26964,0.01034 -0.34313,0.03101 -0.0735,0.02067 -0.13075,0.05076 -0.17209,0.09095 -0.0402,0.03904 -0.0656,0.08383 -0.076,0.134359 -0.0103,0.05053 -0.0155,0.151354 -0.0155,0.30179 h -0.14263 v 0.361735 h 0.14263 v 1.86867 h 0.69608 v -1.86862 h 0.16536 v -0.361735 h -0.293 v -0.07235 c 0,-0.06201 0.013,-0.09951 0.0382,-0.112138 0.0264,-0.01378 0.11122,-0.02067 0.25476,-0.02067 v -0.35295 z m 6.17326,0 v 2.788514 h 0.65113 l 0.045,-0.172082 c 0.0586,0.0712 0.12271,0.124597 0.19276,0.160196 0.0712,0.0356 0.14791,0.05323 0.22944,0.05323 0.11369,0 0.21187,-0.02969 0.29456,-0.0894 0.0827,-0.06086 0.13476,-0.13189 0.15658,-0.213424 0.023,-0.08268 0.0346,-0.208026 0.0346,-0.375687 v -1.029912 c 0,-0.168809 -0.004,-0.279052 -0.0124,-0.330729 -0.007,-0.05168 -0.0284,-0.104674 -0.0651,-0.158646 -0.0367,-0.05397 -0.0901,-0.09572 -0.1602,-0.125574 -0.07,-0.02986 -0.15273,-0.04496 -0.24805,-0.04496 -0.0827,0 -0.15979,0.01682 -0.23099,0.05013 -0.07,0.03215 -0.13379,0.08119 -0.19121,0.147795 v -0.659397 z m 3.63647,0 v 2.788514 h 0.71624 v -2.78846 z m 14.96705,0 v 0.363285 h 0.71675 v -0.363231 z m -34.51779,0.19792 v 0.360185 h -0.14986 v 0.361735 h 0.14986 v 1.160653 c 0,0.227376 0.006,0.37207 0.0186,0.434082 0.0126,0.06086 0.045,0.115583 0.0966,0.163814 0.0517,0.04708 0.11156,0.07769 0.17932,0.09147 0.0678,0.01263 0.18052,0.0186 0.33899,0.0186 h 0.28112 v -0.368453 c -0.11369,0 -0.17874,-0.0086 -0.19482,-0.02584 -0.0149,-0.01723 -0.0222,-0.101229 -0.0222,-0.251664 v -1.222608 h 0.18759 v -0.361735 h -0.18759 v -0.360185 z m 1.07487,0 v 0.360185 h -0.14986 v 0.361735 h 0.14986 v 1.160653 c 0,0.227376 0.006,0.37207 0.0186,0.434082 0.0126,0.06086 0.045,0.115583 0.0966,0.163814 0.0517,0.04708 0.11156,0.07769 0.17932,0.09147 0.0678,0.01263 0.18052,0.0186 0.33899,0.0186 h 0.28112 v -0.368453 c -0.11369,0 -0.17874,-0.0086 -0.19482,-0.02584 -0.0149,-0.01723 -0.0222,-0.101229 -0.0222,-0.251664 v -1.222608 h 0.18759 v -0.361735 h -0.18759 v -0.360185 z m 27.943,0 v 0.360185 h -0.14987 v 0.361735 h 0.14987 v 1.160653 c 0,0.227376 0.006,0.37207 0.0191,0.434082 0.0126,0.06086 0.0444,0.115583 0.0961,0.163814 0.0517,0.04708 0.11157,0.07769 0.17932,0.09147 0.0677,0.01263 0.18104,0.0186 0.33952,0.0186 h 0.2806 v -0.368453 c -0.11369,0 -0.17874,-0.0086 -0.19482,-0.02584 -0.0149,-0.01723 -0.0222,-0.101229 -0.0222,-0.251664 v -1.222608 h 0.18758 v -0.361735 h -0.18758 v -0.360185 z m 12.49174,0.177251 c 0.0528,0 0.0865,0.01895 0.10025,0.05684 0.0149,0.03675 0.0222,0.129363 0.0222,0.277502 v 1.381311 c 0,0.136656 -0.008,0.224506 -0.0243,0.26355 -0.0161,0.03904 -0.0496,0.05891 -0.10129,0.05891 -0.0517,0 -0.0857,-0.01682 -0.1018,-0.05013 -0.0149,-0.0333 -0.0222,-0.131086 -0.0222,-0.293005 v -1.360641 c 0,-0.143545 0.008,-0.234841 0.0238,-0.273885 0.0172,-0.04019 0.0517,-0.06046 0.10335,-0.06046 z m -38.2509,0.0863 c -0.0884,0 -0.16978,0.02027 -0.24442,0.06046 -0.0747,0.04019 -0.14315,0.100884 -0.20516,0.182418 l 0.0124,-0.201539 h -0.70796 v 2.611211 h 0.69556 v -0.523483 c 0.0609,0.07924 0.12804,0.139125 0.20154,0.179318 0.0735,0.04019 0.15365,0.05994 0.23978,0.05994 0.10794,0 0.19964,-0.02584 0.27543,-0.07751 0.0769,-0.05282 0.1273,-0.12253 0.15142,-0.209806 0.0253,-0.08842 0.0382,-0.236563 0.0382,-0.444417 v -0.963249 c 0,-0.181442 -0.01,-0.309714 -0.0295,-0.385506 -0.0195,-0.07579 -0.0691,-0.14257 -0.14831,-0.199988 -0.0781,-0.05857 -0.17111,-0.08785 -0.27906,-0.08785 z m 1.35393,0 c -0.15274,0 -0.28709,0.02371 -0.40308,0.0708 -0.11483,0.04708 -0.1962,0.114262 -0.24443,0.201538 -0.0482,0.08613 -0.0723,0.220486 -0.0723,0.403076 0,0.128617 0.0224,0.239664 0.0672,0.33383 0.0448,0.09302 0.16921,0.197289 0.37362,0.312126 0.24346,0.135507 0.37874,0.216868 0.40515,0.244429 0.0253,0.02756 0.0377,0.09606 0.0377,0.205156 0,0.07924 -0.01,0.131316 -0.0294,0.156579 -0.0195,0.02412 -0.054,0.03617 -0.10336,0.03617 -0.0459,0 -0.0769,-0.01855 -0.093,-0.05529 -0.0149,-0.03675 -0.0222,-0.116387 -0.0222,-0.239262 v -0.144694 h -0.6165 v 0.110071 c 0,0.190629 0.0232,0.333198 0.0703,0.427364 0.0471,0.09417 0.13321,0.168637 0.25838,0.223759 0.12632,0.05512 0.2779,0.08268 0.45475,0.08268 0.15962,0 0.2957,-0.02492 0.40824,-0.07545 0.11369,-0.05168 0.19465,-0.124942 0.24288,-0.219108 0.0482,-0.09531 0.0724,-0.235645 0.0724,-0.42168 0,-0.166513 -0.0314,-0.29358 -0.0946,-0.380855 -0.0632,-0.08728 -0.19579,-0.180294 -0.39791,-0.279053 -0.15158,-0.07464 -0.25189,-0.131488 -0.30127,-0.170532 -0.0482,-0.03904 -0.0775,-0.07482 -0.0879,-0.106971 -0.009,-0.0333 -0.0139,-0.08498 -0.0139,-0.155029 0,-0.05168 0.01,-0.08997 0.0294,-0.115238 0.0195,-0.02641 0.0488,-0.03979 0.0879,-0.03979 0.0482,0 0.0779,0.0147 0.0894,0.04341 0.0126,0.02756 0.0191,0.09382 0.0191,0.199471 v 0.124023 h 0.6165 v -0.132291 c 0,-0.114837 -0.006,-0.199241 -0.0191,-0.253215 -0.0115,-0.05397 -0.0459,-0.11254 -0.10335,-0.1757 -0.0563,-0.06316 -0.13763,-0.114032 -0.24443,-0.151928 -0.10565,-0.03904 -0.23444,-0.0584 -0.38602,-0.0584 z m 6.62336,0 c -0.19177,0.01263 -0.33819,0.126321 -0.43924,0.341065 l 0.0274,-0.299724 h -0.69608 v 2.285702 h 0.69608 v -0.90227 c 0,-0.221635 0.007,-0.362884 0.0207,-0.423747 0.0138,-0.06201 0.0504,-0.110243 0.11006,-0.144694 0.0597,-0.03445 0.15366,-0.05168 0.28112,-0.05168 z m 0.90951,0 c -0.18603,0 -0.33894,0.03617 -0.45837,0.108521 -0.11943,0.07235 -0.20211,0.168408 -0.24805,0.287838 -0.0459,0.11943 -0.0687,0.285197 -0.0687,0.497643 v 0.585495 c 0,0.194073 0.0125,0.340088 0.0377,0.437699 0.0253,0.09646 0.067,0.179145 0.12557,0.248047 0.0597,0.06775 0.14332,0.119028 0.25012,0.153479 0.10679,0.0333 0.23679,0.04961 0.39067,0.04961 0.1378,0 0.2597,-0.01935 0.36535,-0.05839 0.1068,-0.04019 0.19425,-0.101803 0.262,-0.184485 0.0678,-0.08383 0.11162,-0.173403 0.13229,-0.268718 0.0207,-0.09646 0.031,-0.247128 0.031,-0.452685 v -0.560173 c 0,-0.161919 -0.0112,-0.282497 -0.0341,-0.361735 -0.0218,-0.07924 -0.0632,-0.155833 -0.12402,-0.230476 -0.0609,-0.07464 -0.14791,-0.134933 -0.26045,-0.180868 -0.11139,-0.04708 -0.24483,-0.0708 -0.40101,-0.0708 z m 2.17196,0 c -0.0953,0 -0.18012,0.02199 -0.25476,0.06563 -0.0747,0.04249 -0.13878,0.106626 -0.19276,0.192754 l 0.0119,-0.217042 h -0.6873 v 2.285701 h 0.67541 v -1.584399 c 0,-0.110243 8.1e-4,-0.182188 0.003,-0.215491 0.002,-0.03445 0.0144,-0.06333 0.0362,-0.0863 0.0218,-0.02412 0.0486,-0.03617 0.0796,-0.03617 0.0494,0 0.0791,0.02239 0.0894,0.06718 0.0115,0.04479 0.017,0.179145 0.017,0.403076 v 1.452104 h 0.67541 v -1.489831 c 0,-0.196371 0.007,-0.317351 0.0207,-0.363286 0.0149,-0.04593 0.0473,-0.06925 0.0966,-0.06925 0.0482,0 0.0783,0.02371 0.0909,0.0708 0.0138,0.04594 0.0207,0.166514 0.0207,0.361736 v 1.489831 h 0.67541 v -1.62419 c 0,-0.187184 -0.0107,-0.321944 -0.0326,-0.404627 -0.0218,-0.08383 -0.0718,-0.154455 -0.14986,-0.211873 -0.0769,-0.05742 -0.17472,-0.0863 -0.293,-0.0863 -0.0896,0 -0.17094,0.02199 -0.24443,0.06563 -0.0735,0.04249 -0.13987,0.106626 -0.19844,0.192754 -0.1068,-0.172255 -0.25321,-0.258383 -0.43925,-0.258383 z m 4.17907,0 c -0.15962,0 -0.30087,0.03101 -0.42374,0.09302 -0.12288,0.06086 -0.21164,0.149115 -0.26562,0.2651 -0.054,0.114837 -0.0806,0.272507 -0.0806,0.472323 v 0.666625 c -1e-5,0.169958 0.012,0.299552 0.0362,0.389124 0.0241,0.08842 0.0672,0.169786 0.12919,0.24443 0.0632,0.0735 0.15101,0.13166 0.26355,0.174149 0.11254,0.04249 0.24213,0.06356 0.38912,0.06356 0.15159,0 0.27733,-0.02107 0.37724,-0.06356 0.10106,-0.04364 0.18414,-0.108693 0.2496,-0.19482 0.0655,-0.08613 0.1068,-0.167087 0.12402,-0.242879 0.0184,-0.07579 0.0279,-0.184313 0.0279,-0.325562 v -0.168465 h -0.65991 v 0.301274 c 0,0.113688 -0.009,0.1908 -0.0274,0.230993 -0.0172,0.03904 -0.0526,0.05839 -0.10542,0.05839 -0.0425,0 -0.0709,-0.0151 -0.0858,-0.04496 -0.0149,-0.02986 -0.0227,-0.09612 -0.0227,-0.199471 v -0.494543 h 0.90124 v -0.303341 c 0,-0.221634 -0.0258,-0.39297 -0.0775,-0.514697 -0.0505,-0.122875 -0.1397,-0.22106 -0.26716,-0.294556 -0.12632,-0.07464 -0.28692,-0.112138 -0.48215,-0.112138 z m 2.77503,0 c -0.18604,0 -0.33894,0.03617 -0.45837,0.108521 -0.11943,0.07235 -0.20211,0.168408 -0.24805,0.287838 -0.0459,0.11943 -0.0687,0.285197 -0.0687,0.497643 v 0.585495 c 0,0.194073 0.0125,0.340088 0.0377,0.437699 0.0253,0.09646 0.0675,0.179145 0.12609,0.248047 0.0597,0.06775 0.1428,0.119028 0.24959,0.153479 0.1068,0.0333 0.23731,0.04961 0.39119,0.04961 0.13781,0 0.25919,-0.01935 0.36484,-0.05839 0.1068,-0.04019 0.19424,-0.101803 0.262,-0.184485 0.0677,-0.08383 0.11214,-0.173403 0.13281,-0.268718 0.0207,-0.09646 0.031,-0.247128 0.031,-0.452685 v -0.560173 c 0,-0.161919 -0.0117,-0.282497 -0.0346,-0.361735 -0.0218,-0.07924 -0.0632,-0.155833 -0.12402,-0.230476 -0.0609,-0.07464 -0.14739,-0.134933 -0.25994,-0.180868 -0.11139,-0.04708 -0.24534,-0.0708 -0.40152,-0.0708 z m 5.19503,0 c -0.0953,0 -0.17972,0.02107 -0.25321,0.06356 -0.0724,0.04134 -0.13396,0.104272 -0.18449,0.188103 l 0.0124,-0.210324 h -0.70796 v 2.285704 h 0.69556 v -1.545125 c 0,-0.172255 0.006,-0.277732 0.0191,-0.316777 0.0126,-0.04019 0.0436,-0.06046 0.093,-0.06046 0.0471,0 0.076,0.01722 0.0863,0.05168 0.0103,0.03445 0.0155,0.130512 0.0155,0.287838 v 1.582844 h 0.69557 v -1.601969 c 0,-0.199816 -0.0107,-0.341869 -0.0326,-0.426848 -0.0218,-0.08613 -0.0705,-0.15767 -0.14624,-0.21394 -0.0758,-0.05627 -0.17358,-0.08423 -0.29301,-0.08423 z m 1.46089,0 c -0.15962,0 -0.30087,0.03101 -0.42374,0.09302 -0.12288,0.06086 -0.21165,0.149115 -0.26562,0.2651 -0.054,0.114837 -0.0806,0.272507 -0.0806,0.472323 v 0.666625 c 0,0.169958 0.0121,0.299552 0.0362,0.389124 0.0241,0.08842 0.0672,0.169786 0.12919,0.24443 0.0632,0.0735 0.15101,0.13166 0.26355,0.174149 0.11254,0.04249 0.24213,0.06356 0.38912,0.06356 0.15159,0 0.27733,-0.02107 0.37724,-0.06356 0.10106,-0.04364 0.18414,-0.108693 0.2496,-0.19482 0.0654,-0.08613 0.1068,-0.167087 0.12402,-0.242879 0.0184,-0.07579 0.0279,-0.184313 0.0279,-0.325562 v -0.168465 h -0.65991 v 0.301274 c 0,0.113688 -0.009,0.1908 -0.0274,0.230993 -0.0172,0.03904 -0.0526,0.05839 -0.10542,0.05839 -0.0425,0 -0.0709,-0.0151 -0.0858,-0.04496 -0.0149,-0.02986 -0.0227,-0.09612 -0.0227,-0.199471 v -0.494543 h 0.90124 v -0.303341 c 0,-0.221634 -0.0258,-0.39297 -0.0775,-0.514697 -0.0505,-0.122875 -0.1397,-0.22106 -0.26716,-0.294556 -0.12632,-0.07464 -0.28692,-0.112138 -0.48215,-0.112138 z m 4.27365,0 c -0.15963,0 -0.30088,0.03101 -0.42375,0.09302 -0.12288,0.06086 -0.21165,0.149115 -0.26562,0.2651 -0.054,0.114837 -0.0806,0.272507 -0.0806,0.472323 v 0.666625 c 0,0.169958 0.012,0.299552 0.0362,0.389124 0.0241,0.08842 0.0672,0.169786 0.12919,0.24443 0.0632,0.0735 0.15101,0.13166 0.26355,0.174149 0.11254,0.04249 0.24213,0.06356 0.38912,0.06356 0.15159,0 0.27733,-0.02107 0.37724,-0.06356 0.10106,-0.04364 0.18414,-0.108693 0.2496,-0.19482 0.0654,-0.08613 0.1068,-0.167087 0.12402,-0.242879 0.0184,-0.07579 0.0279,-0.184313 0.0279,-0.325562 v -0.168465 h -0.65991 v 0.301274 c 0,0.113688 -0.009,0.1908 -0.0274,0.230993 -0.0172,0.03904 -0.0526,0.05839 -0.10542,0.05839 -0.0425,0 -0.0709,-0.0151 -0.0858,-0.04496 -0.0149,-0.02986 -0.0227,-0.09612 -0.0227,-0.199471 v -0.494543 h 0.90124 v -0.303341 c 0,-0.221634 -0.0258,-0.39297 -0.0775,-0.514697 -0.0505,-0.122875 -0.1397,-0.22106 -0.26717,-0.294556 -0.12632,-0.07464 -0.28691,-0.112138 -0.48213,-0.112138 z m 2.16162,0 c -0.19178,0.01263 -0.33819,0.126321 -0.43925,0.341065 l 0.0274,-0.299724 h -0.69557 v 2.285702 h 0.69557 v -0.90227 c 0,-0.221635 0.007,-0.362884 0.0207,-0.423747 0.0138,-0.06201 0.0509,-0.110243 0.11059,-0.144694 0.0597,-0.03445 0.15313,-0.05168 0.2806,-0.05168 z m 1.78955,0 c -0.15273,0 -0.28709,0.02371 -0.40307,0.0708 -0.11484,0.04708 -0.1962,0.114262 -0.24443,0.201538 -0.0482,0.08613 -0.0724,0.220486 -0.0724,0.403076 0,0.128617 0.0224,0.239664 0.0672,0.33383 0.0448,0.09302 0.16921,0.197289 0.37362,0.312126 0.24345,0.135507 0.37873,0.216868 0.40514,0.244429 0.0253,0.02756 0.0377,0.09606 0.0377,0.205156 0,0.07924 -0.01,0.131316 -0.0295,0.156579 -0.0195,0.02412 -0.054,0.03617 -0.10335,0.03617 -0.0459,0 -0.0769,-0.01855 -0.093,-0.05529 -0.0149,-0.03675 -0.0222,-0.116387 -0.0222,-0.239262 v -0.144694 h -0.6165 v 0.110071 c 0,0.190629 0.0232,0.333198 0.0703,0.427364 0.0471,0.09417 0.13321,0.168637 0.25838,0.223759 0.12632,0.05512 0.27791,0.08268 0.45476,0.08268 0.15962,0 0.2957,-0.02492 0.40824,-0.07545 0.11369,-0.05168 0.19465,-0.124942 0.24288,-0.219108 0.0482,-0.09531 0.0724,-0.235645 0.0724,-0.42168 0,-0.166513 -0.0314,-0.29358 -0.0946,-0.380855 -0.0632,-0.08728 -0.1958,-0.180294 -0.39791,-0.279053 -0.15158,-0.07464 -0.2519,-0.131488 -0.30127,-0.170532 -0.0482,-0.03904 -0.0775,-0.07482 -0.0879,-0.106971 -0.009,-0.0333 -0.014,-0.08498 -0.014,-0.155029 0,-0.05168 0.01,-0.08997 0.0295,-0.115238 0.0195,-0.02641 0.0488,-0.03979 0.0878,-0.03979 0.0482,0 0.0779,0.0147 0.0894,0.04341 0.0126,0.02756 0.0191,0.09382 0.0191,0.199471 v 0.124023 h 0.6165 v -0.132291 c 0,-0.114837 -0.006,-0.199241 -0.0191,-0.253215 -0.0115,-0.05397 -0.0459,-0.11254 -0.10335,-0.1757 -0.0563,-0.06316 -0.13763,-0.114032 -0.24443,-0.151928 -0.10565,-0.03904 -0.23444,-0.0584 -0.38603,-0.0584 z m -13.96607,0.04134 0.29456,2.285649 h 0.75602 l 0.0775,-0.496094 c 0.0333,-0.204409 0.0591,-0.406349 0.0775,-0.606164 0.054,0.455901 0.10181,0.823205 0.14315,1.102258 h 0.75605 l 0.27751,-2.285649 h -0.59945 c -0.0838,0.490352 -0.13683,0.926157 -0.15865,1.307414 l -0.14108,-1.307414 h -0.57722 c -0.0965,0.788927 -0.14814,1.224733 -0.15503,1.307414 -0.0965,-0.811893 -0.14682,-1.247698 -0.15141,-1.307414 z m 12.33155,0 v 2.285703 h 0.71675 v -2.285649 z m -31.60014,0.363286 c 0.0471,0 0.076,0.0151 0.0863,0.04496 0.0103,0.02986 0.0155,0.115583 0.0155,0.256832 v 0.979785 c 0,0.121727 -0.006,0.19884 -0.0171,0.230994 -0.0103,0.03101 -0.0379,0.04651 -0.0827,0.04651 -0.0459,0 -0.0761,-0.01723 -0.0899,-0.05168 -0.0138,-0.03445 -0.0207,-0.120578 -0.0207,-0.258382 v -0.947229 c 0,-0.132062 0.006,-0.215663 0.0191,-0.250114 0.0138,-0.03445 0.0435,-0.05168 0.0894,-0.05168 z m 9.25163,0 c 0.0413,0 0.0685,0.0155 0.0811,0.04651 0.0126,0.02986 0.0191,0.103526 0.0191,0.220659 v 1.054199 c 0,0.09876 -0.007,0.162896 -0.0207,0.192753 -0.0126,0.02986 -0.0398,0.04496 -0.0811,0.04496 -0.0402,0 -0.0674,-0.0159 -0.0811,-0.04806 -0.0138,-0.0333 -0.0207,-0.103928 -0.0207,-0.211874 v -1.031978 c 0,-0.117133 0.007,-0.190801 0.0207,-0.220659 0.0138,-0.03101 0.0413,-0.04651 0.0827,-0.04651 z m 4.54288,0 c 0.0436,0 0.0729,0.01855 0.0879,0.05529 0.0149,0.0356 0.0222,0.112712 0.0222,0.230993 v 0.962732 c 0,0.135507 -0.007,0.221233 -0.0207,0.256832 -0.0126,0.0356 -0.0406,0.05323 -0.0842,0.05323 -0.0425,0 -0.0714,-0.01723 -0.0863,-0.05168 -0.0138,-0.03445 -0.0207,-0.113286 -0.0207,-0.236161 v -0.984953 c 1e-5,-0.127468 0.006,-0.206706 0.0191,-0.237711 0.0126,-0.03215 0.0402,-0.04858 0.0827,-0.04858 z m 1.81694,0 c 0.0391,0 0.0649,0.01722 0.0775,0.05168 0.0126,0.03445 0.0191,0.111162 0.0191,0.229444 v 0.166914 H 162.442 V 15.08328 c 0,-0.128617 0.006,-0.207453 0.0176,-0.236162 0.0115,-0.02986 0.0412,-0.04496 0.0894,-0.04496 z m 2.76676,0 c 0.0413,0 0.068,0.0155 0.0806,0.04651 0.0126,0.02986 0.0191,0.103526 0.0191,0.220659 v 1.054199 c 0,0.09876 -0.007,0.162896 -0.0207,0.192753 -0.0126,0.02986 -0.0398,0.04496 -0.0811,0.04496 -0.0402,0 -0.0668,-0.0159 -0.0806,-0.04806 -0.0138,-0.0333 -0.0207,-0.103928 -0.0207,-0.211874 v -1.031978 c 0,-0.117133 0.007,-0.190801 0.0207,-0.220659 0.0138,-0.03101 0.0414,-0.04651 0.0827,-0.04651 z m 6.66419,0 c 0.039,0 0.0649,0.01722 0.0775,0.05168 0.0126,0.03445 0.0191,0.111162 0.0191,0.229444 v 0.166914 h -0.2036 V 15.08328 c 0,-0.128617 0.006,-0.207453 0.0176,-0.236162 0.0115,-0.02986 0.0412,-0.04496 0.0894,-0.04496 z m 4.27364,0 c 0.039,0 0.0649,0.01722 0.0775,0.05168 0.0126,0.03445 0.0191,0.111162 0.0191,0.229444 v 0.166914 h -0.20361 V 15.08328 c 0,-0.128617 0.006,-0.207453 0.0176,-0.236162 0.0115,-0.02986 0.0412,-0.04496 0.0894,-0.04496 z m -26.62887,0.10697 v 0.56689 h 0.52555 v -0.56689 z m 37.80855,0.378788 c 0.0494,0 0.0846,0.01855 0.10645,0.05529 0.0218,0.03675 0.0331,0.104329 0.0331,0.203088 v 0.521932 c 0,0.128617 -0.0164,0.207855 -0.0486,0.237712 -0.0322,0.02871 -0.0632,0.04341 -0.093,0.04341 -0.0494,0 -0.0846,-0.01895 -0.10645,-0.05684 -0.0207,-0.0379 -0.031,-0.118454 -0.031,-0.241329 v -0.504879 c 0,-0.102204 0.0107,-0.170187 0.0326,-0.204638 0.023,-0.0356 0.0587,-0.05374 0.10697,-0.05374 z m -37.80855,0.868218 v 0.568441 h 0.52555 v -0.568441 z m 19.01538,0 v 0.568441 h 0.52504 v -0.568441 z"
+ id="text987"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="148.69678"
+ y="11.622226"
+ id="text987-3"><tspan
+ sodipodi:role="line"
+ id="tspan985-6"
+ x="148.69678"
+ y="11.622226"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:11.2889px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">Eris 2206</tspan></text>
+ <g
+ id="g72395"
+ transform="translate(-0.44679485,4.632698)">
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:3.70417px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="165.07814"
+ y="21.829409"
+ id="text991"><tspan
+ sodipodi:role="line"
+ id="tspan989"
+ x="165.07814"
+ y="21.829409"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">Demo:</tspan><tspan
+ sodipodi:role="line"
+ x="165.07814"
+ y="26.062738"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px"
+ id="tspan1007">Load:</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:3.70417px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="177.38087"
+ y="22.135914"
+ id="text991-3"><tspan
+ sodipodi:role="line"
+ id="tspan989-6"
+ x="177.38087"
+ y="22.135914"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$1D $80</tspan><tspan
+ sodipodi:role="line"
+ x="177.38087"
+ y="26.369244"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px"
+ id="tspan1009-7">$1D $C0</tspan><tspan
+ sodipodi:role="line"
+ x="177.38087"
+ y="30.337994"
+ id="tspan1007-5" /></text>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="101.60313"
+ y="36.656078"
+ id="text947"><tspan
+ sodipodi:role="line"
+ id="tspan945"
+ x="101.60313"
+ y="36.656078"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">Data</tspan></text>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 99.407531,34.895833 h -63 l 0,3.46875"
+ id="path949"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 113.40753,34.895833 h 63 l 0,3.46875"
+ id="path951"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="175.50789"
+ y="55.514313"
+ id="text955"><tspan
+ sodipodi:role="line"
+ id="tspan953"
+ x="175.50789"
+ y="55.514313"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">0</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="155.22534"
+ y="55.523407"
+ id="text959"><tspan
+ sodipodi:role="line"
+ id="tspan957"
+ x="155.22534"
+ y="55.523407"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">1</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="135.08871"
+ y="55.521759"
+ id="text963"><tspan
+ sodipodi:role="line"
+ id="tspan961"
+ x="135.08871"
+ y="55.521759"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">2</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="115.10616"
+ y="55.470818"
+ id="text967"><tspan
+ sodipodi:role="line"
+ id="tspan965"
+ x="115.10616"
+ y="55.470818"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">3</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="94.920792"
+ y="55.559963"
+ id="text971"><tspan
+ sodipodi:role="line"
+ id="tspan969"
+ x="94.920792"
+ y="55.559963"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">4</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="75.036369"
+ y="55.445679"
+ id="text975"><tspan
+ sodipodi:role="line"
+ id="tspan973"
+ x="75.036369"
+ y="55.445679"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">5</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="54.947971"
+ y="55.459869"
+ id="text979"><tspan
+ sodipodi:role="line"
+ id="tspan977"
+ x="54.947971"
+ y="55.459869"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">6</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="35.208584"
+ y="55.515778"
+ id="text983"><tspan
+ sodipodi:role="line"
+ id="tspan981"
+ x="35.208584"
+ y="55.515778"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">7</tspan></text>
+ </g>
+</svg>
diff --git a/case/dst/labeled/top_plate/acryl_top_plate.svg b/case/dst/labeled/top_plate/acryl_top_plate.svg
@@ -0,0 +1,781 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="200mm"
+ height="200mm"
+ viewBox="0 -200 200 200"
+ version="1.1"
+ id="svg2589"
+ sodipodi:docname="acryl_top_plate.svg"
+ inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata2595">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>OpenSCAD Model</dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs2593" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1680"
+ inkscape:window-height="986"
+ id="namedview2591"
+ showgrid="true"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:zoom="9.9906665"
+ inkscape:cx="200.68731"
+ inkscape:cy="47.194048"
+ inkscape:window-x="1920"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer2"
+ inkscape:snap-bbox="true"
+ inkscape:bbox-paths="true"
+ inkscape:bbox-nodes="true"
+ inkscape:snap-bbox-edge-midpoints="true"
+ inkscape:snap-bbox-midpoints="true"
+ inkscape:pagecheckerboard="0"
+ inkscape:document-units="mm">
+ <sodipodi:guide
+ position="32.359124,181.42083"
+ orientation="0,1"
+ id="guide3294"
+ inkscape:locked="false" />
+ <inkscape:grid
+ type="xygrid"
+ id="grid3296" />
+ <sodipodi:guide
+ position="16.737288,126.48305"
+ orientation="1,0"
+ id="guide3817"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="182.83898,101.95975"
+ orientation="1,0"
+ id="guide3819"
+ inkscape:locked="false" />
+ </sodipodi:namedview>
+ <title
+ id="title2585">OpenSCAD Model</title>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="Aux"
+ style="display:none">
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#d3d3d3;stroke:#000000;stroke-width:0.5"
+ d="M 200,-200 H 0 V 2.3706049e-7 H 200 Z M 9.79094,-188.011 9.38196,-188.098 9,-188.268 8.66173,-188.514 8.38196,-188.824 8.1729,-189.187 8.0437,-189.584 8,-190 l 0.0437,-0.416 0.1292,-0.397 0.20906,-0.363 0.27977,-0.31 0.33827,-0.246 0.38196,-0.17 0.40898,-0.087 H 10.209 l 0.409,0.087 0.382,0.17 0.3383,0.246 0.2797,0.31 0.2091,0.363 0.1292,0.397 L 12,-190 l -0.0437,0.416 -0.1292,0.397 -0.2091,0.363 -0.2797,0.31 -0.3383,0.246 -0.382,0.17 -0.409,0.087 z m 180.00006,0 -0.409,-0.087 -0.382,-0.17 -0.338,-0.246 -0.28,-0.31 -0.209,-0.363 -0.129,-0.397 L 188,-190 l 0.044,-0.416 0.129,-0.397 0.209,-0.363 0.28,-0.31 0.338,-0.246 0.382,-0.17 0.409,-0.087 h 0.418 l 0.409,0.087 0.382,0.17 0.338,0.246 0.28,0.31 0.209,0.363 0.129,0.397 0.044,0.416 -0.044,0.416 -0.129,0.397 -0.209,0.363 -0.28,0.31 -0.338,0.246 -0.382,0.17 -0.409,0.087 z M 20,-20.000002 V -180 h 160 v 159.999998 z m 169.791,11.9890402 -0.409,-0.0869 -0.382,-0.17005 -0.338,-0.24576 -0.28,-0.31072 -0.209,-0.3621 -0.129,-0.39765 -0.044,-0.4158602 0.044,-0.4158 0.129,-0.3977 0.209,-0.3621 0.28,-0.3107 0.338,-0.2457 0.382,-0.1701 0.409,-0.0869 h 0.418 l 0.409,0.0869 0.382,0.1701 0.338,0.2457 0.28,0.3107 0.209,0.3621 0.129,0.3977 0.044,0.4158 -0.044,0.4158302 -0.129,0.39765 -0.209,0.3621 -0.28,0.31072 -0.338,0.24576 -0.382,0.17005 -0.409,0.0869 z m -180.00006,0 -0.40898,-0.0869 L 9,-8.2679118 8.66173,-8.5136718 8.38196,-8.8243918 8.1729,-9.1864918 8.0437,-9.5841418 8,-10.000002 l 0.0437,-0.4158 0.1292,-0.3977 0.20906,-0.3621 0.27977,-0.3107 0.33827,-0.2457 0.38196,-0.1701 0.40898,-0.0869 H 10.209 l 0.409,0.0869 0.382,0.1701 0.3383,0.2457 0.2797,0.3107 0.2091,0.3621 0.1292,0.3977 0.0437,0.4158 -0.0437,0.4158302 -0.1292,0.39765 -0.2091,0.3621 -0.2797,0.31072 -0.3383,0.24576 -0.382,0.17005 -0.409,0.0869 z"
+ id="path2587-4" />
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333311px;line-height:58.10250092px;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="40"
+ y="50"
+ id="text3851"><tspan
+ sodipodi:role="line"
+ x="40"
+ y="80.150925"
+ id="tspan3861"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:4.23333311px;line-height:4.76249981px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332px" /></text>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="Cut"
+ style="display:inline">
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#d3d3d3;stroke:#000000;stroke-width:0.5"
+ d="M 200,-200 H 3.9999996e-8 V 6e-6 H 200 Z m -10.209,11.989 -0.409,-0.087 -0.382,-0.17 -0.338,-0.246 -0.28,-0.31 -0.209,-0.363 -0.129,-0.397 L 188,-190 l 0.044,-0.416 0.129,-0.397 0.209,-0.363 0.28,-0.31 0.338,-0.246 0.382,-0.17 0.409,-0.087 h 0.418 l 0.409,0.087 0.382,0.17 0.338,0.246 0.28,0.31 0.209,0.363 0.129,0.397 0.044,0.416 -0.044,0.416 -0.129,0.397 -0.209,0.363 -0.28,0.31 -0.338,0.246 -0.382,0.17 -0.409,0.087 z m -180.00006,0 -0.4089799,-0.087 -0.3819599,-0.17 -0.3382703,-0.246 -0.2797699,-0.31 -0.20906,-0.363 -0.1292,-0.397 L 8,-190 l 0.0437,-0.416 0.1292,-0.397 0.20906,-0.363 0.2797699,-0.31 0.3382703,-0.246 0.3819599,-0.17 0.4089799,-0.087 H 10.209 l 0.409,0.087 0.382,0.17 0.3383,0.246 0.2797,0.31 0.2091,0.363 0.1292,0.397 L 12,-190 l -0.0437,0.416 -0.1292,0.397 -0.2091,0.363 -0.2797,0.31 -0.3383,0.246 -0.382,0.17 -0.409,0.087 z M 189.791,-8.010953 l -0.409,-0.08693 -0.382,-0.17005 -0.338,-0.245759 -0.28,-0.310721 -0.209,-0.362098 -0.129,-0.39765 -0.044,-0.41583 0.044,-0.415801 0.129,-0.397701 0.209,-0.362101 0.28,-0.3107 0.338,-0.2457 0.382,-0.170098 0.409,-0.0869 h 0.418 l 0.409,0.0869 0.382,0.170098 0.338,0.2457 0.28,0.3107 0.209,0.362101 0.129,0.397701 0.044,0.415801 -0.044,0.41583 -0.129,0.39765 -0.209,0.362098 -0.28,0.310721 -0.338,0.245759 -0.382,0.17005 -0.409,0.08693 z m -180.00006,0 L 9.3819601,-8.097883 9.0000002,-8.267935 8.6617299,-8.513693 8.38196,-8.824414 8.1729,-9.186513 8.0437,-9.584163 8,-9.999993 l 0.0437,-0.4158 0.1292,-0.397701 0.20906,-0.362101 0.2797699,-0.3107 0.3382703,-0.2457 0.3819599,-0.170098 0.4089799,-0.0869 H 10.209 l 0.409,0.0869 0.382,0.170098 0.3383,0.2457 0.2797,0.3107 0.2091,0.362101 0.1292,0.397701 0.0437,0.4158 -0.0437,0.41583 -0.1292,0.39765 -0.2091,0.362099 -0.2797,0.310721 -0.3383,0.245758 -0.382,0.170051 -0.409,0.08693 z"
+ id="path4413" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Label"
+ style="display:inline">
+ <path
+ inkscape:connector-curvature="0"
+ d="M 19.989559,-20.398378 V -180.01045 H 179.89291 v 159.612072 z"
+ style="fill:none;stroke:#000000;stroke-width:0.09319773"
+ id="path24" />
+ <path
+ inkscape:connector-curvature="0"
+ d="M 19.989559,-20.398378 H 179.89291 V -180.01046 H 19.989559 Z"
+ style="fill:none;stroke:#000000;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+ id="path62" />
+ <path
+ inkscape:connector-curvature="0"
+ d="M 99.941239,-20.398378 V -180.01046"
+ style="fill:none;stroke:#000000;stroke-width:0.09319773"
+ id="path64" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="181.06989"
+ y="28.481983"
+ id="text3292"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan3290"
+ x="181.06989"
+ y="28.481983"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">Clk</tspan></text>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-170 H 180"
+ id="path3331"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-160.00001 H 180"
+ id="path3333"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-150.00001 H 180"
+ id="path3335"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-140.00001 H 180"
+ id="path3337"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-130.00001 H 180"
+ id="path3339"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-120 H 180"
+ id="path3341"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-110.00001 H 180"
+ id="path3343"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-100.00001 H 180"
+ id="path3345"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-90.00001 H 180"
+ id="path3347"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-80.00001 H 180"
+ id="path3349"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-70.00001 H 180"
+ id="path3351"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-60.00001 H 180"
+ id="path3353"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-50.00001 H 180"
+ id="path3355"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-40.00001 H 180"
+ id="path3357"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 19.999999,-30.00001 H 180"
+ id="path3359"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.50000001;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="m 99.999999,-180.00001 -0.0588,159.601632"
+ id="path3361"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="181.07356"
+ y="38.583694"
+ id="text3292-5"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan3290-3"
+ x="181.07356"
+ y="38.583694"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">PCS </tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="181.12363"
+ y="48.325733"
+ id="text3292-51"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan3290-1"
+ x="181.12363"
+ y="48.325733"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">PCS0</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="181.07356"
+ y="58.067772"
+ id="text3292-0"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan3290-0"
+ x="181.07356"
+ y="58.067772"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">PCS0</tspan></text>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.165;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 51.461458,-194.04687 6.614584,-3.96875"
+ id="path3397"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="181.0368"
+ y="68.169487"
+ id="text3292-7"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan3290-08"
+ x="181.0368"
+ y="68.169487"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">PCI</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="181.07356"
+ y="77.911522"
+ id="text3292-1"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan3290-6"
+ x="181.07356"
+ y="77.911522"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">DPS</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="181.07356"
+ y="88.494858"
+ id="text3292-4"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan3290-14"
+ x="181.07356"
+ y="88.494858"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">DPG</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="181.07356"
+ y="98.114944"
+ id="text3292-9"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan3290-8"
+ x="181.07356"
+ y="98.114944"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">MIPS</tspan></text>
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 29.999999,-180.00001 V -170"
+ id="path3450"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 39.999999,-180.00001 V -170"
+ id="path3452"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 49.999999,-180.00001 V -170"
+ id="path3454"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 59.999999,-180.00001 V -170"
+ id="path3456"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 69.999999,-180.00001 V -170"
+ id="path3458"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 79.999999,-180.00001 V -170"
+ id="path3460"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 89.999999,-180.00001 V -170"
+ id="path3462"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 130,-180.00001 V -170"
+ id="path3464"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 140,-180.00001 V -170"
+ id="path3466"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 150,-180.00001 V -170"
+ id="path3468"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:7.40833px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="115.09582"
+ y="-189.02806"
+ id="text3474"><tspan
+ sodipodi:role="line"
+ id="tspan3472"
+ x="115.09582"
+ y="-189.02806"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0.264583px">Acc</tspan><tspan
+ sodipodi:role="line"
+ x="115.09582"
+ y="-181.61974"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0.264583px"
+ id="tspan3476">Cmd</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="181.47044"
+ y="138.28407"
+ id="text3292-9-0"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan3290-8-1"
+ x="181.47044"
+ y="138.28407"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">AccG</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="181.1319"
+ y="148.33823"
+ id="text3292-9-5"
+ transform="rotate(-90)"><tspan
+ sodipodi:role="line"
+ id="tspan3290-8-0"
+ x="181.1319"
+ y="148.33823"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">MmS</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:7.40833px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="164.21013"
+ y="-189.02806"
+ id="text3474-6"><tspan
+ sodipodi:role="line"
+ id="tspan3472-9"
+ x="164.21013"
+ y="-189.02806"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0.264583px">ALU</tspan><tspan
+ sodipodi:role="line"
+ x="164.21013"
+ y="-181.61974"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;stroke-width:0.264583px"
+ id="tspan3476-7">Get</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="17.536915"
+ y="-161.51346"
+ id="text3527"><tspan
+ sodipodi:role="line"
+ id="tspan3525"
+ x="17.536915"
+ y="-161.51346"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">Addr</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.49171"
+ y="-161.51346"
+ id="text3531"><tspan
+ sodipodi:role="line"
+ id="tspan3529"
+ x="182.49171"
+ y="-161.51346"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">Data</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="17.660936"
+ y="-151.15131"
+ id="text3527-8"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9"
+ x="17.660936"
+ y="-151.15131"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">Acc</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.87669"
+ y="-151.21538"
+ id="text3527-9"><tspan
+ sodipodi:role="line"
+ id="tspan3525-8"
+ x="182.87669"
+ y="-151.21538"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">ALU</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="17.014275"
+ y="-141.09093"
+ id="text3527-8-9"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3"
+ x="17.014275"
+ y="-141.09093"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">PC</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.47981"
+ y="-141.35551"
+ id="text3527-8-6"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36"
+ x="182.47981"
+ y="-141.35551"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">DP</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="17.03908"
+ y="-131.07811"
+ id="text3527-8-9-0"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4"
+ x="17.03908"
+ y="-131.07811"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$00</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="16.871323"
+ y="-121.28853"
+ id="text3527-8-9-0-4"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4-9"
+ x="16.871323"
+ y="-121.28853"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$02</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="16.786898"
+ y="-111.23436"
+ id="text3527-8-9-0-6"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4-6"
+ x="16.786898"
+ y="-111.23436"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$04</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="17.014275"
+ y="-101.44478"
+ id="text3527-8-9-0-41"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4-98"
+ x="17.014275"
+ y="-101.44478"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$06</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="17.014275"
+ y="-91.39061"
+ id="text3527-8-9-0-0"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4-4"
+ x="17.014275"
+ y="-91.39061"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$08</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="17.148308"
+ y="-81.607224"
+ id="text3527-8-9-0-9"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4-0"
+ x="17.148308"
+ y="-81.607224"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$0A</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="17.014275"
+ y="-71.54686"
+ id="text3527-8-9-0-5"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4-5"
+ x="17.014275"
+ y="-71.54686"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$0C</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="16.890251"
+ y="-61.228107"
+ id="text3527-8-9-0-01"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4-60"
+ x="16.890251"
+ y="-61.228107"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$0E</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="17.03908"
+ y="-51.703106"
+ id="text3527-8-9-0-2"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4-8"
+ x="17.03908"
+ y="-51.703106"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$10</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="16.891994"
+ y="-41.384357"
+ id="text3527-8-9-0-8"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4-49"
+ x="16.891994"
+ y="-41.384357"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$12</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="16.786898"
+ y="-31.85936"
+ id="text3527-8-9-0-83"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4-44"
+ x="16.786898"
+ y="-31.85936"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$14</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="17.014275"
+ y="-21.805191"
+ id="text3527-8-9-0-91"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-3-4-7"
+ x="17.014275"
+ y="-21.805191"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:end;writing-mode:lr-tb;text-anchor:end;stroke-width:0.264583px">$16</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.61574"
+ y="-131.60727"
+ id="text3527-8-6-5"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7"
+ x="182.61574"
+ y="-131.60727"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$01</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.60384"
+ y="-121.55311"
+ id="text3527-8-6-5-6"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7-2"
+ x="182.60384"
+ y="-121.55311"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$03</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.61574"
+ y="-111.23436"
+ id="text3527-8-6-5-4"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7-25"
+ x="182.61574"
+ y="-111.23436"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$05</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.61574"
+ y="-101.45097"
+ id="text3527-8-6-5-5"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7-0"
+ x="182.61574"
+ y="-101.45097"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$07</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.61574"
+ y="-91.65519"
+ id="text3527-8-6-5-52"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7-9"
+ x="182.61574"
+ y="-91.65519"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$09</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.60384"
+ y="-81.336441"
+ id="text3527-8-6-5-7"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7-7"
+ x="182.60384"
+ y="-81.336441"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$0B</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.61574"
+ y="-71.54686"
+ id="text3527-8-6-5-68"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7-1"
+ x="182.61574"
+ y="-71.54686"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$0D</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.60384"
+ y="-61.492691"
+ id="text3527-8-6-5-2"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7-03"
+ x="182.60384"
+ y="-61.492691"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$0F</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.60384"
+ y="-51.70311"
+ id="text3527-8-6-5-28"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7-74"
+ x="182.60384"
+ y="-51.70311"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$11</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.60384"
+ y="-41.384357"
+ id="text3527-8-6-5-63"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7-8"
+ x="182.60384"
+ y="-41.384357"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$13</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.60384"
+ y="-31.330193"
+ id="text3527-8-6-5-0"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7-4"
+ x="182.60384"
+ y="-31.330193"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$15</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;line-height:58.1025px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="182.61574"
+ y="-21.540609"
+ id="text3527-8-6-5-9"><tspan
+ sodipodi:role="line"
+ id="tspan3525-9-36-7-79"
+ x="182.61574"
+ y="-21.540609"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:8.46667px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px">$17</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:5.64444px;line-height:4.7625px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ x="101.1039"
+ y="-14.973572"
+ id="text3474-4"><tspan
+ sodipodi:role="line"
+ x="101.1039"
+ y="-14.973572"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:5.64444px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px"
+ id="tspan3476-4">NOP $00 LDA $02 LDA# $08 LDA() $0B STA $12 STA() $17 JMP $1D JNZ $21</tspan><tspan
+ sodipodi:role="line"
+ x="101.1039"
+ y="-10.211072"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:5.64444px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px"
+ id="tspan3888">JZE $25 ADD $29 ADD() $30 ADD# $38 SUB $3C SUB() $43 SUB# $4B</tspan><tspan
+ sodipodi:role="line"
+ x="101.1039"
+ y="-5.4485717"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:5.64444px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px"
+ id="tspan3890">AND $4F AND() $56 AND# $5E ORA $62 ORA() $69 ORA# $71 XOR $75</tspan><tspan
+ sodipodi:role="line"
+ x="101.1039"
+ y="-0.68607211"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:condensed;font-size:5.64444px;font-family:Impact;-inkscape-font-specification:'Impact, Condensed';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.264583px"
+ id="tspan126050">XOR() $7C XOR# $84 INC $88 DEC $8A ROL $8C ROR $8E INV $90</tspan></text>
+ </g>
+</svg>
diff --git a/case/dst/stl/.gitkeep b/case/dst/stl/.gitkeep
diff --git a/case/dst/svg/.gitkeep b/case/dst/svg/.gitkeep
diff --git a/case/lasercut b/case/lasercut
@@ -0,0 +1 @@
+Subproject commit 024df03077871597195a3ef78026bf80a475035d
diff --git a/doc/README.md b/doc/README.md
@@ -0,0 +1,371 @@
+Eris 2206
+---------
+
+1. Introduction
+2. Operating Eris 2206
+3. Programming
+3.1 Memory
+3.2 Assembler
+3.3 Example
+3.4 I/O and UART
+3. Hardware
+3.1 SOC
+3.2 CPU
+3.4 LED Matrix Monitor
+4. Case and Electronics
+4.1 Case
+4.2 Electronics
+5. License
+
+
+Introduction
+============
+
+[Watch the video!](https://frombelow.net/projects/eris2206/images/eris2206_demo.mp4)
+
+Eris 2206 is a front-panel programmable 8 bit computer with lots of
+Blinkenlights, implemented on an FPGA. It is not directly based on an
+existing computer design (contemporary or historic), but it takes
+inspiration from minicomputers and early microcomputers. The most
+prominent feature of Eris 2206 is its 16x16 LED display, which shows
+the internal state of the CPU and the first 24 memory addresses. The
+main mode of programming Eris 2206 is by directly writing to its 128
+bytes of RAM via front-panel switches. The 125 bytes ROM contain a
+small bootloader to load programs and data via a serial connection.
+
+
+Operating Eris 2206
+===================
+
+Eris 2206 knows three operation modes: run mode, step mode, and memory
+set mode. The mode is chosen by a three way switch. In run mode,
+execution speed is set by the speed dial next to the mode switch,
+while in step mode the step button triggers execution of the next
+micro instruction.
+
+Eris 2206 powers on when connected to a USB power supply. On power up
+in run or step mode, it starts executing the program located at the
+first ROM address, $80, which computes Fibonacci numbers.
+
+The 16x16 LED matrix shows the internal state of the CPU and the first
+RAM cells:
+
+ Row | Left Side | Right Side
+----:|:-----------------:|:------------------:
+0 | Micro Instruction | Micro Instruction
+1 | Address Bus | Data Bus
+2 | Accumulator | ALU
+3 | Program Counter | Data Pointer
+4-15 | RAM | RAM
+
+
+Programming
+===========
+
+The main mode of programming Eris 2206 is by front panel switches. For
+this, the mode switch has to be set to memory set mode. Pushing the
+reset button sets the memory address to the first address, $00. Now
+the data bus can be set via switches. Pushing the step button writes
+the current value on the data bus to the current memory address and
+advances the memory pointer. Pushing the skip button advances the
+memory pointer without writing to memory. When program and data have
+been written to memory, execution is started by setting the mode
+button to step mode and pushing the reset button. Now the program is
+executed by pushing the step button repeatedly or by switching to run
+mode.
+
+Alternatively, programs can be uploaded via the serial UART provided
+by the USB interface. For this, a minimal first-stage boot loader has
+to be programmed and executed via the front panel. This first-stage
+boot loader jumps to the second stage serial boot loader at ROM
+address $C0. The host program for serial upload is located in
+directory `src/tools/send_serial.py`. It expects hex code input.
+
+
+Memory
+------
+
+Since we have an 8 bit address bus, a total of 256 memory addresses
+are available. The lower 128 bytes are RAM. The upper 125 bytes are
+RAM. The uppermost three bytes provide memory mapped access
+to I/O and the UART.
+
+Address | Assignment
+:-------|:--------------------
+$FF | UART - Clear/Status
+$FE | UART - Send/Receive
+$FD | I/O (0..5: LEDs)
+$C0-$FC | ROM (Serial boot loader)
+$80-$BF | ROM (Fibonacci numbers)
+$00-$7F | RAM
+
+
+Assembler
+---------
+
+`src/tools/eras.pl` provides a macro assembler using CPP for macro
+processing. The directory also contains a number of example programs.
+
+The CPU knows four addressing modes:
+
+- Implicit
+
+The argument is given implicitly, e.g. INC, which adds one to the
+accumulator.
+
+- Immediate
+
+The argument is the actual value. This mode is indicated by a
+"#". Example: LDA #$5C loads the value $5C into the accumulator.
+
+- Direct
+
+The argument is the memory location of the actual value. Example: LDA
+$5C loads the value stored at memory address $5C into the accumulator.
+
+- Indirect
+
+The argument is the memory address where the memory address of the
+actual value is located. This mode is indicated by "()". Example: If
+memory address $5C contains value $3B, and memory address $3B contains
+value $67, LDA ($5C) loads $67 into the accumulator.
+
+Op. | Imp. | Imm. | Dir. | Ind. | Description
+----|------|------|------|------|:------------------------------------
+NOP | $00 | | | | No operation
+LDA | | $08 | $02 | $0B | Load accumulator
+STA | | | $12 | $17 | Store accumulator
+JMP | | | $1D | | Jump to address
+JNZ | | | $21 | | Jump if accumulator != 0
+JZE | | | $25 | | Jump if accumulator == 0
+ADD | | $38 | $29 | $30 | Add value to accumulator
+SUB | | $4B | $3C | $43 | Subtract value from accumulator
+AND | | $5E | $4F | $56 | Logical AND of accumulator and value
+ORA | | $71 | $62 | $69 | Logical OR of accumulator and value
+XOR | | $84 | $75 | $7C | Logical XOR of accumulator and value
+INC | $88 | | | | Increment accumulator
+DEC | $8A | | | | Decrement accumulator
+ROL | $8C | | | | Rotate accumulator 1 bit left
+ROR | $8E | | | | Rotate accumulator 1 bit right
+INV | $90 | | | | Invert accumulator
+
+
+Example
+-------
+
+We write a program that adds $05 and $06:
+
+```
+start:
+ LDA #$05
+ ADD #$06
+ STA :result
+ JMP :start
+result:
+```
+
+The assembler generates the following machine code for this:
+
+```
+08 05
+38 06
+12 08
+1D 00
+```
+
+In order to enter the machine code, we set the mode switch to "set",
+and push the reset button. Now we enter each byte, followed by pushing
+"step". Once we are done, we set the mode switch to step, push reset,
+and set the mode switch to run. After a number of steps, the result is
+shown memory address $08.
+
+If we want to add different numbers, we set the mode to set again,
+push reset, push skip once in order to advance to memory address $01
+without overwriting the LDA instruction, set the first new number, push
+step, push skip in order to advance to memory address $03, set the
+second new number, and set the mode switch to run.
+
+
+I/O and UART
+------------
+
+The I/O register simply maps the lowest 5 bits to the LEDs on the
+iCEstick (which are not visible, since the iCEstick is in the
+case).
+
+The UART utilizes two addresses: One address for sending and receiving
+data, and a second address for status information and to clear the
+input buffer.
+
+The byte written to address $FE is send. While the bit is transmitted,
+bit 0 of $FF is 1 (tx_busy). In order to receive a byte, the receiver
+buffer must be cleared by writing any value to $FF. Once a byte is
+received, bit 1 of $FF is 1 (recv_buffer_full). Now the byte can be
+read from $FE. In order to receive the next byte, the receive buffer
+has to be cleared again. See `src/roms/rom_uart.asm` for an example.
+
+
+Hardware
+========
+
+Eris2206 is implemented on an iCEstick FPGA Evaluation Kit. It is
+synthesized using the free tools of project
+[IceStorm](https://clifford.at/icestorm).
+
+The GPIO pins of the FPGA connect to the 16x16 (WS2811) matrix display
+and the buttons/switches. Beside some pull-down resistors, the only
+additional hardware is an NE555 multivibrator circuit providing the
+bus clock. The speed dial changes the frequency of the multivibrator.
+
+
+SOC
+---
+
+See `doc/schematic.dia` for an overview of the SOC. Besides the CPU core,
+the main peripherals are memory (RAM and ROM), the UART, and a system
+monitor providing output to a matrix of WS2811 LEDs.
+
+
+CPU
+---
+
+The following description of the internal works of the CPU should help
+you to understand the implementation in `src/ecpu.v`. It is not
+necessary to operate Eris 2206.
+
+An instance of module control_logic orchestras the components of the
+CPU. (These control lines are not shown in the schematic.) Microcode
+implementations of the opcodes govern the operation of the control
+logic. The microcode for the assembler opcodes is defined in and
+generated by `src/tools/mc_compiler.py`.
+
+The CPU has two counters and three registers:
+
+The program counter (PC) points to the next instruction/argument to
+be processed. The micro instruction pointer (MIP) points to the next
+micro instruction to be executed. These counters can be set or
+incremented.
+
+The three registers are the data pointer (DP), the accumulator, and
+the output of the arithmetic-logic unit (ALU).
+
+The accumulator is the only register visible to the user. It reads
+from and writes to external memory (and memory mapped I/O modules) via
+the data bus. In addition to read and write operations, the
+accumulator can be incremented, decremented, rotated (left and right),
+and inverted.
+
+The ALU operates on the current value of the accumulator and the
+current value on the data base, and writes back to the data bus.
+
+Like the PC, the DP does not write to the data bus, but to the address
+bus. It is used to dereference addresses in direct and indirect
+addressing mode.
+
+A zero flag, i.e. a wire indicating whether the register value is
+zero, is available for the accumulator. This flag is used by the
+comparator in order to implement the conditional jump on (not) zero
+instructions.
+
+A little bit of glue logic multiplexes the data and address line:
+Only the active component may write to the buses.
+
+Micro instructions consist of 15 bits:
+
+ Bit | Operation
+-----:|:---------------------------------------------------------------------
+ 0 | Write data bus to PC
+ 1 | Write data bus to PC if zero flag 1
+ 2 | Write data bus to PC if zero flag 1
+ 3 | Increment PC
+ 4 | Write data bus to DP
+ 5 | Write DP to address bus (write PC to address bus if bit 5 = 0)
+ 6 | Set memory address on address bus to value on data bus
+ 7 | Write accumulator to data bus
+ 8-10 | Set/increment/decrement/rotate/invert accumulator
+ 11 | Set MIP to value on data bus (increment MIP if bit 11 = 0)
+12-14 | Add/subtract/and/or/xor data bus to accumulator and write to data bus
+
+The implementation of the opcodes as micro instructions is given in
+`src/tools/mc_compiler.py`. `mc_compiler.py` compiles a ROM file of
+the micro instruction implementations of all opcodes. The machine code
+(= byte value) of an opcodes is the entry points for the microcode of
+its implementation in this ROM file. Therefore in order to decode an
+opcode, its byte code is read from the data bus and written into the
+MIP.
+
+On negative edges of the clock, the next micro instruction is set,
+i.e. components are turned on/off according to the micro
+instruction. The components operate on positive clock edges.
+
+There is a separate clock port for the UART, because the UART must be
+run at 12 MHz for timing reasons, while the rest of the SOC may run at
+a lower speed.
+
+
+LED Matrix Monitor
+------------------
+
+A 16x16 LED matrix provides a monitor view into the internals of the
+SOC. The LEDs are driven by WS2811 controllers. The control logic is
+implemented in `src/ws2811.v`. On each iteration of the internal (12
+MHz) clock of the FPGA, one 8 bit element of the monitor is updated,
+i.e. it takes 32 cycles to update the complete LED matrix. The WS2811
+driver allows to set the three color channels of each LED on or
+off. The intensity is fixed for all LEDs and color channels.
+
+
+Case and Electronics
+====================
+
+Case
+----
+
+The case has been designed in OpenSCAD. The main design file is
+`case/case.scad`. Most elements of the case can be cut from 6 mm ply
+wood with a laser cutter. Running make in directory case generates
+cutouts for a laser cutter in `case/dst/svg/`. Three elements are not
+only cut, but also engraved. Engravings have been added manually using
+Inkscape. These files for laser cutting are located in
+`case/dst/labeled`. Note that for
+`case/dst/labeled/top_plate/acryl_top_plate.svg` not 6 mm plywood, but
+an acryl plate should be cutted.
+
+The holders for the iCEstick and the circuit board are 3D printed.
+After running make in directory case/, the 3D print files are located
+in directory case/dst/stl.
+
+The case is partly glued and partly held together by M4 screws. Most
+M4 screws have nuts as counterparts, except the four screws in the
+bottom. These are held by claw nuts.
+
+Electronics
+-----------
+
+The NE555 multivibrator is housed on a small circuit board, together
+with a bunch of pull-down resistors for the switches. A Fritzing
+design file is given in board/circuit.fzz. See src/ecpu.pcf for how to
+connect the hardware components to the GPIO I/O pins.
+
+License
+=======
+
+See case/lasercut/LICENSE for author, copyright, and licensing
+information of the lasercut library.
+
+Everything else:
+
+Copyright © 2022 Gerd Beuster <gerd@frombelow.net>
+
+This project is free soft- and hardware: 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 project 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 project. If not, see <http://www.gnu.org/licenses/>.
diff --git a/doc/bom.txt b/doc/bom.txt
@@ -0,0 +1,19 @@
+- 1x iCEstick FPGA Evaluation Kit
+- 6 mm Plywood
+- 4 mm Acryl Plate
+- 3x Push Buttons - 7.2 mm diameter mounting hole
+- 8x 2 Way Switches - 6.6 mm mounting hole
+- 1x 3 Way Switch - 6.6 mm mounting hole
+- 1x Potentiometer 500 KΩ - 6.6 mm mounting hole
+- 2x 1.24 kΩ Resistors
+- 4x 3.3 kΩ Resistors
+- 3x Capacitors 100 nF
+- 1x Capacitor 2.2 µF
+- 1x NE555
+- 1x Diode
+- 1x 16x16 WS2811 matrix
+- M4 screws 10 mm
+- M4 screws 12 mm
+- M4 screws 18 mm
+- 10x M4 Nuts
+- 4x M4 Claw Nuts
diff --git a/doc/schematic.dia b/doc/schematic.dia
Binary files differ.
diff --git a/src/Makefile b/src/Makefile
@@ -0,0 +1,51 @@
+TARGET=ecpu
+INC=-I../inc
+ROMS=roms/rom.dat roms/rom_opcode_test_0.dat roms/rom_opcode_test_1.dat \
+ roms/rom_leds.dat roms/rom_uart.dat
+
+all: binary simulation
+
+binary: $(TARGET).bin
+
+%.s: %.asm
+ cpp -nostdinc -C -P -o $@ $<
+
+# Assemble programs for SOC
+%.dat: %.s tools/opcodes.pl
+ tools/eras.pl $< $@
+
+tools/opcodes.pl:
+ cd tools; python3 ./mc_compiler.py opcodes
+
+%.s: %.asm
+ cpp -nostdinc -C -P -o $@ $<
+
+# Synthesize
+%.blif: %.v main.v uart.v $(ROMS)
+ cd tools; python3 ./mc_compiler.py microcode
+ yosys -p "read_verilog $(INC) main.v; synth_ice40 -blif $@"
+
+# Place and route
+%.txt: %.blif
+ arachne-pnr -d 1k -p $(TARGET).pcf $< -o $@
+
+# Convert to bitstream
+%.bin: %.txt
+ icepack $< $@
+
+# Upload
+upload: $(TARGET).bin
+ iceprog ${ICEPROG_ARGS} $<
+
+# Simulation
+simulation: $(TARGET).v $(ROMS)
+ cd tools; python3 ./mc_compiler.py microcode
+ iverilog $(INC) -o $(TARGET).out $(TARGET)_tb.v
+ ./$(TARGET).out
+ gtkwave $(TARGET)_tb.vcd $(TARGET)_tb.gtkw
+
+clean:
+ rm -f *.txt *.bin *.blif *.out *.vcd roms/*.s $(ROMS) tools/opcodes.pl \
+ tools/microcode_rom_lsb.dat tools/microcode_rom_msb.dat
+
+.PHONY: all clean upload simulation binary
diff --git a/src/ecpu.pcf b/src/ecpu.pcf
@@ -0,0 +1,36 @@
+set_io CLK_IN 21
+set_io GREEN 95
+set_io RED_N 99
+set_io RED_E 98
+set_io RED_S 97
+set_io RED_W 96
+set_io DTR 3
+set_io RTS 7
+set_io TX 8
+set_io RX 9
+set_io PMOD_1 78
+set_io PMOD_2 79
+set_io PMOD_3 80
+set_io PMOD_4 81
+set_io PMOD_7 87
+set_io PMOD_8 88
+set_io PMOD_9 90
+set_io PMOD_10 91
+set_io WS2811_DOUT 112
+set_io SWITCH_PROGRAM 113
+set_io BUTTON_STEP 114
+set_io BUTTON_RESET 115
+set_io SWITCH_SINGLE_CONT 116
+set_io BUTTON_SKIP 117
+set_io USER_CLOCK 118
+set_io SWITCH_D0 44
+set_io SWITCH_D1 45
+set_io SWITCH_D2 47
+set_io SWITCH_D3 48
+set_io SWITCH_D4 56
+set_io SWITCH_D5 60
+set_io SWITCH_D6 61
+set_io SWITCH_D7 62
+
+
+
diff --git a/src/ecpu.v b/src/ecpu.v
@@ -0,0 +1,581 @@
+/*
+ * Copyright 2022 Gerd Beuster (gerd@frombelow.net). This is free
+ * soft-/hardware under the GNU GPL v3 license or any later
+ * version. See COPYING in the root directory for details.
+ */
+
+`ifndef ecpu_v
+ `define ecpu_v
+
+ `include "uart.v"
+ `include "ws2811.v"
+
+module esoc( // System operates at this clock speed in run mode
+ input slow_clk,
+ // Resets counters and registers, RAM is not deleted!
+ input reset_in,
+ // Switch between memory set mode andexecution mode
+ input program_mode,
+ // Single step mode or continous execution
+ input single_cont,
+ // Step trigger in single step mode, write data in
+ // set memory mode.
+ input step,
+ // Skip memory cell in set memory mode
+ input skip,
+ input [7:0] din, // Data bus input in set memory mode
+ // GPIO (LEDs)
+ output green, output red_n, output red_e, output red_s,
+ output red_w,
+ // Fast clock for timing sensitive modules (UART & WS2811)
+ input fast_clk,
+ // UART
+ output tx, input rx,
+ // WS2811
+ output ws2811_dout);
+
+ // The default ROM contains two programs:
+ //
+ // - Computation of Fibonacci numbers (at $80)
+ //
+ // This program is located at the start of the ROM, and thus gets
+ // executed on power on
+ //
+ // - Second stage bootloader (at $C0)
+ //
+ // The bootloader loads a program via the serial line. (See
+ // tools/send_serial.py for the upload program.) In order to use it,
+ // the user has to ener a minimal first stage bootloader, which
+ // jumps into this second stage bootloader, via the front panel
+ // switches.
+ parameter rom_file = "roms/rom.dat";
+
+ // This ROM shows a sequence on the built-in LEDs of the
+ // iCEstick. Since the iCEstick is embedded in the case, the LEDs
+ // are only visible when the cas is opened.
+ // parameter rom_file = "roms/rom_leds.dat";
+
+ // A serial echo program to test the UART.
+ // parameter rom_file = "roms/rom_uart.dat";
+
+ // The program to test all opcodes had to be split in two parts. As
+ // the result of each opcode test, the value $FF should be written
+ // to memory.
+ // parameter rom_file = "roms/rom_opcode_test_0.dat";
+ // parameter rom_file = "roms/rom_opcode_test_1.dat";
+
+ //
+ // Operation modes
+ //
+
+ // There are two main modes:
+ //
+ // - In execution mode, the CPU runs all components
+ //
+ // - In memory set mode, modul manual_programmer controls the
+ // address bus and the memory write line. Data input comes straight
+ // from the switches set by the user.
+ wire [7:0] data_bus, address_bus, cpu_address_bus, programmer_address_bus;
+ wire mem_set, cpu_mem_set, programmer_mem_set;
+ wire cpu_clk;
+ // In programming mode, the CPU clock is stopped. In exeuction mode, it
+ // normally runs on the slow clock, unless we are in singel step mode.
+ assign cpu_clk = program_mode ? 0 :
+ ((single_cont | reset_in) ? slow_clk : step);
+ assign mem_set = program_mode ? programmer_mem_set : cpu_mem_set;
+ assign data_bus = program_mode ? din : cpu_dout;
+ assign address_bus = program_mode ? programmer_address_bus : cpu_address_bus;
+
+ manual_programmer mp(.clk(fast_clk), .res(reset_in),
+ .step(step), .skip(skip),
+ .mem_set(programmer_mem_set),
+ .aout(programmer_address_bus));
+
+ //
+ // Glue logic: Memory mapping of peripherals
+ //
+
+ // The CPU addresses a flat memory space. Here we define glue logic
+ // to map this flat memory space to access to RAM, ROM, UART, and
+ // GPIO.
+ //
+ // The lower 5 bits of $FD turn the LEDs of the iCEstick on and off.
+
+ // hFF : UART - Write: Clear recv_buffer_full
+ // - Read: Status (0: TX busy, 1: recv_buffer_full)
+ // hFE : UART - Write: Send Data - Read: Received Data
+ // $FD : I/O (0..5: LEDs)
+ // h80-hFC : ROM
+ // h00-h7F : RAM
+
+ // Data input for the CPU may come from ROM, RAM, or UART.
+ wire [7:0] mem_dout; // CPU data (memory) input
+ // Data output of ROM, RAM, and UART
+ wire [7:0] rom_dout, ram_dout, uart_dout;
+ // Map data output to CPU data input according to memory map
+ assign mem_dout = (address_bus < 8'h80) ? ram_dout :
+ ((address_bus < 8'hFE) ? rom_dout : uart_dout);
+ wire [7:0] cpu_dout;
+ // Set correct device to write mode
+ wire ram_set, gpio_set, uart_set;
+ assign ram_set = (address_bus < 8'h80) ? mem_set : 0;
+ assign gpio_set = (address_bus == 8'hFD) ? mem_set : 0;
+ assign uart_set = (address_bus > 8'hFD) ? mem_set : 0;
+
+ //
+ // CPU and peripherals definitions
+ //
+
+ wire [15:0] control_logic;
+ wire [7:0] reg_a_value;
+ wire [7:0] alu_value;
+ wire [7:0] pc_value;
+ wire [7:0] dp_value;
+ ecpu e(.clk(cpu_clk),
+ .reset_in(reset_in),
+ .mem_dout(mem_dout),
+ .mem_set(cpu_mem_set),
+ .data_bus(cpu_dout),
+ .address_bus(cpu_address_bus),
+ .ctrl_logic_mon(control_logic),
+ .reg_a_value(reg_a_value),
+ .alu_value(alu_value),
+ .pc_value(pc_value),
+ .dp_value(dp_value));
+
+ ram ram_mem(.clk(fast_clk), .set(ram_set),
+ .din(data_bus), .dout(ram_dout), .ain(address_bus[6:0]));
+
+ rom
+ #(.rom_file(rom_file))
+ rom_mem(.clk(fast_clk), .dout(rom_dout), .ain(address_bus[6:0]));
+
+
+ gpio g(.clk(fast_clk), .din(data_bus[4:0]), .write(gpio_set),
+ .green(green), .red_n(red_n), .red_e(red_e),
+ .red_s(red_s), .red_w(red_w));
+
+ // UART reg_select is connected to the LSB of the address bus, thus
+ // mapping the two UART registers to two consequtive memory addresses.
+ // The start wire connects to the write signal of the CPU: Writing
+ // data two the UART starts transmission.
+ // The UART must be driven by a 12 Mhz clock.
+ uart u(.clk(fast_clk), .din(data_bus), .dout(uart_dout),
+ .reg_select(address_bus[0]), .write(uart_set), .tx(tx), .rx(rx));
+
+ // Monitor: Show internal state of system on LED matrix
+ `define VRAM_SIZE 32
+ led_monitor #(.vram_size(`VRAM_SIZE))
+ led_mon (.fast_clk(fast_clk),
+ .data_bus(data_bus),
+ .address_bus(address_bus),
+ .mem_set(mem_set),
+ .control_logic(control_logic),
+ .reg_a(reg_a_value),
+ .alu(alu_value),
+ // We set value to address bus in program mode in order
+ // to highlight the address currently manipulated
+ .pc(program_mode ? address_bus : pc_value),
+ .dp(dp_value),
+ .ws2811_dout(ws2811_dout));
+
+endmodule // esoc
+
+module ecpu(input clk,
+ input reset_in,
+ input [7:0] mem_dout,
+ output mem_set,
+ output [7:0] data_bus,
+ output [7:0] address_bus,
+ output [15:0] ctrl_logic_mon, // Monitor output
+ output [7:0] reg_a_value,
+ output [7:0] alu_value,
+ output [7:0] pc_value,
+ output [7:0] dp_value);
+
+ // While the control logic of the CPU operates on negative clock
+ // edges, the components operate on positive edges.
+
+ // Enable/disable lines for components
+ // PC
+ wire pc_set, pc_inc;
+ // The comperator connects microcode for conditional
+ // (pc_set_if_zero, pc_set_if_nonzero) and unconditional
+ // (pc_set_uncond) jumps to the set signal of the PC (pc_set).
+ wire pc_set_if_zero, pc_set_if_nonzero, pc_set_uncond;
+ // MIP
+ wire mip_set;
+ // DP
+ wire dp_set, dp_get;
+ // Accumulator
+ wire reg_a_get, reg_a_zero;
+ // Accumulator does not only allow setting, but more
+ // commands (inc, dec, ...).
+ wire [2:0] reg_a_cmd;
+ // ALU
+ // Three bits determine which result we get from the ALU:
+ `define alu_off 3'b000
+ `define alu_add 3'b001
+ `define alu_sub 3'b010
+ // Multiplication and division occpuy too many PLBs
+/* -----\/----- EXCLUDED -----\/-----
+ `define alu_mul 3'b011
+ `define alu_div 3'b100
+ -----/\----- EXCLUDED -----/\----- */
+ `define alu_and 3'b101
+ `define alu_or 3'b110
+ `define alu_xor 3'b111
+ wire [2:0] alu_get;
+
+ // Glue logic: Since all components may write to the buses, write
+ // access to the buses must be multiplexed.
+ wire [7:0] pc_dout, dp_dout, mip_dout, reg_a_dout, alu_dout;
+ // Multiplexer for address bus:
+ // If dp_get is set, the data pointer is loaded on the address bus.
+ // Otherwise the program counter is loaded on the address bus.
+ assign address_bus = dp_get ? dp_dout : pc_dout;
+ // Multiplexer for data bus
+ // Unless the data bus is explicitly loaded with the accumulator
+ // or the ALU, it is loaded from memory.
+ wire [7:0] alu_sum;
+ wire [7:0] alu_difference;
+ wire [7:0] alu_and;
+ wire [7:0] alu_or;
+ wire [7:0] alu_xor;
+ assign alu_value = (alu_get == `alu_add) ? alu_sum :
+ ((alu_get == `alu_sub) ? alu_difference :
+ ((alu_get == `alu_and) ? alu_and :
+ ((alu_get == `alu_or) ? alu_or :
+ ((alu_get == `alu_xor) ? alu_xor :
+ alu_sum))));
+ assign data_bus = reg_a_get ? reg_a_dout :
+ ((alu_get == `alu_off) ? mem_dout : alu_value);
+ // Monitor output
+ assign ctrl_logic_mon = { clk, pc_set_uncond, pc_set_if_zero,
+ pc_set_if_nonzero,
+ pc_inc, dp_set, dp_get,
+ mip_set, reg_a_cmd, reg_a_get,
+ mem_set, alu_get } ;
+ assign reg_a_value = reg_a_dout;
+ assign pc_value = pc_dout;
+ assign dp_value = dp_dout;
+
+ // Reset logic
+ reg res = 1;
+ always @(posedge(clk))
+ res <= reset_in;
+
+
+ control_logic ctrl (.clk(clk),
+ .res(res),
+ .pc_set_uncond(pc_set_uncond),
+ .pc_set_if_zero(pc_set_if_zero),
+ .pc_set_if_nonzero(pc_set_if_nonzero),
+ .pc_inc(pc_inc),
+ .dp_set(dp_set), .dp_get(dp_get),
+ .mip_set(mip_set),
+ .mip_value(mip_dout),
+ .reg_a_cmd(reg_a_cmd), .reg_a_get(reg_a_get),
+ .mem_set(mem_set),
+ .alu_get(alu_get));
+
+
+ // Program Counter
+ counter
+ #(.start_value(8'h80)) // Start execution in ROM
+ pc (.clk(clk), .res(res),
+ .set(pc_set), .inc(pc_inc),
+ .din(data_bus), .dout(pc_dout));
+
+ // The micro instruction pointer (mip) keeps track of the current
+ // micro instruction. It is updated from the data bus (when the
+ // next opcode is read, because opcode = pointer to begin of
+ // microcode implementation of opcode) and read by the control
+ // logic.
+ //
+ // The increment input is fixed to high, because the MIP shall
+ // always step to the next instruction always, unless a new
+ // value is set.
+ counter mip (.clk(clk), .res(res),
+ .set(mip_set), .inc(1'b1),
+ .din(data_bus), .dout(mip_dout));
+
+ // The data pointer reads from data bus and writes to the address
+ // bus. It is used to dereference memory addresses.
+ register dp (.clk(clk), .res(res),
+ .set(dp_set), .inc(1'b0), .dec(1'b0),
+ .rol(1'b0), .ror(1'b0), .inv(1'b0),
+ .din(data_bus), .dout(dp_dout));
+
+ // Accumulator
+ // The accumulator supports additional operations besides setting.
+ // We demultiplex the reg_a_cmd for this
+ wire reg_a_set, reg_a_inc, reg_a_dec, reg_a_rol,
+ reg_a_ror, reg_a_inv;
+ assign reg_a_set = (reg_a_cmd == 3'b001);
+ assign reg_a_inc = (reg_a_cmd == 3'b010);
+ assign reg_a_dec = (reg_a_cmd == 3'b011);
+ assign reg_a_rol = (reg_a_cmd == 3'b100);
+ assign reg_a_ror = (reg_a_cmd == 3'b101);
+ assign reg_a_inv = (reg_a_cmd == 3'b110);
+ register reg_a (.clk(clk), .res(res),
+ .set(reg_a_set), .inc(reg_a_inc), .dec(reg_a_dec),
+ .rol(reg_a_rol), .ror(reg_a_ror), .inv(reg_a_inv),
+ .din(data_bus), .dout(reg_a_dout), .zero(reg_a_zero));
+
+ // Comperator
+ // The program counter is set from the data bus (i.e. a jump is
+ // executed) when we execute the microcode for an unconditional
+ // jump (pc_set_uncond) or when we execute the microcode for a
+ // conditional jump (pc_set_if_zero) and the zero flag of the
+ // accumulator is set.
+ assign pc_set = pc_set_uncond | (pc_set_if_zero & reg_a_zero) |
+ (pc_set_if_nonzero & !reg_a_zero);
+
+ // ALU
+ // The ALU consists of an adder and a register. The adders gets the
+ // accumulator and the data bus as input and updates the register.
+ // The register writes to the data bus.
+ alu a(.clk(clk), .din_a(reg_a_dout), .din_b(data_bus), .sum(alu_sum),
+ .difference(alu_difference), .band(alu_and), .bor(alu_or),
+ .bxor(alu_xor));
+endmodule
+
+module counter(input clk,
+ input res,
+ input set,
+ input inc,
+ input [7:0] din,
+ output [7:0] dout);
+
+ // Start value is only set on initialization. Reset
+ // always sets counter to 0, not back to start value.
+ // By setting the start value of the PC to the first
+ // ROM address, the SOC will run from ROM on power-up,
+ // but can be programmed starting from address h00
+ // on reset.
+ parameter start_value = 8'h00;
+ reg [7:0] value;
+ reg init = 0;
+
+ assign dout = value;
+ always @(posedge(clk))
+ if (init == 0)
+ begin
+ value <= start_value;
+ init <= 1;
+ end
+ else
+ if (res)
+ value <= 8'h00;
+ else if (set)
+ value <= din;
+ else if (inc)
+ // Only increment value if no new value is set. This order is
+ // important for two reasons:
+ // - Conditional jumps always increment the PC.
+ // This should only have an effect if no new address is set.
+ // - For the MIP, inc is fixed to high. If mip_set sets a new
+ // new address, the new address should not increment immediately.
+ value <= value + 1;
+endmodule
+
+module alu(input clk, input [7:0] din_a, input [7:0] din_b,
+ output reg [7:0] sum,
+ output reg [7:0] difference,
+ output reg [7:0] band,
+ output reg [7:0] bor,
+ output reg [7:0] bxor);
+ always @(posedge(clk))
+ begin
+ sum <= din_a + din_b;
+ difference <= din_a - din_b;
+ // Multiplication and division occpuy too many PLBs
+/* -----\/----- EXCLUDED -----\/-----
+ product <= din_a * din_b;
+ quotient <= din_a / din_b;
+ -----/\----- EXCLUDED -----/\----- */
+ band <= din_a & din_b;
+ bor <= din_a | din_b;
+ bxor <= din_a ^ din_b;
+ end
+endmodule
+
+module register(input clk,
+ input res,
+ input set,
+ input inc,
+ input dec,
+ input rol,
+ input ror,
+ input inv,
+ input [7:0] din,
+ output [7:0] dout,
+ output zero);
+
+ reg [7:0] value;
+
+ assign dout = value;
+ assign zero = (value == 0);
+ always @(posedge(clk))
+ if (res)
+ value <= 8'b00000000;
+ else if (set)
+ value <= din;
+ else if (inc)
+ value <= value + 1;
+ else if (dec)
+ value <= value - 1;
+ else if (rol)
+ value <= { value[6], value[5], value[4], value[3],
+ value[2], value[1], value[0], value[7] };
+ else if (ror)
+ value <= { value[0], value[7], value[6], value[5],
+ value[4], value[3], value[2], value[1] };
+ else if (inv)
+ value <= value ^ 8'b11111111;
+endmodule
+
+// 128 byte RAM module
+module ram(input clk,
+ input set, // Write din to memory cell
+ input [7:0] din,
+ output reg [7:0] dout,
+ input [6:0] ain);
+
+ reg [7:0] mem [0:127];
+ always @(posedge(clk))
+ begin
+ if (set)
+ mem[ain] <= din;
+ dout <= mem[ain];
+ end
+endmodule
+
+// 128 byte ROM module
+module rom(input clk,
+ output reg [7:0] dout,
+ input [6:0] ain);
+
+ parameter rom_file = "roms/rom.dat";
+
+ reg [7:0] mem [0:127];
+
+ always @(posedge(clk))
+ begin
+ dout <= mem[ain];
+ end
+
+ initial
+ $readmemh(rom_file, mem);
+endmodule
+
+module gpio(input clk, input [4:0] din,
+ input write,
+ output reg green, output reg red_n, output reg red_e,
+ output reg red_s, output reg red_w);
+
+ always @(posedge(clk))
+ if (write)
+ { red_n, red_e, red_s, red_w, green} <= din;
+endmodule
+
+// All microcode is stored in array microcode_(lsb|msb). The data for
+// this arrays is generated by tools/mc_compiler.py. Pointers to the
+// microcode for an opcode are stored in array ptr_opcode_microcode.
+// These arrays are initialized upon reset.
+module control_logic(input clk, input res,
+ output reg pc_set_uncond,
+ output reg pc_set_if_zero,
+ output reg pc_set_if_nonzero,
+ output reg pc_inc,
+ output reg dp_set, dp_get,
+ output reg mip_set,
+ input [7:0] mip_value,
+ output reg mem_set,
+ output reg reg_a_get,
+ output reg [2:0] reg_a_cmd,
+ output reg [2:0] alu_get);
+
+ // Used to set all enable/disable signals in one go
+ `define execute_microcode {alu_get, \
+ mip_set, \
+ reg_a_cmd, reg_a_get, \
+ mem_set, \
+ dp_get, dp_set, \
+ pc_inc, \
+ pc_set_if_nonzero, pc_set_if_zero, pc_set_uncond}
+
+ reg [7:0] microcode_lsb [0:145];
+ reg [6:0] microcode_msb [0:145];
+
+ // Microcode for the assembler opcodes is defined in
+ // tools/mc_compiler.py. During synthesis,
+ // mc_compiler.py writes the microcode for the assembler
+ // opcodes into a ROM file, which is read here.
+ initial
+ begin
+ $readmemh("tools/microcode_rom_lsb.dat", microcode_lsb);
+ $readmemh("tools/microcode_rom_msb.dat", microcode_msb);
+ end
+
+ always @(negedge(clk))
+ if (res)
+ `execute_microcode <= 0;
+ else
+ `execute_microcode <= { microcode_msb[mip_value],
+ microcode_lsb[mip_value] };
+
+endmodule
+
+module manual_programmer(input clk, input res,
+ input step,
+ input skip,
+ output reg mem_set,
+ output reg [7:0] aout);
+ reg state;
+ // The monitor (LED matrix) does not access the system memory.
+ // Instead it listens to the address and data busses and maintainces
+ // its own memory. Since the monitor update operation either updates
+ // the registers or the memory, it may miss a memory updates if we
+ // update the memory too fast here. In order to fix this problem, the
+ // write signal is kept up for time given by write_delay.
+ reg [3:0] write_delay;
+ `define state_set_data 0
+ `define state_write_or_skip_data 1
+ initial
+ begin
+ state <= `state_set_data;
+ aout <= 8'h00;
+ mem_set <= 0;
+ end
+ always @(posedge(clk))
+ if (res)
+ begin
+ state <= `state_set_data;
+ aout <= 8'h00;
+ mem_set <= 0;
+ end
+ else
+ case (state)
+ `state_set_data:
+ if (step || skip)
+ begin
+ state <= `state_write_or_skip_data;
+ mem_set <= !skip;
+ write_delay <= -1;
+ end
+ `state_write_or_skip_data:
+ begin
+ if (write_delay == 0)
+ begin
+ mem_set <= 0;
+ state <= `state_set_data;
+ aout <= aout + 1;
+ end
+ write_delay <= write_delay - 1;
+ end
+ endcase
+endmodule
+
+`endif
diff --git a/src/ecpu_tb.gtkw b/src/ecpu_tb.gtkw
@@ -0,0 +1,68 @@
+[*]
+[*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI
+[*] Sun Aug 7 09:08:48 2022
+[*]
+[dumpfile] "/media/gb/m/projects/20210624_icestick/eris2206/src/ecpu_tb.vcd"
+[dumpfile_mtime] "Sun Aug 7 08:55:25 2022"
+[dumpfile_size] 1479207
+[savefile] "/media/gb/m/projects/20210624_icestick/eris2206/src/ecpu_tb.gtkw"
+[timestart] 0
+[size] 1920 1016
+[pos] 3 0
+*-1.320806 7 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] ecpu_tb.
+[treeopen] ecpu_tb.s.
+[treeopen] ecpu_tb.s.e.
+[treeopen] ecpu_tb.s.led_mon.
+[sst_width] 233
+[signals_width] 247
+[sst_expanded] 1
+[sst_vpaned_height] 334
+@200
+-Clock & Busses
+@28
+ecpu_tb.s.e.clk
+@22
+ecpu_tb.s.e.address_bus[7:0]
+ecpu_tb.s.e.data_bus[7:0]
+ecpu_tb.s.e.pc_dout[7:0]
+ecpu_tb.s.e.mip_dout[7:0]
+@200
+-Control
+@28
+ecpu_tb.s.e.mip_set
+ecpu_tb.s.e.pc_set
+ecpu_tb.s.e.pc_inc
+ecpu_tb.s.e.dp_get
+ecpu_tb.s.e.dp_set
+ecpu_tb.s.e.mem_set
+@29
+ecpu_tb.s.e.reg_a_set
+@28
+ecpu_tb.s.e.ctrl.reg_a_get
+ecpu_tb.s.e.pc_set_if_nonzero
+ecpu_tb.s.e.pc_set_if_zero
+ecpu_tb.s.e.pc_set_uncond
+@200
+-Accumulator
+@22
+ecpu_tb.s.e.reg_a.value[7:0]
+@200
+-ALU
+-PC
+@22
+ecpu_tb.s.e.pc.value[7:0]
+@200
+-DP
+@22
+ecpu_tb.s.e.dp.value[7:0]
+@200
+-GPIO
+@28
+ecpu_tb.s.g.green
+ecpu_tb.s.g.red_e
+ecpu_tb.s.g.red_n
+ecpu_tb.s.g.red_s
+ecpu_tb.s.g.red_w
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/src/ecpu_tb.v b/src/ecpu_tb.v
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2022 Gerd Beuster (gerd@frombelow.net). This is free
+ * soft-/hardware under the GNU GPL v3 license or any later
+ * version. See COPYING in the root directory for details.
+ */
+
+`include "ecpu.v"
+
+module ecpu_tb;
+
+ wire green, red_n, red_e, red_s, red_w;
+
+ reg clk;
+ initial clk = 0;
+ integer clk_ctr;
+ initial clk_ctr = 0;
+
+ always #1 clk = ~clk;
+ always @(posedge(clk))
+ clk_ctr <= clk_ctr +1;
+
+ esoc s (.slow_clk(clk), .fast_clk(clk),
+ .reset_in(1'b0),
+ .program_mode(1'b0),
+ .single_cont(1'b1),
+ .step(1'b0),
+ .skip(1'b0),
+ .din(8'b00000000),
+ .green(green), .red_n(red_n), .red_e(red_e), .red_s(red_s),
+ .red_w(red_w));
+
+initial begin
+ $dumpfile("ecpu_tb.vcd");
+ $dumpvars(0, ecpu_tb);
+ # 8192 $finish;
+end
+
+endmodule
diff --git a/src/main.v b/src/main.v
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2022 Gerd Beuster (gerd@frombelow.net). This is free
+ * soft-/hardware under the GNU GPL v3 license or any later
+ * version. See COPYING in the root directory for details.
+ */
+
+`include "ecpu.v"
+
+module main(input CLK_IN, // System clock (12 Mhz)
+ // External clock generated by NE555; user can set frequency.
+ // This clock is used by the CPU.
+ input USER_CLOCK,
+ // Switch to choose between continously running clock and single stepping
+ input SWITCH_SINGLE_CONT,
+ // Single step (exeuction mode) / write (programming mode) signal
+ input BUTTON_STEP,
+ input BUTTON_SKIP, // Skip memory cell (programming mode) signal
+ input BUTTON_RESET,
+ input SWITCH_PROGRAM, // Program or execute mode
+ // Manual input to data bus
+ input SWITCH_D0, SWITCH_D1, SWITCH_D2, SWITCH_D3,
+ input SWITCH_D4, SWITCH_D5, SWITCH_D6, SWITCH_D7,
+ output GREEN, output RED_N, output RED_E,
+ output RED_S, output RED_W, input RX, output TX,
+ output WS2811_DOUT);
+
+ wire button_step_debounced, button_skip_debounced;
+ debouncer deb0(.clk(CLK_IN), .button(BUTTON_STEP), .debounced(button_step_debounced));
+ debouncer deb1(.clk(CLK_IN), .button(BUTTON_SKIP), .debounced(button_skip_debounced));
+
+ // The SOC uses two clocks: The internal 12 Mhz clock of the
+ // iCEstick is used for updating the WS2811 LED matrix and for
+ // timing serial communication. An external, user-supplied clock
+ // generated by an NE555 is used for running the CPU. The speed of
+ // this clock can be set via the speed dial. Since the high and low
+ // phases of the external clock have different length, we use a prescaler
+ // to "convert" some to same length phases.
+ wire slow_clk;
+ prescaler #(.bits(1)) B1(.clk_in(USER_CLOCK), .clk_out(slow_clk));
+
+ esoc s(.slow_clk(slow_clk), .fast_clk(CLK_IN),
+ .reset_in(BUTTON_RESET),
+ .program_mode(SWITCH_PROGRAM),
+ .single_cont(SWITCH_SINGLE_CONT),
+ .step(button_step_debounced),
+ .skip(button_skip_debounced),
+ .din({ !SWITCH_D7, !SWITCH_D6, !SWITCH_D5, !SWITCH_D4,
+ !SWITCH_D3, !SWITCH_D2, !SWITCH_D1, !SWITCH_D0 }),
+ .green(GREEN), .red_n(RED_N), .red_e(RED_E), .red_s(RED_S),
+ .red_w(RED_W),
+ .tx(TX), .rx(RX), .ws2811_dout(WS2811_DOUT));
+
+endmodule
+
+module debouncer(input clk, input button, output reg debounced);
+
+ parameter delay = 20;
+
+ reg [delay:0] debounce_timer;
+ always @(posedge(clk))
+ begin
+ if (button && (debounce_timer == 0))
+ begin
+ debounced <= 1;
+ debounce_timer <= -1;
+ end
+ else
+ begin
+ if (debounce_timer > 0)
+ debounce_timer <= debounce_timer - 1;
+ debounced <= 0;
+ end
+ end
+endmodule
+
+module prescaler(input clk_in, output clk_out);
+
+ parameter bits = 24;
+ reg [bits-1:0] c = 0;
+
+ assign clk_out = c[bits-1];
+
+ always @(posedge(clk_in))
+ c <= c + 1;
+
+endmodule
diff --git a/src/roms/rom.asm b/src/roms/rom.asm
@@ -0,0 +1,93 @@
+//
+// Fibonacci numbers
+//
+
+#define DATA_PTR_0 $15
+#define DATA_PTR_1 $16
+#define DATA_PTR_2 $17
+ .set_address $80
+ // Set initial values
+ LDA #$00
+ STA $00
+ LDA #$01
+ STA $01
+initialize_data_pointers:
+ LDA #$00
+ STA DATA_PTR_0
+ LDA #$01
+ STA DATA_PTR_1
+ LDA #$02
+ STA DATA_PTR_2
+loop:
+ // Compute next value
+ LDA (DATA_PTR_0)
+ ADD (DATA_PTR_1)
+ STA (DATA_PTR_2)
+ // Increment pointers
+ // DATA_PTR_0
+ LDA DATA_PTR_0
+ // Check if we have reached
+ // the end of visible RAM
+ ADD #$EC // (-20 % 255) + 1
+ JNZ :DATA_PTR_0_in_range
+ LDA #$EB // Set accumulator to #$EB + #$16 = 00
+DATA_PTR_0_in_range:
+ ADD #$15 // Increment accumulator by #$EC + #$15 - 1 = 1
+ STA DATA_PTR_0
+ // DATA_PTR_1
+ LDA DATA_PTR_1
+ // Check if we have reached
+ // the end of visible RAM
+ ADD #$EC // (-20 % 255) + 1
+ JNZ :DATA_PTR_1_in_range
+ LDA #$EB // Set accumulator to #$EB + #$16 = 00
+DATA_PTR_1_in_range:
+ ADD #$15 // Increment accumulator by #$EC + #$15 - 1 = 1
+ STA DATA_PTR_1
+ // DATA_PTR_2
+ LDA DATA_PTR_2
+ // Check if we have reached
+ // the end of visible RAM
+ ADD #$EC // (-20 % 255) + 1
+ JNZ :DATA_PTR_2_in_range
+ LDA #$EB // Set accumulator to #$EB + #$16 = 00
+DATA_PTR_2_in_range:
+ ADD #$15 // Increment accumulator by #$EC + #$15 - 1 = 1
+ STA DATA_PTR_2
+ JMP :loop
+
+//
+// Load RAM from serial line
+//
+
+#define UART_STATUS $FF
+#define UART_DATA $FE
+#define DATA_PTR $7F
+#define MASK_RECV_BUFFER_FULL $FE
+#define MASK_TX_BUSY $FF
+start:
+ // Start writing serial data at begin of RAM
+ LDA #$00
+ STA DATA_PTR
+ STA UART_STATUS // Clear recv_buffer_full; ready to receive next byte.
+receive_loop:
+ LDA UART_STATUS
+ AND #$02
+ JZE :receive_loop
+ // Byte received.
+ // Store it in RAM and advance data pointer.
+ LDA UART_DATA
+ STA (DATA_PTR)
+ LDA DATA_PTR
+ INC
+ STA DATA_PTR
+ STA UART_STATUS // Clear recv_buffer_full
+ // Confirm reception of byte
+ LDA #$AA
+ STA UART_DATA
+ // Wait until byte sent
+send_loop:
+ LDA UART_STATUS
+ AND #$01
+ JNZ :send_loop
+ JMP :receive_loop
diff --git a/src/roms/rom_leds.asm b/src/roms/rom_leds.asm
@@ -0,0 +1,16 @@
+#define LEDS $FD
+#define START_VALUE $00
+#define COUNTER $01
+ .set_address $80
+ LDA #$20
+ STA START_VALUE
+start:
+ LDA START_VALUE
+ STA COUNTER
+loop:
+ LDA COUNTER
+ ADD #$FF
+ STA COUNTER
+ STA LEDS
+ JNZ :loop
+ JZE :start
diff --git a/src/roms/rom_opcode_test_0.asm b/src/roms/rom_opcode_test_0.asm
@@ -0,0 +1,61 @@
+ // Test all opcodes
+ .set_address $80
+ // LDA, STA & NOP
+ // Result should be $FF in $00..$03
+ LDA #$FF
+ STA $00
+ LDA #$00
+ LDA $00
+ STA $01
+ LDA #$01
+ NOP
+ STA $7F
+ NOP
+ LDA ($7F)
+ NOP
+ STA $02
+ NOP
+ LDA #$03
+ STA $7F
+ NOP
+ LDA #$FF
+ NOP
+ STA ($7F)
+ // STA
+ LDA #$FF
+ // ADD
+ // Result should be $FF in $04..$06
+ LDA #$FE
+ ADD #$01
+ STA $04
+ LDA #$01
+ STA $7F
+ LDA #$FE
+ ADD $7F
+ STA $05
+ LDA #$02
+ STA $7E
+ LDA #$7E
+ STA $7F
+ LDA #$FD
+ ADD ($7F)
+ STA $06
+ // Test rest of ALU
+ // Result should be $FF in $07..$0A
+ LDA #$04
+ SUB #$05
+ STA $07
+ LDA #$FF
+ AND #$0F
+ ADD #$F0
+ STA $08
+ LDA #$0F
+ ORA #$F0
+ STA $09
+ LDA #$05
+ XOR #$0F
+ SUB #$0B
+ STA $0A
+end:
+ LDA $0B
+ JMP :end
diff --git a/src/roms/rom_opcode_test_1.asm b/src/roms/rom_opcode_test_1.asm
@@ -0,0 +1,56 @@
+ // Test all opcodes
+ .set_address $80
+ // Accumulator manipulation
+ LDA #$FE
+ INC
+ STA $00
+ LDA #$00
+ DEC
+ STA $01
+ LDA #$FE
+ ROL
+ ORA #$02
+ STA $02
+ LDA #$FB
+ ROR
+ ORA #$02
+ STA $03
+ LDA #$00
+ INV
+ STA $04
+ // Jump commands
+ // Result should be $FF in $05..$07
+ // JMP
+ LDA #$FF
+ JMP :skip1
+ LDA #$01
+skip1:
+ STA $05
+ // JNZ
+ JNZ :skip2
+ LDA #$01
+skip2:
+ STA $06
+ // JZE
+ JZE :skip3
+ STA $07
+ JMP :skip4
+skip3:
+ LDA #$01
+ STA $07
+skip4:
+ // Program execution from RAM
+ // Result should be $FF in $08
+ LDA #$1D // JMP
+ STA $7E
+ LDA #:skip6
+ STA $7F
+ JMP $7E
+skip5:
+ JMP :skip5
+skip6:
+ LDA #$FF
+ STA $08
+end:
+ LDA $09
+ JMP :end
diff --git a/src/roms/rom_uart.asm b/src/roms/rom_uart.asm
@@ -0,0 +1,25 @@
+#define UART_STATUS $FF
+#define UART_DATA $FE
+#define LEDS $FD
+.set_address $80
+start:
+ STA UART_STATUS // Clear recv_buffer_full; ready to receive next byte
+receive_loop:
+ LDA UART_STATUS
+ STA LEDS
+ ADD :mask_recv_buffer_full // A is 0 if recv_buffer_full
+ JNZ :receive_loop
+ LDA UART_DATA
+ // Echo byte
+ STA UART_DATA
+ // Wait until byte sent
+send_loop:
+ LDA UART_STATUS
+ ADD :mask_tx_busy_and_recv_buffer_full // A is 0 if tx_busy and recv_buffer_full
+ JZE :send_loop
+ // Start over
+ JMP :start
+mask_recv_buffer_full:
+ $FE
+mask_tx_busy_and_recv_buffer_full:
+ $FD
diff --git a/src/tools/eras.pl b/src/tools/eras.pl
@@ -0,0 +1,276 @@
+#!/usr/bin/env -S swipl --quiet
+
+% This is an assembler for the Eris SOC. The program takes two command
+% line arguments: The first argument is the assembler program. Second
+% argument is the target binary.
+%
+% Besides writing the target file, the assembler outputs the
+% result. Lines in the output start with the current memory
+% adress. Opcodes are followed by their binary representation in round
+% brackets. Label references are followed by their memory location in
+% square brackets.
+%
+% The assembler knows one directive: .start_of_rom sets the
+% current memory address to $80. This is the start address of the ROM.
+% In order to assemble a program stored in ROM, this directive should
+% precede the actual code.
+%
+% Copyright 2022 Gerd Beuster (gerd@frombelow.net). This is free soft
+% under the GNU GPL v3 license or any later version. See COPYING in
+% the root directory for details.
+
+
+%
+% Load opcodes generated by microcode compiler.
+%
+
+:- consult("opcodes.pl").
+
+
+:- use_module(library(dcg/basics)).
+
+% The actual main predicate. The output file is only written if the
+% assembly was successful.
+assemble_file(SourceFile, TargetFile) :-
+ read_file_to_string(SourceFile, S, []),
+ string_to_list(S, L),
+ % Step 1: Tokenize the input
+ tokenize(1, _, Parsed, L, []),
+ % Step 2: Assemble it
+ assemble(Assembled, labels{}, Labels, 0, _, Parsed, []),
+ % Step 3: De-reference labels
+ dereferenceLabels(Assembled, Final, Labels),
+ !,
+ % Write result
+ get_binary(Final, Binary),
+ !,
+ check_for_errors(Binary),
+ save_binary(TargetFile, Binary),
+ write("$00: "),
+ print_map(Final, []).
+
+% We write a hex file as output.
+save_binary(TargetFile, Binary) :-
+ open(TargetFile, write, S),
+ write_hex(S, Binary),
+ close(S).
+write_hex(_, []).
+write_hex(S, [F|R]) :-
+ format(S, '~|~`0t~16R~2+ ', F),
+ write_hex(S, R).
+
+% If the list of binary values resulting from assembly contains
+% the atom 'error', then an error occured in the assembly process.
+check_for_errors([]).
+check_for_errors([error|_]) :- !, fail.
+check_for_errors([_|R]) :- check_for_errors(R).
+
+% Write source code together with binary representation to standard
+% out.
+print_map --> print_command, print_map.
+print_map --> print_command.
+print_command --> [(newline, _, bytePosition(BytePos), _)],
+ { format('\n$~|~`0t~16R~2+: ', [BytePos]) }.
+print_command --> [(labelDefinition(L), _, _, _)],
+ { format('~w:', L) }.
+print_command --> [(opcode(P), _, _, assembly(A))],
+ { format(' ~w [$~|~`0t~16R~2+]', [P, A]) }.
+print_command --> [(number(N, direct), _, _, _)],
+ { format(' $~|~`0t~16R~2+', [N]) }.
+print_command --> [(number(N, immediate), _, _, _)],
+ { format(' #$~|~`0t~16R~2+', [N]) }.
+print_command --> [(number(N, indirect), _, _, _)],
+ { format(' ($~|~`0t~16R~2+)', [N]) }.
+print_command --> [(comment(C), _, _, _)],
+ { format(' //~w', [C]) }.
+print_command --> [(labelReference(E, direct), _, _, assembly(A))],
+ { format(' :~w [$~|~`0t~16R~2+]', [E, A]) }.
+print_command --> [(labelReference(E, immediate), _, _, assembly(A))],
+ { format(' #:~w [$~|~`0t~16R~2+]', [E, A]) }.
+print_command --> [(labelReference(E, indirect), _, _, assembly(A))],
+ { format(' (:~w [$~|~`0t~16R~2+])', [E, A]) }.
+print_command --> [(assembler_directive(D), _, _, _)],
+ { format('.~w', [D]) }.
+
+% The result of the assembly is a list of tokens augmented by their
+% binary representation. Here we remove everything but the binary
+% representation from the list elements, resulting in a sequence of
+% bytes.
+get_binary([], []).
+get_binary([(_, _, _, assembly(A))|R], [A|B]) :-
+ get_binary(R, B).
+get_binary([(_, _, _, assembly())|R], B) :-
+ get_binary(R, B).
+
+
+% Predicate assemble is the parser. It takes the tuples returned
+% by the tokenizer and augments them by the corresponding byte
+% representation in term assembly/1.
+%
+% When translating the tokens to their byte representation, a list of
+% labels and their representation in memory is created. These
+% variables have names like L0 and L1, for the labels before/after a
+% token is processed. In order to associate the labels with their
+% memory location, we keep track of the current memory location in the
+% way in varaibles named like B0 (processing the next token) and B1
+% (processing the next token). The actual variable names may vary.
+
+assemble(A, L0, L2, B0, B2) -->
+ command(F, L0, L1, B0, B1),
+ assemble(R, L1, L2, B1, B2),
+ { append(F, R, A) }.
+assemble(F, L0, L1, B0, B1) --> command(F, L0, L1, B0, B1).
+
+% Newslines and comments do not generate assembler code.
+command([(newline, lineNumber(N), bytePosition(B), assembly())],
+ L, L, B, B) -->
+ [(newline, lineNumber(N))].
+command([(comment(S), lineNumber(N), bytePosition(B), assembly())],
+ L, L, B, B) -->
+ [(comment(S), lineNumber(N))].
+% Label references are replaced by the (1 byte) address of the label,
+% therefore the byte counter advances by 1. The symbolic label is
+% stored as the "byte code" in assembly/1. In the second pass, these
+% references are resolved by the number representing the absolute
+% position.
+command([(labelReference(S, M), lineNumber(N), bytePosition(B), assembly(S))],
+ L, L, B, B1) -->
+ [(labelReference(S, M), lineNumber(N))],
+ { B1 is B + 1 }.
+% Number are very similar to label references. The difference is that
+% we can already generate assemble code for them; no future
+% de-referencing required.
+command([(number(X, M), lineNumber(N), bytePosition(B), assembly(X))],
+ L, L, B, B1) -->
+ [(number(X, M), lineNumber(N))],
+ { B1 is B + 1 }.
+% Label definitions refer to the current byte position. We store the
+% association of label and byte position.
+command([(labelDefinition(S), lineNumber(N), bytePosition(B), assembly())],
+ L, L.put(S, B), B, B) -->
+ [(labelDefinition(S), lineNumber(N))].
+% Opcodes may or may not be followed by an argument (number or label
+% reference). Since the argument indicates the addressing mode of the
+% opcode, we have to parse them together.
+% - Two byte opcodes
+command([(opcode(S), lineNumber(LN0), bytePosition(B), assembly(OpByte)),
+ (number(X, M), lineNumber(LN1), bytePosition(B1), assembly(X))],
+ L, L, B, B2) -->
+ [(opcode(S), lineNumber(LN0)),
+ (number(X, M), lineNumber(LN1))],
+ { opcode_to_byte(S, M, OpByte),
+ B1 is B + 1,
+ B2 is B + 2 }.
+command([(opcode(S), lineNumber(LN0), bytePosition(B), assembly(OpByte)),
+ (labelReference(X, M), lineNumber(LN1), bytePosition(B1), assembly(X))],
+ L, L, B, B2) -->
+ [(opcode(S), lineNumber(LN0)),
+ (labelReference(X, M), lineNumber(LN1))],
+ { opcode_to_byte(S, M, OpByte),
+ B1 is B + 1,
+ B2 is B + 2 }.
+% - One byte opcodes
+command([(opcode(S), lineNumber(LN0), bytePosition(B), assembly(OpByte))],
+ L, L, B, B1) -->
+ [(opcode(S), lineNumber(LN0))],
+ { opcode_to_byte(S, OpByte),
+ B1 is B + 1 }.
+% - Unkown opcodes
+command([(opcode(S), lineNumber(LN0), bytePosition(B), assembly(error))],
+ L, L, B, B) -->
+ [(opcode(S), lineNumber(LN0))],
+ { format('ERROR: Unknown opcode/addressing mode "~w" (line ~w)\n', [S, LN0]) }.
+% Compiler directive set_address changes the current byte address. It
+% does not generate any assembly code on its own.
+command([(assembler_directive("set_address"), lineNumber(LN0), bytePosition(B1),
+ assembly()),
+ (number(B2, direct), lineNumber(LN1), bytePosition(B1), assembly())],
+ L, L, B1, B2) -->
+ [(assembler_directive("set_address"), lineNumber(LN0)),
+ (number(B2, direct), lineNumber(LN1))].
+
+% At this point, the assembly code is a list of bytes interspersed
+% with label references. Here we replace the label references by the
+% corresponding memory location.
+dereferenceLabels([], [], _).
+dereferenceLabels([(labelReference(L, M), lineNumber(N), bytePosition(P),
+ assembly(L))|RL],
+ [(labelReference(L, M), lineNumber(N), bytePosition(P),
+ assembly(B))|R],
+ Labels) :-
+ get_dict(L, Labels, B),
+ dereferenceLabels(RL, R, Labels).
+dereferenceLabels([(labelReference(L, M), lineNumber(N), assembly(L))|RL],
+ [(labelReference(L, M), lineNumber(N), assembly(error))|R],
+ Labels) :-
+ format('ERROR: Unknown label "~w" (line ~w)\n', [L, N]),
+ dereferenceLabels(RL, R, Labels).
+dereferenceLabels([F|R], [F|RD], L) :-
+ dereferenceLabels(R, RD, L).
+
+% The tokenizer knows the following tokens:
+% newline, comment, labelReference, labelDefinition, number, and
+% opcode. The differen tokens are identified as follows:
+% - Comments start with '//' and end at the end of the line.
+% - Labels end with ':'.
+% - Label references begin with ':'.
+% - Numbers begin with '$'.
+% - Everything else is an opcode.
+% We store the line number of the token with the token for error reporting.
+
+% LNum0 and LNum1 keep track of line numbers: LNum0 is the line number
+% before parsing the next token, LNum1 is the line number after
+% parsing the next token.
+tokenize(LNum0, LNum1, [T]) --> token(LNum0, LNum1, T).
+tokenize(LNum0, LNum2, [T|R]) -->
+ token(LNum0, LNum1, T), tokenize(LNum1, LNum2, R).
+% When we parse a new line, the line number is incremented.
+token(LNum0, LNum1, (newline, lineNumber(LNum0))) -->
+ whites, [10], {LNum1 is LNum0 + 1}.
+% Parse assembler directives
+token(LNum, LNum, (assembler_directive(A), lineNumber(LNum))) -->
+ whites, [0'.], string_without("\n \t", L), { string_to_list(A, L) }.
+% Parse comments
+token(LNum, LNum, (comment(C), lineNumber(LNum))) -->
+ whites, [0'/], [0'/], string_without("\n", L), { string_to_list(C, L) }.
+% Label references - direct addressing
+token(LNum, LNum, (labelReference(A, direct), lineNumber(LNum))) -->
+ whites, [0':], string_without("\n \t", L),
+ { string_to_list(S, L), atom_string(A, S) }.
+% Label references - immediate addressing
+token(LNum, LNum, (labelReference(A, immediate), lineNumber(LNum))) -->
+ whites, [0'#], [0':], string_without("\n \t", L),
+ { string_to_list(S, L), atom_string(A, S) }.
+% Label references - indirect addressing
+token(LNum, LNum, (labelReference(A, indirect), lineNumber(LNum))) -->
+ whites, [0'(], [0':], string_without("\n \t", L), [0')],
+ { string_to_list(S, L), atom_string(A, S) }.
+% Label definitions
+token(LNum, LNum, (labelDefinition(A), lineNumber(LNum))) -->
+ whites, string_without("\r\n \t:", L), [0':],
+ { string_to_list(S, L), atom_string(A, S) }.
+% Parse numbers - direct addressing mode
+token(LNum, LNum, (number(N, direct), lineNumber(LNum))) -->
+ whites, [0'$], xinteger(N).
+% Parse numbers - immediate addressing mode
+token(LNum, LNum, (number(N, immediate), lineNumber(LNum))) -->
+ whites, [0'#], [0'$], xinteger(N).
+% Parse numbers - indirect addressing mode
+token(LNum, LNum, (number(N, indirect), lineNumber(LNum))) -->
+ whites, [0'(], [0'$], xinteger(N), [0')].
+% Everything not parsed yet is an opcode
+token(LNum, LNum, (opcode(P), lineNumber(LNum))) -->
+ whites, string_without("\n \t", L), { string_to_list(P, L) }.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+:- initialization(main, main).
+
+main([Source, Binary]) :-
+ !,
+ assemble_file(Source, Binary),
+ nl.
+
+main(_) :-
+ writeln('Usage: eras.pl <SOURCE> <BINARY>').
diff --git a/src/tools/mc_compiler.py b/src/tools/mc_compiler.py
@@ -0,0 +1,342 @@
+#!/usr/bin/env python3
+
+# Copyright 2022 Gerd Beuster (gerd@frombelow.net). This is free soft
+# under the GNU GPL v3 license or any later version. See COPYING in
+# the root directory for details.
+
+import sys
+
+pc_set_uncond = 1 << 0
+pc_set_if_zero = 1 << 1
+pc_set_if_nonzero = 1 << 2
+pc_inc = 1 << 3
+dp_set = 1 << 4
+dp_get = 1 << 5
+mem_set = 1 << 6
+reg_a_get = 1 << 7
+reg_a_set = 0b001 << 8
+reg_a_inc = 0b010 << 8
+reg_a_dec = 0b011 << 8
+reg_a_rol = 0b100 << 8
+reg_a_ror = 0b101 << 8
+reg_a_inv = 0b110 << 8
+mip_set = 1 << 11
+alu_add = 0b001 << 12
+alu_sub = 0b010 << 12
+# Multiplication and division occpuy too many PLBs
+# alu_mul = 0b011 << 12
+# alu_div = 0b100 << 12
+alu_and = 0b101 << 12
+alu_or = 0b110 << 12
+alu_xor = 0b111 << 12
+
+# Loading the address bus
+#
+# In every cycle, the CPU loads the address bus with either
+# the value of the program counter or the data pointer.
+# Therefore we only need dp_get, a flag indicating if the address bus
+# loads the data pointer. If this flag is not set, the address bus
+# loads the program counter.
+
+# Loading the data bus
+#
+# In every cycle, the CPU loads the data bus with either
+# the value from accumulator, the memory, or the alu.
+# Accumulator access has priority. If reg_a_get is not set,
+# the data bus is loaded from the ALU if alu_... is set and from memory
+# otherwise.
+
+# Summary:
+
+# - Unless dp_get is set, the address bus is loaded from the PC on every
+# instruction.
+# - If neither alu_... nor reg_a_get is set, the data bus is loaded
+# from memory on every instructions
+#
+# Therefore microcode 0 loads the data bus with the memory location
+# given by the PC.
+
+opcode = [['NOP',
+ [
+ # First instruction implicitly loads address bus with PC
+ # and reads memory at that location. The memory content is loaded on the data bus in the next step,
+ # and the MIP is set from the data bus.
+ # The PC is incremented such that the operand of the
+ # next instruction can be fetched in the next step
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['LDA', 'direct',
+ [
+ # We want to load from the memory address pointed to
+ # by the PC. We read the memory address (i.e. the pointer value) ...
+ 0,
+ # ... and store it DP.
+ dp_set,
+ # Now we transfer this value to the address bus, read this memory
+ # address ...
+ dp_get,
+ # ... and store it in the accumulator. We also increment
+ # the PC such that we can fetch the next instruction
+ # and the following step.
+ dp_get | reg_a_set | pc_inc,
+ # We are done. Fetch next instruction and increment PC such that
+ # the next instruction can load its argument.
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['LDA', 'immediate',
+ [
+ reg_a_set | pc_inc,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['LDA', 'indirect',
+ [
+ 0,
+ dp_set,
+ dp_get | dp_set,
+ dp_get,
+ dp_get | reg_a_set | pc_inc,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['STA', 'direct',
+ [
+ 0,
+ dp_set,
+ dp_get | mem_set | reg_a_get | pc_inc,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['STA', 'indirect',
+ [
+ 0,
+ dp_set,
+ dp_get | dp_set,
+ dp_get | mem_set |reg_a_get | pc_inc,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['JMP', 'direct',
+ [
+ 0,
+ pc_set_uncond,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['JNZ', 'direct',
+ [
+ 0,
+ pc_inc | pc_set_if_nonzero,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['JZE', 'direct',
+ [
+ 0,
+ pc_inc | pc_set_if_zero,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['ADD', 'direct',
+ [
+ 0,
+ dp_set,
+ dp_get,
+ dp_get,
+ alu_add | pc_inc | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['ADD', 'indirect',
+ [
+ 0,
+ dp_set,
+ dp_get | dp_set,
+ dp_get,
+ dp_get,
+ pc_inc | alu_add | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['ADD', 'immediate',
+ [
+ 0,
+ alu_add | pc_inc | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['SUB', 'direct',
+ [
+ 0,
+ dp_set,
+ dp_get,
+ dp_get,
+ alu_sub | pc_inc | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['SUB', 'indirect',
+ [
+ 0,
+ dp_set,
+ dp_get | dp_set,
+ dp_get,
+ dp_get,
+ pc_inc | alu_sub | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['SUB', 'immediate',
+ [
+ 0,
+ alu_sub | pc_inc | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['AND', 'direct',
+ [
+ 0,
+ dp_set,
+ dp_get,
+ dp_get,
+ alu_and | pc_inc | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['AND', 'indirect',
+ [
+ 0,
+ dp_set,
+ dp_get | dp_set,
+ dp_get,
+ dp_get,
+ pc_inc | alu_and | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['AND', 'immediate',
+ [
+ 0,
+ alu_and | pc_inc | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['ORA', 'direct',
+ [
+ 0,
+ dp_set,
+ dp_get,
+ dp_get,
+ alu_or | pc_inc | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['ORA', 'indirect',
+ [
+ 0,
+ dp_set,
+ dp_get | dp_set,
+ dp_get,
+ dp_get,
+ pc_inc | alu_or | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['ORA', 'immediate',
+ [
+ 0,
+ alu_or | pc_inc | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['XOR', 'direct',
+ [
+ 0,
+ dp_set,
+ dp_get,
+ dp_get,
+ alu_xor | pc_inc | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['XOR', 'indirect',
+ [
+ 0,
+ dp_set,
+ dp_get | dp_set,
+ dp_get,
+ dp_get,
+ pc_inc | alu_xor | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['XOR', 'immediate',
+ [
+ 0,
+ alu_xor | pc_inc | reg_a_set,
+ 0,
+ pc_inc | mip_set,
+ ]],
+ ['INC',
+ [
+ reg_a_inc,
+ pc_inc | mip_set,
+ ]],
+ ['DEC',
+ [
+ reg_a_dec,
+ pc_inc | mip_set,
+ ]],
+ ['ROL',
+ [
+ reg_a_rol,
+ pc_inc | mip_set,
+ ]],
+ ['ROR',
+ [
+ reg_a_ror,
+ pc_inc | mip_set,
+ ]],
+ ['INV',
+ [
+ reg_a_inv,
+ pc_inc | mip_set,
+ ]],
+]
+
+if len(sys.argv) != 2:
+ sys.stderr.write("Usage: mc_compiler.py microcode|opcode\n")
+ sys.exit(-1)
+
+if sys.argv[1] == 'microcode':
+ # Since ROM data has a width of 8 bit, we split the microcode into two
+ # rom files.
+ with open('microcode_rom_lsb.dat', 'w') as r_lsb:
+ r_lsb.write('// Microcode - LSB\n')
+ with open('microcode_rom_msb.dat', 'w') as r_msb:
+ r_msb.write('// Microcode - MSB\n')
+ byte_count = 0
+ for o in opcode:
+ r_lsb.write('// {}\n'.format(o[0]))
+ r_msb.write('// {}\n'.format(o[0]))
+ r_lsb.write("".join(["{:02X} ".format(x & 0xFF) for x in o[-1]]) + "\n")
+ r_msb.write("".join(["{:02X} ".format(x >> 8) for x in o[-1]]) + "\n")
+ byte_count += len(o[1])
+ r_lsb.write('// Number of instructions: {}\n'.format(byte_count))
+ r_msb.write('// Number of instructions: {}\n'.format(byte_count))
+
+
+if sys.argv[1] == 'opcodes':
+ byte_count = 0
+ with open('opcodes.pl', 'w') as f:
+ f.write(':- discontiguous opcode_to_byte/2.\n')
+ for o in opcode:
+ if(len(o) == 2):
+ # Opcode without addressing mode
+ f.write('opcode_to_byte("{}", {}).\n'.format(o[0], byte_count))
+ else:
+ # Opcode with addressing mode
+ f.write('opcode_to_byte("{}", {}, {}).\n'.format(o[0], o[1], byte_count))
+ byte_count += len(o[-1])
diff --git a/src/tools/send_serial.py b/src/tools/send_serial.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+
+# Copyright 2022 Gerd Beuster (gerd@frombelow.net). This is free soft
+# under the GNU GPL v3 license or any later version. See COPYING in
+# the root directory for details.
+
+import sys
+import serial
+import time
+
+PORT = '/dev/ttyUSB1'
+SPEED = 115200
+
+def send_file(filename):
+ s = serial.Serial(PORT, SPEED)
+ with open(filename, "r") as f:
+ for line in f:
+ line_as_bytes = map(lambda x: int(x, 16), filter(lambda x: x != '', line.split(" ")))
+ for b in line_as_bytes:
+ print("{:02X}".format(b))
+ time.sleep(.1)
+ s.write(bytes([b]))
+ assert(s.read(1) == b'\xaa')
+
+if __name__ == '__main__':
+ send_file(filename=sys.argv[1])
diff --git a/src/uart.v b/src/uart.v
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2022 Gerd Beuster (gerd@frombelow.net). This is free
+ * soft-/hardware under the GNU GPL v3 license or any later
+ * version. See COPYING in the root directory for details.
+ */
+
+`ifndef uart_v
+ `define uart_v
+
+// In order to send a byte, din is set to the byte to be send and
+// write is set to 1. While transmitting, bit 0 of the status register
+// is 1.
+//
+// In order to receive a byte, the receive buffer must be cleared by
+// writing to the status register. Once the byte is received, bit 1 of
+// the status register is set to 1.
+
+module uart(input clk, // 12 Mhz system clock
+ // Data to be send via the serial line is read from din.
+ input [7:0] din,
+ // When reg_select is set to 0 (see below), dout carries
+ // the last byte received via the serial line.
+ // When reg_select is set to 1, dout carries the current bits:
+ // Bit 0: The UART is in the process of sending the byte at din
+ // Bit 1: The UART received a byte.
+ output [7:0] dout,
+ // When reg_select is set to 0 (see below), setting write to 1
+ // starts serial transmission of din.
+ // When reg_select is set to 1, setting write to 1 clears
+ // the receive buffer.
+ input write,
+ // 0: Data Register
+ // 1: Status register
+ input reg_select,
+ // Connections to hardware lines
+ output reg tx,
+ input rx);
+
+ reg [9:0] tx_buffer; // Internal transmit buffer (start bit, data, stop bit)
+ reg [7:0] rx_buffer; // Internal receive buffer
+ reg [7:0] received_byte; // Last complete byte received
+ reg [7:0] bit_time_tx; // Clock ticks until bit transmitted
+ reg [3:0] curr_bit_tx; // Index of bit currently transmitted
+ reg rx_busy;
+ reg tx_busy;
+ wire recv_buffer_full;
+
+ parameter ticks_per_bit = 104; // Clock ticks per bit for 115200 bps @ 12 Mhz
+
+ assign dout = reg_select ? {6'b000000, recv_buffer_full, tx_busy} : received_byte;
+
+ initial
+ begin
+ tx_busy <= 0;
+ tx <= 1;
+ curr_bit_tx <= 0;
+ rx_busy <= 0;
+ end
+
+ /*
+ * Transmitter
+ *
+ */
+
+ always @(posedge(clk))
+ begin
+ // Begin of transmission
+ if (write && !reg_select && !tx_busy)
+ // Transmissions starts on write operation to data register:
+ // Fill the internal transmit buffer, and get busy.
+ begin
+ tx_buffer <= {1'b1, din, 1'b0};
+ curr_bit_tx <= 0;
+ bit_time_tx <= ticks_per_bit;
+ tx_busy <= 1;
+ end
+ // End of transmission
+ if (curr_bit_tx == 10)
+ begin
+ // Keep tx high will not transmitting.
+ tx <= 1;
+ // If the CPU clock is significangtly slower than the
+ // system clock, write may still be high. In order to
+ // avoid sending the same byte again, we only set tx_busy
+ // to low when write is low as well.
+ if(!write)
+ begin
+ tx_busy <= 0;
+ curr_bit_tx <= 0;
+ end
+ end // if (curr_bit_tx == 10)
+ else
+ // In transmission
+ begin
+ if (tx_busy)
+ // Output current bit
+ begin
+ tx <= tx_buffer[curr_bit_tx];
+ bit_time_tx <= bit_time_tx - 1;
+ end
+ if (bit_time_tx == 0)
+ // Switch to next bit
+ begin
+ curr_bit_tx <= curr_bit_tx + 1;
+ bit_time_tx <= ticks_per_bit;
+ end
+ end
+ end // always @ (posedge(clk))
+
+ /*
+ * Receiver
+ *
+ */
+
+ reg [7:0] bit_time_rx; // Clock ticks until bit received
+ reg [3:0] curr_bit_rx; // Index of bit currently received
+
+ assign recv_buffer_full = (curr_bit_rx == 9);
+ always @(posedge(clk))
+ begin
+ if (write && reg_select)
+ curr_bit_rx <= 0;
+ else
+ begin
+ if (!rx_busy && !rx)
+ begin
+ // Start receving once we get the start bit
+ rx_busy <= 1;
+ curr_bit_rx <= 0;
+ // bit_time_rx hits 0 in the middle
+ // of the first data bit
+ bit_time_rx <= ticks_per_bit * 1.5;
+ end
+ else if ((curr_bit_rx == 9) && rx)
+ begin
+ // If this is the stop bit, we are done
+ rx_busy <= 0;
+ received_byte <= rx_buffer;
+ end
+ else if ((rx_busy) && (bit_time_rx == 0))
+ // We are in the middle of the next bit.
+ begin
+ // Read it
+ rx_buffer[curr_bit_rx] <= rx;
+ curr_bit_rx <= curr_bit_rx + 1;
+ bit_time_rx <= ticks_per_bit;
+ end
+ else
+ bit_time_rx <= bit_time_rx - 1;
+ end
+ end // always @ (posedge(clk))
+
+endmodule
+
+`endif
diff --git a/src/ws2811.v b/src/ws2811.v
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2022 Gerd Beuster (gerd@frombelow.net). This is free
+ * soft-/hardware under the GNU GPL v3 license or any later
+ * version. See COPYING in the root directory for details.
+ */
+
+`ifndef ws2811_v
+ `define ws2811_v
+
+// Module led_monitor uses a number of sub-modules:
+//
+// - Module vram listens to the CPU internals and the busses in order
+// to keep track of the system state, including memory value. (System
+// memory is not tapped but mirrored by listening to the busses and
+// write operations.)
+//
+// - Module bit2pixel converts 3 bit GRB data to 24 bits GRB data
+// suitable for the WS2811 LED matrix.
+//
+// - Module ws2811 sends the sequence of 24 bits GRB data to the LED
+// matrix in WS2811 protocol.
+
+module led_monitor(input fast_clk,
+ // Memory content is mirrored for monitoring
+ // purposes by listening to data and address bus
+ input [7:0] data_bus,
+ input [7:0] address_bus,
+ input mem_set,
+ // Input of CPU debugging output
+ input [15:0] control_logic,
+ input [7:0] reg_a,
+ input [7:0] alu,
+ input [7:0] pc,
+ input [7:0] dp,
+ // Data line of WS2811 matrix
+ output ws2811_dout);
+
+ // Each row of the 16x16 matrix represents two bytes,
+ // therefore the size of the video RAM of the matrix
+ // is 32 bytes
+ parameter vram_size = 32;
+ // WS2811 timing
+ parameter cycles_t0h = 4; // 0: Cycles for high
+ parameter cycles_t0l = 13; // 0: Cycles for low
+ parameter cycles_t1h = 13; // 1: Cycles for high
+ parameter cycles_t1l = 4; // 1: Cycles for low
+ parameter cycles_reset = 4000; // Cycles for rest
+
+ // The output of the video RAM is fed into bit2pixel in order to
+ // convert video RAM data into pixel values for the LED matrix.
+ wire [2:0] vram_dout;
+ // vram_next requests the next bit from video ram. Video ram sets
+ // vram_eod when video ram transfer is completed.
+ wire vram_next, vram_eod;
+ vram #(.size(vram_size))
+ vram_mem (.din(data_bus),
+ .ain(address_bus),
+ .mem_set(mem_set),
+ .control_logic(control_logic),
+ .reg_a(reg_a),
+ .alu(alu),
+ .pc(pc),
+ .dp(dp),
+ .vclk(fast_clk),
+ .veod(vram_eod), .vnext(vram_next),
+ .vout(vram_dout));
+ // bs_next requests to set bs_dout to the next pixel. bs_eod
+ // indicates that all pixels have been transmitted.
+ wire bs_next, bs_dout, bs_eod;
+ bit2pixel b2p (.clk(fast_clk),
+ .vram_din(vram_dout), .vram_eod(vram_eod),
+ .vram_next(vram_next),
+ .dout_next(bs_next), .dout(bs_dout),
+ .dout_eod(bs_eod));
+ // ws2811 translates the bit values of pixels to the high/low
+ // signals of the WS2811 protocol.
+ ws2811 #(.cycles_t0h(cycles_t0h), .cycles_t0l(cycles_t0l),
+ .cycles_t1h(cycles_t1h), .cycles_t1l(cycles_t1l),
+ .cycles_reset(cycles_reset))
+ ws (.clk(fast_clk),
+ .din(bs_dout),
+ .next(bs_next),
+ .eod(bs_eod), .dout(ws2811_dout));
+endmodule
+
+// The input interface of the VRAM connects to the databus, the output
+// interface to WS2811. The output interface is not random access but
+// provides a bitstream.
+module vram(// VRAM input interfaces to read internal state
+ input [7:0] din,
+ input [7:0] ain,
+ input mem_set, // Write din to memory cell
+ input [15:0] control_logic, // All control logic flags
+ input [7:0] reg_a,
+ input [7:0] alu,
+ input [7:0] pc,
+ input [7:0] dp,
+ // VRAM interface for video output
+ input vclk,
+ input vnext, // Dump next bit
+ output reg veod,
+ output reg [2:0] vout // Stream output
+ );
+
+ parameter size = 32;
+
+ reg [7:0] mem [0:size-1];
+ reg [$clog2(size)-1:0] v_byte_ptr = 0;
+ reg [2:0] v_bit_ptr = 0;
+ reg [7:0] byte_out;
+
+ // The LED matrix is wired in snake wiring, ain_snake allows us to
+ // access memory cells in the usual left-to-right, row-by-row
+ // order. We still have to remember that the order of LEDs in the
+ // memory cells in every other row is reversed.
+ wire [7:0] ain_snake;
+ assign ain_snake = (((ain % 4) == 0) ?
+ (ain + 9)
+ : (((ain % 4) == 1) ?
+ (ain + 7)
+ : (ain + 8)));
+ wire [$clog2(size)-1:0] v_byte_ptr_snake;
+ assign v_byte_ptr_snake = (((v_byte_ptr % 4) == 0) ?
+ (v_byte_ptr - 7)
+ : (((v_byte_ptr % 4) == 1) ?
+ (v_byte_ptr - 9)
+ : (v_byte_ptr - 8)));
+
+ // When using BRAM, we can only write one cell on each
+ // cycle. Therefore we have to split VRAM updates into a number of
+ // cycles. The output will only be accurate if the bus clock is
+ // much slower than the VRAM clock that all VRAM parts are updated
+ // in one bus clock cycle.
+ `define state_update_control_logic_0 0
+ `define state_update_control_logic_1 1
+ `define state_update_address_bus 2
+ `define state_update_data_bus 3
+ `define state_update_accumulator 4
+ `define state_update_alu 5
+ `define state_update_pc 6
+ `define state_update_dp 7
+ `define state_update_mem 8
+ reg [3:0] state = `state_update_control_logic_0;
+ always @(posedge(vclk))
+ case (state)
+ `state_update_control_logic_0:
+ begin
+ mem[0] <= control_logic[7:0];
+ state <= `state_update_control_logic_1;
+ end
+ `state_update_control_logic_1:
+ begin
+ mem[1] <= { 1'b0, control_logic[15:8] };
+ state <= `state_update_address_bus;
+ end
+ `state_update_address_bus:
+ begin
+ mem[2] <= { ain[0], ain[1], ain[2], ain[3], ain[4], ain[5], ain[6], ain[7] };
+ state <= `state_update_data_bus;
+ end
+ `state_update_data_bus:
+ begin
+ mem[3] <= { din[0], din[1], din[2], din[3], din[4], din[5], din[6], din[7] };
+ state <= `state_update_accumulator;
+ end
+ `state_update_alu:
+ begin
+ mem[4] <= alu;
+ state <= `state_update_pc;
+ end
+ `state_update_accumulator:
+ begin
+ mem[5] <= reg_a;
+ state <= `state_update_alu;
+ end
+ `state_update_pc:
+ begin
+ mem[6] <= { pc[0], pc[1], pc[2], pc[3], pc[4], pc[5], pc[6], pc[7] };
+ state <= `state_update_dp;
+ end
+ `state_update_dp:
+ begin
+ mem[7] <= { dp[0], dp[1], dp[2], dp[3], dp[4], dp[5], dp[6], dp[7] };
+ state <= `state_update_mem;
+ end
+ `state_update_mem:
+ begin
+ if (mem_set && (ain <= (size - 9)))
+ // We are in the phase for updating memory, and
+ // the memory in the range shown is written. Therefore we update it.
+ if ((ain % 4) > 1)
+ // While ain_snake de-mangles the order of memory cells, we still have
+ // to reverse the bit order of the memory cells in every other row due
+ // to the snake wiring.
+ mem[ain_snake] <= {din[0], din[1], din[2], din[3],
+ din[4], din[5], din[6], din[7] };
+ else
+ mem[ain_snake] <= din;
+ state <= `state_update_control_logic_0;
+ end
+ endcase
+
+
+ // Output interface: Dump memory as bitstream for output on LED array.
+ always @(posedge(vclk))
+ begin
+ byte_out <= mem[v_byte_ptr];
+ vout <= ((v_byte_ptr < 2) ?
+ // First row shows bits of control logic
+ ((v_bit_ptr % 2 == 0) ?
+ // Alternate colors when showing control logic bits
+ { 1'b0, byte_out[v_bit_ptr], 1'b0 }
+ : { 1'b0, 1'b0 , byte_out[v_bit_ptr] })
+ : ((v_byte_ptr < 8) ?
+ // Registers & busses
+ ((v_byte_ptr % 2 == 0) ?
+ // In alternating colors
+ { 1'b0, byte_out[v_bit_ptr], 1'b0 }
+ : { 1'b0, 1'b0, byte_out[v_bit_ptr] })
+ :
+ // Memory content shown in blue. In order to
+ // indicate the location of the PC and the DP,
+ // non-set bits of the memory cell pointed to by
+ // the PC and DP are colored in the respective
+ // color.
+ { byte_out[v_bit_ptr],
+ ((v_byte_ptr_snake == pc) && (byte_out[v_bit_ptr] == 1'b0)) ? 1'b1 : 1'b0,
+ ((v_byte_ptr_snake == dp) && (byte_out[v_bit_ptr] == 1'b0)) ? 1'b1 : 1'b0
+ }));
+ veod <= ((v_bit_ptr == 7) && (v_byte_ptr == (size - 1)));
+ // Advance to next output bit
+ if (vnext)
+ begin
+ // Memory is organized as bytes, so we may have to
+ // advance to the next byte when all bits of the current
+ // bit have been output.
+ // Note that we do not set v_byte_ptr and v_bit_ptr explicitly
+ // back to 0 when a complete byte has been output; we simply let
+ // it overflow.
+ if (v_bit_ptr == 7)
+ v_byte_ptr <= v_byte_ptr + 1;
+ v_bit_ptr <= v_bit_ptr + 1;
+ end
+ end // always @ (posedge(vclk))
+endmodule
+
+// Takes a stream of bit triples representing 3 bit GRB color values.
+// These triplets are translated to a 24 bit GRB value as input for
+// the ws2811 input stream by module ws2811.
+module bit2pixel(input clk,
+ // Interface to VRAM
+ input [2:0] vram_din,
+ input vram_eod,
+ output reg vram_next,
+ // Interface to WS2811
+ output reg dout,
+ output reg dout_eod,
+ input dout_next);
+
+ parameter LED_INTENSITY = 3; // Intensity of LED; range [1..7]
+ reg init = 0;
+ // Color of output bit
+ reg [1:0] dout_color;
+ // Position of output bit in output byte
+ reg [2:0] dout_bit;
+
+ always @(posedge(clk))
+ if (init == 0)
+ begin
+ init <= 1;
+ dout_eod <= 0;
+ dout <= 0;
+ dout_color <= 0;
+ dout_bit <= 0;
+ end
+ else
+ begin
+ // Each input bit is translated to 3 colors of 8 bits
+ // intensity. We output 0 unless we output the desired color
+ // in the desired intensity.
+ dout <= (dout_bit == 8-LED_INTENSITY) ? vram_din[dout_color] : 0;
+ dout_eod <= ((vram_eod) && (dout_color == 2) &&
+ (dout_bit == 7));
+ if (dout_next)
+ begin
+ if (dout_bit == 7)
+ // 8 bit have been output. Switch to next color
+ // channel.
+ if(dout_color == 2)
+ begin
+ dout_color <= 0;
+ // Since all colors have been output, the output
+ // for this bit from VRAM is complete and we
+ // request the next one.
+ vram_next <= 1;
+ end
+ else
+ dout_color <= dout_color + 1;
+ // Since width of dout_bit is 3 bit, it runs
+ // over bits 0..7
+ dout_bit <= dout_bit + 1;
+ end // if (dout_next)
+ else
+ vram_next <= 0;
+ end
+
+endmodule
+
+module ws2811(input clk, input din, input eod, output reg next, output reg dout);
+
+ // One clock cycle @ 12 Mhz:
+ // 83.3333 ns
+
+ // Protocol
+
+ // https://www.tme.eu/Document/26d574b43ad9ddaffa4d5bcd140ec145/WS2811.pdf
+ // Send order: GRB, MSB First
+ // 0: High 220 ns ~ 380 ns | Low 580 ns ~ 1600 ns
+ // 1: High 580 ns ~ 1600 ns | Low 220 ns ~ 420 ns
+ // Frame length: 800 ns ~ 1980 ns
+ // Reset: > 280000 ns
+ parameter cycles_t0h = 4; // 0: Cycles for high
+ parameter cycles_t0l = 13; // 0: Cycles for low
+ parameter cycles_t1h = 13; // 1: Cycles for high
+ parameter cycles_t1l = 4; // 1: Cycles for low
+ parameter cycles_reset = 4000; // Cycles for rest
+
+ `define state_reset 0
+ `define state_high 1
+ `define state_low 2
+ reg [1:0] state_ptr;
+ reg [15:0] cycles_counter;
+
+ reg init = 0;
+
+ always @(posedge(clk))
+ if (init == 0)
+ begin
+ init <= 1;
+ state_ptr <= `state_reset;
+ cycles_counter <= cycles_reset;
+ dout <= 0;
+ next <= 0;
+ end
+ else
+ begin
+ cycles_counter <= cycles_counter + 1;
+ next <= 0;
+ // In state_reset, dout is kept low in order to initate
+ // a new transmission of color values for all LEDs. After
+ // that, we alternate between state_high and state_low,
+ // sending each color value bit by PWM. Each cycle
+ // represents a bit: The length of the high/low phases
+ // depends on the bit value.
+ case (state_ptr)
+ `state_reset:
+ if (cycles_counter == cycles_reset)
+ begin
+ state_ptr <= `state_high;
+ cycles_counter <= 0;
+ dout <= 1;
+ end
+ `state_high:
+ if (cycles_counter == ((din == 1'b1) ?
+ cycles_t1h-1 : cycles_t0h-1))
+ begin
+ state_ptr <= `state_low;
+ cycles_counter <= 0;
+ dout <= 0;
+ end
+ `state_low:
+ if (cycles_counter == ((din == 1'b1) ?
+ cycles_t1l-1 : cycles_t0l-1))
+ begin
+ if (eod)
+ // When all bits are send, we are done and start over.
+ begin
+ state_ptr <= `state_reset;
+ cycles_counter <= 0;
+ dout <= 0;
+ end
+ else
+ // Transmit next bit
+ begin
+ state_ptr <= `state_high;
+ cycles_counter <= 0;
+ dout <= 1;
+ end // else: !if(eod)
+ next <= 1;
+ end
+ endcase // case (state_ptr)
+ end
+
+endmodule
+
+`endif