]> cloudbase.mooo.com Git - z180-stamp.git/commitdiff
Merge branch 'chan-fatfs' into fatfs-integration
authorLeo C <erbl259-lmu@yahoo.de>
Sun, 27 May 2018 22:33:58 +0000 (00:33 +0200)
committerLeo C <erbl259-lmu@yahoo.de>
Sun, 27 May 2018 22:33:58 +0000 (00:33 +0200)
# Conflicts:
# fatfs/source/diskio.h
# fatfs/source/integer.h
# fatfs/src/integer.h
# fatfs/src/option/ccsbcs.c
# include/avr/ffconf.h
# include/integer.h

148 files changed:
.gitmodules [new file with mode: 0644]
COPYING [new file with mode: 0644]
TODO.md [new file with mode: 0644]
Tupfile.ini [new file with mode: 0644]
Tuprules.tup [new file with mode: 0644]
avr/Tupfile [new file with mode: 0644]
avr/background.c [new file with mode: 0644]
avr/bcd.c [new file with mode: 0644]
avr/cli.c [new file with mode: 0644]
avr/cli_readline.c [new file with mode: 0644]
avr/cmd_attach.c [new file with mode: 0644]
avr/cmd_boot.c [new file with mode: 0644]
avr/cmd_date.c [new file with mode: 0644]
avr/cmd_fat.c [new file with mode: 0644]
avr/cmd_gpio.c [new file with mode: 0644]
avr/cmd_help.c [new file with mode: 0644]
avr/cmd_loadcpm3.c [new file with mode: 0644]
avr/cmd_loadihex.c [new file with mode: 0644]
avr/cmd_mem.c [new file with mode: 0644]
avr/cmd_misc.c [new file with mode: 0644]
avr/cmd_run.c [new file with mode: 0644]
avr/cmd_sd.c [new file with mode: 0644]
avr/command.c [new file with mode: 0644]
avr/command_tbl.c [new file with mode: 0644]
avr/con-utils.c [new file with mode: 0644]
avr/debug.c [new file with mode: 0644]
avr/env.c [new file with mode: 0644]
avr/eval_arg.c [new file with mode: 0644]
avr/getopt-min.c [new file with mode: 0644]
avr/gpio.c [new file with mode: 0644]
avr/i2c.c [new file with mode: 0644]
avr/main.c [new file with mode: 0644]
avr/mmc.c [new file with mode: 0644]
avr/pcf8583.c [new file with mode: 0644]
avr/print-utils.c [new file with mode: 0644]
avr/serial.c [new file with mode: 0644]
avr/timer.c [new file with mode: 0644]
avr/xmalloc.c [new file with mode: 0644]
avr/z180-serv.c [new file with mode: 0644]
avr/z80-if.c [new file with mode: 0644]
configs/default.config [new file with mode: 0644]
configs/gcc.tup [new file with mode: 0644]
configs/m1281-debug.config [new file with mode: 0644]
configs/m2561-debug.config [new file with mode: 0644]
fatfs/source/diskio.h.dist [moved from fatfs/source/diskio.h with 100% similarity]
fatfs/source/ffconf.h.dist [moved from fatfs/source/ffconf.h with 100% similarity]
include/avr/ffconf.h [new file with mode: 0644]
include/background.h [new file with mode: 0644]
include/bcd.h [new file with mode: 0644]
include/cli.h [new file with mode: 0644]
include/cli_readline.h [new file with mode: 0644]
include/cmd_mem.h [new file with mode: 0644]
include/command.h [new file with mode: 0644]
include/common.h [new file with mode: 0644]
include/con-utils.h [new file with mode: 0644]
include/config.h [new file with mode: 0644]
include/crc.h [new file with mode: 0644]
include/debug.h [new file with mode: 0644]
include/diskio.h [new file with mode: 0644]
include/env.h [new file with mode: 0644]
include/eval_arg.h [new file with mode: 0644]
include/ff.h [new symlink]
include/ffconf.h [new file with mode: 0644]
include/getopt-min.h [new file with mode: 0644]
include/gpio.h [new file with mode: 0644]
include/i2c.h [new file with mode: 0644]
include/integer.h [new file with mode: 0644]
include/print-utils.h [new file with mode: 0644]
include/ring.h [new file with mode: 0644]
include/rtc.h [new file with mode: 0644]
include/serial.h [new file with mode: 0644]
include/spi.h [new file with mode: 0644]
include/time.h [new symlink]
include/timer.h [new file with mode: 0644]
include/xmalloc.h [new file with mode: 0644]
include/z180-serv.h [new file with mode: 0644]
include/z80-if.h [new file with mode: 0644]
time/Files.am [new file with mode: 0644]
time/Makefile [new file with mode: 0644]
time/Makefile.am [new file with mode: 0644]
time/Makefile.in [new file with mode: 0644]
time/Rules.am [new file with mode: 0644]
time/asc_store.c [new file with mode: 0644]
time/asctime.c [new file with mode: 0644]
time/asctime_r.c [new file with mode: 0644]
time/ctime.c [new file with mode: 0644]
time/ctime_r.c [new file with mode: 0644]
time/daylight_seconds.c [new file with mode: 0644]
time/difftime.c [new file with mode: 0644]
time/dst_pointer.c [new file with mode: 0644]
time/ephemera_common.h [new file with mode: 0644]
time/equation_of_time.c [new file with mode: 0644]
time/fatfs_time.c [new file with mode: 0644]
time/geo_location.c [new file with mode: 0644]
time/gm_sidereal.c [new file with mode: 0644]
time/gmtime.c [new file with mode: 0644]
time/gmtime_r.c [new file with mode: 0644]
time/isLeap.c [new file with mode: 0644]
time/iso_week_date.c [new file with mode: 0644]
time/iso_week_date_r.c [new file with mode: 0644]
time/isotime.c [new file with mode: 0644]
time/isotime_r.c [new file with mode: 0644]
time/lm_sidereal.c [new file with mode: 0644]
time/localtime.c [new file with mode: 0644]
time/localtime_r.c [new file with mode: 0644]
time/mk_gmtime.c [new file with mode: 0644]
time/mktime.c [new file with mode: 0644]
time/month_length.c [new file with mode: 0644]
time/moon_phase.c [new file with mode: 0644]
time/print_lz.c [new file with mode: 0644]
time/set_dst.c [new file with mode: 0644]
time/set_position.c [new file with mode: 0644]
time/set_system_time.c [new file with mode: 0644]
time/set_zone.c [new file with mode: 0644]
time/solar_declination.c [new file with mode: 0644]
time/solar_noon.c [new file with mode: 0644]
time/strftime.c [new file with mode: 0644]
time/sun_rise.c [new file with mode: 0644]
time/sun_set.c [new file with mode: 0644]
time/system_tick.S [new file with mode: 0644]
time/system_time.c [new file with mode: 0644]
time/time.c [new file with mode: 0644]
time/time.h [new file with mode: 0644]
time/tm_store.c [new file with mode: 0644]
time/utc_offset.c [new file with mode: 0644]
time/week_of_month.c [new file with mode: 0644]
time/week_of_year.c [new file with mode: 0644]
z180/Makefile [new file with mode: 0644]
z180/Tupfile [new file with mode: 0644]
z180/asci-p.180 [new file with mode: 0644]
z180/asci1-i.180 [new file with mode: 0644]
z180/bioscio.180 [new file with mode: 0644]
z180/cfboot.180 [new file with mode: 0644]
z180/chario.180 [new file with mode: 0644]
z180/conbuf-a.180 [new file with mode: 0644]
z180/config.inc [new file with mode: 0644]
z180/console.180 [new file with mode: 0644]
z180/ddtz.180 [new file with mode: 0644]
z180/fifoio.180 [new file with mode: 0644]
z180/init-80.180 [new file with mode: 0644]
z180/init.180 [new file with mode: 0644]
z180/modebaud.inc [new file with mode: 0644]
z180/msgbuf-a.180 [new file with mode: 0644]
z180/msgbuf-s.180 [new file with mode: 0644]
z180/msgfifo.180 [new file with mode: 0644]
z180/romend.180 [new file with mode: 0644]
z180/z180.lib [new file with mode: 0644]
z180/z180reg.inc [new file with mode: 0644]

diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  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
+this service 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 make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  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.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+                     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
+convey 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 2 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, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision 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, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This 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.
diff --git a/TODO.md b/TODO.md
new file mode 100644 (file)
index 0000000..75c9679
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,10 @@
+TODO List
+=========
+
+- TODO: eliminate xmalloc
+- TODO: build time directory as lib
+- TODO: file search path. 'cd' command?
+- TODO: increase __malloc_margin to ? (now 0x20)
+----------------------------------------------------
+- Done:
+       - command 'help <topic>' should return success
diff --git a/Tupfile.ini b/Tupfile.ini
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/Tuprules.tup b/Tuprules.tup
new file mode 100644 (file)
index 0000000..185c6bf
--- /dev/null
@@ -0,0 +1,3 @@
+.gitignore
+TOP = $(TUP_CWD)
+
diff --git a/avr/Tupfile b/avr/Tupfile
new file mode 100644 (file)
index 0000000..d41de25
--- /dev/null
@@ -0,0 +1,120 @@
+include_rules
+
+PROG           = stamp-monitor
+
+FATFS  = $(TOP)/fatfs/src/ff.c
+
+SRC            = main.c
+SRC            += cli.c cli_readline.c command.c command_tbl.c
+SRC            += cmd_help.c cmd_run.c cmd_boot.c cmd_misc.c
+SRC            += cmd_date.c cmd_mem.c cmd_gpio.c cmd_attach.c
+SRC            += cmd_loadihex.c cmd_loadcpm3.c cmd_sd.c cmd_fat.c
+SRC            += env.c xmalloc.c con-utils.c print-utils.c
+SRC            += getopt-min.c eval_arg.c
+SRC            += timer.c serial.c i2c.c bcd.c pcf8583.c mmc.c
+SRC            += background.c z180-serv.c z80-if.c gpio.c
+SRC            += $(FATFS) $(TOP)/fatfs/src/option/unicode.c
+
+#TODO: time lib
+SRC            += ../time/asctime_r.c ../time/gmtime_r.c ../time/mk_gmtime.c
+SRC            += ../time/print_lz.c ../time/isLeap.c
+SRC            += ../time/time.c ../time/fatfs_time.c
+SRC            += ../time/system_time.c ../time/set_system_time.c
+
+ASRC   += ../time/system_tick.S
+
+SRC_Z          = ../z180/hdrom.c ../z180/cfboot.c
+
+#TARGETS       = $(PROG).elf
+
+ifdef MCU
+  MCU_TARGET = @(MCU)
+else
+  MCU_TARGET = atmega1281
+endif
+ifeq ($(MCU_TARGET),atmega1281)
+  DEFS         += -DMCU_STRING=\"ATmega1281\"
+else
+  DEFS         += -DMCU_STRING=\"ATmega2561\"
+endif
+
+F_CPU          = 18432000UL
+DEFS           += -DF_CPU=$(F_CPU)
+
+INCLUDES += -I$(TOP)/include
+
+#INCLUDES += -I../z180
+
+###############################################################################
+
+TOOLCHAINDIR   =
+TOOLCHAIN      = avr
+
+CC     = $(TOOLCHAIN)-gcc
+LD     = $(TOOLCHAIN)-gcc
+AR     = $(TOOLCHAIN)-ar
+AS     = $(TOOLCHAIN)-as
+OBJCOPY        = $(TOOLCHAIN)-objcopy
+OBJDUMP        = $(TOOLCHAIN)-objdump
+SIZE   = $(TOOLCHAIN)-size
+GDB    = $(TOOLCHAIN)-gdb
+
+###############################################################################
+
+ifdef DEBUG
+SRC    += debug.c
+DEFS   += -DDEBUG=2
+endif
+
+CFLAGS = -g -Os
+CFLAGS += -mmcu=$(MCU_TARGET)
+CFLAGS += -std=gnu99
+CFLAGS += -Wall -Wextra
+CFLAGS += -Wredundant-decls
+CFLAGS += -mrelax
+CFLAGS += -fno-common
+CFLAGS += -ffunction-sections
+CFLAGS += -fdata-sections
+CFLAGS += -fno-tree-loop-optimize
+CFLAGS += -fno-move-loop-invariants
+CFLAGS += -fno-split-wide-types
+#CFLAGS        += -flto
+CFLAGS += -fshort-enums
+
+#CFLAGS        +=  -fdiagnostics-color=always
+#CFLAGS        += -save-temps -fverbose-asm
+
+CFLAGS_$(FATFS)        = -fno-strict-aliasing
+
+CFLAGS += $(INCLUDES)
+
+CPPFLAGS += $(DEFS)
+
+#ASFLAGS += -Wa,-adhlns=$(<:.S=.lst),-gstabs
+ASFLAGS += -mmcu=$(MCU_TARGET) -x assembler-with-cpp $(ASFLAGS)
+
+# Linker flags
+LDFLAGS        += -Wl,--gc-sections
+LDFLAGS        += -Wl,--cref
+
+# Assemble: create object files from assembler source files.
+#.S.o:
+#      $(CC) -c $(ALL_ASFLAGS) $< -o $@
+
+
+!as = |> ^ AS %f^ $(CC) $(ASFLAGS) -c %f -o %o |> %B.o
+!cc = |> ^ CC %f^ $(CC) $(CFLAGS) $(CPPFLAGS) $(CFLAGS_%f) -c %f -o %o |> %B.o
+#!cc = |> ^ CC %f^ $(CC) $(CFLAGS) $(CPPFLAGS) $(CFLAGS_%f) -c %f -o %o |> %B.o | %B.s %B.i
+!LINK = |> ^ LINK %o^ $(LD) $(CFLAGS) $(LDFLAGS) -Wl,-Map=%O.map %f $(LDLIBS) -o %o |> | %O.map
+!OBJCOPY= |> ^ OBJCOPY %o^ $(OBJCOPY) -Oihex %f %o |>
+!OBJDUMP= |> ^ OBJDUMP %o^ $(OBJDUMP) -h -S %f > %o |> %O.lss
+!SIZE = |> ^ SIZE^ $(SIZE) %f |>
+
+: foreach $(ASRC) |> !as |>  {objs}
+: foreach $(SRC) | ../z180/hdrom.h ../z180/cfboot.h |> !cc |>  {objs}
+: foreach $(SRC_Z) |> !cc -D'const=const __flash' |> {objs}
+
+: {objs} |> !LINK |> $(PROG).elf
+: $(PROG).elf |> !OBJCOPY |> %B.hex
+: $(PROG).elf |> !OBJDUMP |> %B.lss
+: $(PROG).elf |> !SIZE |>
diff --git a/avr/background.c b/avr/background.c
new file mode 100644 (file)
index 0000000..9c8b5a6
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "common.h"
+#include "background.h"
+
+
+#define BG_FUNC_MAX 5
+
+static struct {
+       bg_func fct;
+       int param;
+} func_tab[BG_FUNC_MAX];
+
+static int_fast8_t fcount;
+
+int bg_register(bg_func f, int initval)
+{
+       if (fcount < BG_FUNC_MAX) {
+               func_tab[fcount].fct = f;
+               func_tab[fcount].param = initval;
+               return ++fcount - 1;
+       }
+       return -1;
+}
+
+int bg_setstat(int handle, int val)
+{
+       if (handle < fcount) {
+               func_tab[handle].param = val;
+               return 1;
+       }
+
+       return 0;
+}
+
+
+int bg_getstat(int handle)
+{
+       if (handle < fcount) {
+               return func_tab[handle].param;
+       }
+       return 0;
+}
+
+
+void bg_shed(void)
+{
+       static int_fast8_t current;
+
+       if (func_tab[current].fct) {
+               int v = func_tab[current].fct(func_tab[current].param);
+               func_tab[current].param = v;
+       }
+       if (++current >= fcount)
+               current = 0;
+}
diff --git a/avr/bcd.c b/avr/bcd.c
new file mode 100644 (file)
index 0000000..5154852
--- /dev/null
+++ b/avr/bcd.c
@@ -0,0 +1,21 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "stdlib.h"
+#include "stdint.h"
+#include "bcd.h"
+
+uint_fast8_t bcd2bin(uint8_t val)
+{
+       return (val >> 4) * 10 + (val & 0x0f);
+}
+
+uint8_t bin2bcd (uint_fast8_t val)
+{
+       div_t d = div(val, 10);
+
+       return (d.quot << 4) | d.rem;
+}
diff --git a/avr/cli.c b/avr/cli.c
new file mode 100644 (file)
index 0000000..922f9e1
--- /dev/null
+++ b/avr/cli.c
@@ -0,0 +1,428 @@
+/*
+ * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Add to readline cmdline-editing by
+ * (C) Copyright 2005
+ * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include "cli.h"
+#include "common.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "command.h"
+#include "xmalloc.h"
+#include "debug.h"
+#include "env.h"
+#include "cli_readline.h"
+#include "con-utils.h"
+
+
+/* FIXME: Quoting problems */
+
+#define DEBUG_PARSER   0       /* set to 1 to debug */
+
+#define debug_parser(fmt, args...)             \
+       debug_cond(DEBUG_PARSER, fmt, ##args)
+
+
+static bool opt_xtrace;
+static bool opt_verbose;
+static int_least8_t command_level;
+
+static void cli_trace_cmd(int_fast8_t level, int argc, char *argv[])
+{
+       while (level-- > 0)
+               putchar('+');
+       for (int_fast8_t i = 0; i < argc; i++)
+               printf_P(PSTR(" %s"), argv[i]);
+       putchar('\n');
+}
+
+
+
+
+static int cli_parse_line(char *line, char *argv[])
+{
+       uint_fast8_t state = 0;
+       uint_fast8_t nargs = 0;
+       char *inp, *outp;
+       char c, quote;
+
+       debug_parser("%s: \"%s\"\n", __func__, line);
+
+       for (outp = inp = line, quote = '\0'; (c = *inp) != '\0'; inp++) {
+
+               switch (state) {
+               case 0:                                         /* before arg string, waiting for arg start */
+                       if (isblank(c))
+                               continue;
+
+                       argv[nargs++] = inp;    /* begin of argument string     */
+                       outp = inp;
+                       state = 1;
+                       /* fall thru */
+
+               case 1:                                         /* in arg string, waiting for end of arg string */
+                       if (c == '\\') {
+                               ++state;
+                               continue;
+                       }
+                       if (c == '\"' || c == '\'') {
+                               quote = c;
+                               state = 3;
+                               continue;
+                       }
+                       if (isblank(c)) {
+                               c = '\0';
+                               state = 0;
+                       }
+                       break;
+
+               case 3:                                         /* in quote */
+                       if (c == '\\' && quote == '\"') {
+                               ++state;
+                               continue;
+                       }
+                       if (c == quote) {
+                               state = 1;
+                               continue;
+                       }
+                       break;
+
+               case 2:                                         /* waiting for next char */
+               case 4:
+                       --state;
+                       break;
+
+               }
+
+               if (nargs > CONFIG_SYS_MAXARGS) {
+                       --nargs;
+                       break;
+               }
+               *outp++ = c;
+       }
+
+       if (*inp != '\0')
+               printf_P(PSTR("** Too many args (max. %d) **\n"), CONFIG_SYS_MAXARGS);
+
+       *outp = '\0';
+       argv[nargs] = NULL;
+       debug_parser("%s: nargs=%d\n", __func__, nargs);
+#if 0
+       for (int i = 0; i < nargs; i++)
+               debug_parser("%s: arg %d: >%s<\n", __func__, i, argv[i]);
+#endif
+       return nargs;
+
+}
+
+static
+void append_char(uint_fast8_t pass, char **p, char c)
+{
+
+       if (pass) {
+               **p = c;
+       }
+       ++(*p);
+}
+
+static
+char *process_macros(char *input, char *output)
+{
+       char c, prev, *inp, *outp;
+       const char *varname = NULL;
+
+       for(uint_fast8_t pass = 0; pass < 2; pass++)
+       {
+               uint_fast8_t state = 0;
+               /* 0 = waiting for '$'  */
+               /* 1 = waiting for '{' */
+               /* 2 = waiting for '}' */
+               /* 3 = waiting for ''' */
+
+               if (pass == 0) {
+                       outp = output;
+               } else {
+                       int outputlen = outp - output;
+                       outp = xrealloc(output, outputlen);
+                       output = outp;
+               }
+
+               inp = input;
+
+               debug_parser("[PROCESS_MACROS] INPUT len %d: \"%s\"\n",
+                                               strlen(inp), inp);
+
+               for (prev = '\0'; (c = *inp++) != '\0'; prev = c) {
+
+
+
+                       switch (state) {
+                       case 0: /* Waiting for (unescaped) $    */
+                               if ((c == '\'') && (prev != '\\')) {
+                                       state = 3;
+                                       break;
+                               }
+                               if ((c == '$') && (prev != '\\')) {
+                                       state++;
+                                       continue;
+                               }
+                               break;
+                       case 1: /* Waiting for {        */
+                               if (c == '{') {
+                                       state++;
+                                       varname = inp;
+                                       continue;
+                               } else {
+                                       state = 0;
+                                       append_char(pass, &outp, '$');
+                               }
+                               break;
+                       case 2: /* Waiting for }        */
+                               if (c == '}') {
+                                       /* Terminate variable name */
+                                       *(inp-1) = '\0';
+                                       const char *envval = getenv_str(varname);
+                                       *(inp-1) = '}';
+                                       /* Copy into the line if it exists */
+                                       if (envval != NULL)
+                                               while (*envval)
+                                                       append_char(pass, &outp, *(envval++));
+                                       /* Look for another '$' */
+                                       state = 0;
+                               }
+                               continue;
+                       case 3: /* Waiting for '        */
+                               if (c == '\'')
+                                       state = 0;
+                               break;
+                       }
+                       append_char(pass, &outp, c);
+               }
+
+               append_char(pass, &outp, 0);
+       }
+
+       debug_parser("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
+                    strlen(output), output);
+
+       return output;
+}
+
+/**
+ *
+ *
+ * WARNING:
+ *
+ * We must create a temporary copy of the command since the command we get
+ * may be the result from getenv_str(), which returns a pointer directly to
+ * the environment data, which may change magicly when the command we run
+ * creates or modifies environment variables (like "bootp" does).
+ *
+ *
+ * @param cmd
+ * @param flag
+ * @returns
+ *
+ */
+static int cli_run_command(const char *cmd, int flag)
+{
+       char *cmdbuf;                   /* working copy of cmd          */
+       char *token;                    /* start of token in cmdbuf     */
+       char *sep;                      /* end of token (separator) in cmdbuf */
+       char *finaltoken = NULL;        /* token after macro expansion  */
+       char *str;
+       char *argv[CONFIG_SYS_MAXARGS + 1];     /* NULL terminated      */
+       int argc;
+       uint_fast8_t inquotes, repeatable = 1;
+       int rc = 0;
+
+       opt_verbose = 0;
+       opt_xtrace = 0;
+       char *optenv = getenv_str(PSTR("cli"));
+       if (optenv) {
+               opt_verbose = (strstr_P(optenv, PSTR("verbose")) != NULL);
+               opt_xtrace = (strstr_P(optenv, PSTR("xtrace")) != NULL);
+       }
+
+       debug_parser("[RUN_COMMAND] cmd[%p]=\"%s\"\n",
+                       cmd, cmd ? cmd : "NULL");
+
+       if (opt_verbose)
+               printf_P(PSTR("%s\n"), cmd, cmd ? cmd : "");
+
+       clear_ctrlc();          /* forget any previous Control C */
+
+       if (!cmd || !*cmd)
+               return -1;      /* empty command */
+
+       cmdbuf = strdup(cmd);
+       if (!cmdbuf)
+               return -1;      /* not enough memory */
+
+       ++command_level;
+       str = cmdbuf;
+
+       /* Process separators and check for invalid
+        * repeatable commands
+        */
+
+       debug_parser("[PROCESS_SEPARATORS] %s\n", cmd);
+       while (*str) {
+               /*
+                * Find separator, or string end
+                * Allow simple escape of ';' by writing "\;"
+                */
+               for (inquotes = 0, sep = str; *sep; sep++) {
+                       if ((*sep == '\'') &&
+                           (sep != str) &&                                     /* past string start */
+                           (*(sep - 1) != '\\'))                       /* and NOT escaped */
+                               inquotes = !inquotes;
+
+                       if (!inquotes &&
+                           (*sep == ';' || *sep == '\n'        /* separator */
+                                       || *sep == '#') &&                      /*   or start of comment */
+                           ((sep == str) ||                            /* string start */
+                           (*(sep - 1) != '\\')))                      /*   or NOT escaped */
+                               break;
+               }
+
+               /* no more commands after unescaped '#' token */
+               if (*sep == '#')
+                       *sep = '\0';
+
+               /* Limit the token to data between separators */
+               token = str;
+               if (*sep) {
+                       str = sep + 1;          /* start of command for next pass */
+                       *sep = '\0';
+               } else {
+                       str = sep;                      /* no more commands for next pass */
+               }
+               debug_parser("token: \"%s\"\n", token);
+
+               /* find macros in this token and replace them */
+               finaltoken = process_macros(token, finaltoken);
+
+               /* Extract arguments */
+               argc = cli_parse_line(finaltoken, argv);
+               if (argc == 0) {
+                       rc = -1;        /* no command at all */
+                       continue;
+               }
+
+               if (opt_xtrace)
+                       cli_trace_cmd(command_level, argc, argv);
+
+               rc = cmd_process(flag, argc, argv, &repeatable);
+               if (rc != CMD_RET_SUCCESS) {
+                       if (opt_verbose)
+                               printf_P(PSTR("Command failed, result=%d\n"), rc);
+                       rc = -1;
+               }
+
+               /* Did the user stop this? */
+               if (had_ctrlc()) {
+                       rc = -1;        /* if stopped then not repeatable */
+                       break;
+               }
+       }
+
+       free(cmdbuf);
+       free(finaltoken);
+       --command_level;
+
+       return rc ? rc : repeatable;
+}
+
+static int cli_run_command_list(const char *cmd)
+{
+       return (cli_run_command(cmd, 0) < 0);
+}
+
+/******************************************************************************/
+
+
+/*
+ * Run a command.
+ *
+ * @param cmd  Command to run
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+int run_command(const char *cmd, int flag)
+{
+       /*
+        * cli_run_command can return 0 or 1 for success, so clean up
+        * its result.
+        */
+       if (cli_run_command(cmd, flag) == -1)
+               return 1;
+
+       return 0;
+}
+
+/*
+ * Run a command using the selected parser, and check if it is repeatable.
+ *
+ * @param cmd  Command to run
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 (not repeatable) or 1 (repeatable) on success, -1 on error.
+ */
+static int run_command_repeatable(const char *cmd, int flag)
+{
+       return cli_run_command(cmd, flag);
+}
+
+int run_command_list(const char *cmd, int len)
+{
+       (void) len;
+
+       return cli_run_command_list(cmd);
+}
+
+/****************************************************************************/
+
+
+void cli_loop(void)
+{
+       char *lastcommand = NULL;
+       int len;
+       int flag;
+       int rc = 1;
+
+       for (;;) {
+               len = cli_readline(lastcommand ? PSTR(CONFIG_SYS_PROMPT_REPEAT) : PSTR(CONFIG_SYS_PROMPT), 1);
+
+               flag = 0;       /* assume no special flags for now */
+               if (len > 0) {
+                       free (lastcommand);
+                       lastcommand = strdup(console_buffer);
+               } else if (len == 0)
+                       flag |= CMD_FLAG_REPEAT;
+
+               if (len == -1) {
+                       if (opt_verbose)
+                               my_puts_P(PSTR("<INTERRUPT>\n"));
+               } else
+                       rc = run_command_repeatable(lastcommand, flag);
+
+               if (rc <= 0) {
+                       /* invalid command or not repeatable, forget it */
+                       free(lastcommand);
+                       lastcommand = NULL;
+               }
+       }
+}
diff --git a/avr/cli_readline.c b/avr/cli_readline.c
new file mode 100644 (file)
index 0000000..2fdc56e
--- /dev/null
@@ -0,0 +1,681 @@
+/*
+ * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Add to readline cmdline-editing by
+ * (C) Copyright 2005
+ * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include "cli_readline.h"
+#include "common.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "con-utils.h"
+#include "print-utils.h"
+#include "command.h"
+
+
+
+char console_buffer[CONFIG_SYS_CBSIZE + 1];    /* console I/O buffer   */
+
+#define CTL_CH(c)                      ((c) - 'a' + 1)
+#define CTL_BACKSPACE          ('\b')
+#define DEL                                    ((char)255)
+#define DEL7                           ((char)127)
+
+
+/************************************************************************************************/
+/* TODO:
+ *
+ */
+
+#define ESC                                            0x1b
+
+#define KEY_TAB                 '\t'                                                // TAB key
+#define KEY_CR                  '\r'                                                // RETURN key
+#define KEY_BACKSPACE           '\b'                                                // Backspace key
+#define KEY_ESCAPE              0x1B                                                // ESCAPE (pressed twice)
+
+#define KEY_DOWN                0x80                                                // Down arrow key
+#define KEY_UP                  0x81                                                // Up arrow key
+#define KEY_LEFT                0x82                                                // Left arrow key
+#define KEY_RIGHT               0x83                                                // Right arrow key
+#define KEY_HOME                0x84                                                // Home key
+#define KEY_DC                  0x85                                                // Delete character key
+#define KEY_IC                  0x86                                                // Ins char/toggle ins mode key
+#define KEY_NPAGE               0x87                                                // Next-page key
+#define KEY_PPAGE               0x88                                                // Previous-page key
+#define KEY_END                 0x89                                                // End key
+#define KEY_BTAB                0x8A                                                // Back tab key
+#define KEY_F1                  0x8B                                                // Function key F1
+#define KEY_F(n)                (KEY_F1+(n)-1)                                      // Space for additional 12 function keys
+
+
+struct fkey_tbl_s {
+       const FLASH char *sequence;             /* ESC Sequence */
+       int     code;                                           /* Keycode      */
+};
+
+//typedef const FLASH struct fkey_tbl_s fkey_tbl_t;
+
+#define FKEY_TBL_ITEM(_seq, _code)             { FSTR(#_seq), _code }
+
+
+
+static const FLASH struct fkey_tbl_s fkey_table[] = {
+
+FKEY_TBL_ITEM(B,   KEY_DOWN),                  // Down arrow key
+FKEY_TBL_ITEM(A,   KEY_UP),                            // Up arrow key
+FKEY_TBL_ITEM(D,   KEY_LEFT),                  // Left arrow key
+FKEY_TBL_ITEM(C,   KEY_RIGHT),                 // Right arrow key
+FKEY_TBL_ITEM(1~,  KEY_HOME),                  // Home key
+FKEY_TBL_ITEM(3~,  KEY_DC),                            // Delete character key
+FKEY_TBL_ITEM(2~,  KEY_IC),                            // Ins char/toggle ins mode key
+FKEY_TBL_ITEM(6~,  KEY_NPAGE),                 // Next-page key
+FKEY_TBL_ITEM(5~,  KEY_PPAGE),                 // Previous-page key
+FKEY_TBL_ITEM(4~,  KEY_END),                   // End key
+FKEY_TBL_ITEM(Z,   KEY_BTAB),                  // Back tab key
+/*  */
+FKEY_TBL_ITEM(H,   KEY_HOME),                  // Home key
+FKEY_TBL_ITEM(F,   KEY_END),                   // End key
+/* VT400: */
+FKEY_TBL_ITEM(11~, KEY_F(1)),                  // Function key F1
+FKEY_TBL_ITEM(12~, KEY_F(2)),                  // Function key F2
+FKEY_TBL_ITEM(13~, KEY_F(3)),                  // Function key F3
+FKEY_TBL_ITEM(14~, KEY_F(4)),                  // Function key F4
+FKEY_TBL_ITEM(15~, KEY_F(5)),                  // Function key F5
+/* Linux console */
+FKEY_TBL_ITEM([A,  KEY_F(1)),                  // Function key F1
+FKEY_TBL_ITEM([B,  KEY_F(2)),                  // Function key F2
+FKEY_TBL_ITEM([C,  KEY_F(3)),                  // Function key F3
+FKEY_TBL_ITEM([D,  KEY_F(4)),                  // Function key F4
+FKEY_TBL_ITEM([E,  KEY_F(5)),                  // Function key F5
+
+FKEY_TBL_ITEM(17~, KEY_F(6)),                  // Function key F6
+FKEY_TBL_ITEM(18~, KEY_F(7)),                  // Function key F7
+FKEY_TBL_ITEM(19~, KEY_F(8)),                  // Function key F8
+FKEY_TBL_ITEM(20~, KEY_F(9)),                  // Function key F9
+FKEY_TBL_ITEM(21~, KEY_F(10)),                 // Function key F10
+FKEY_TBL_ITEM(23~, KEY_F(11)),                 // Function key F11
+FKEY_TBL_ITEM(24~, KEY_F(12)),                 // Function key F12
+{ NULL }       /* Mark end of table */
+};
+
+
+
+typedef enum {
+       STATE_GROUND,
+       STATE_ESCAPE,
+       STATE_CSI_ENTRY,
+       STATE_SS3
+} vtparse_state_t;
+
+#define CHB_SIZE       15
+
+static
+int vt_parse (void)
+{
+       static vtparse_state_t state = STATE_GROUND;
+       char    buf[CHB_SIZE+1];
+       uint8_t param[2];
+       uint8_t i_buf;
+       uint8_t i_param;
+       int  ch;
+
+
+       while (1) {
+               ch = my_getchar(1);
+//             debug_getch(state, ch);
+
+               switch (state) {
+               case STATE_GROUND:
+                       if (ch == ESC) {
+                               state = STATE_ESCAPE;
+                               continue;
+                       }
+                       if (ch == 0x7F)                         // BACKSPACE on VT200 sends DEL char
+                               ch = KEY_BACKSPACE;             // map it to '\b'
+                       break;
+               case STATE_ESCAPE:
+                       if (ch < 0)
+                               continue;
+
+                       if (ch == '[') {
+                               state = STATE_CSI_ENTRY;
+                               param[0] = param[1] = 0;
+                               i_buf = 0;
+                               i_param = 0;
+                               continue;
+                       }
+                       if (ch == 'O') {
+                               state = STATE_SS3;
+                               continue;
+                       }
+                       state = STATE_GROUND;
+                       break;
+               case STATE_SS3:
+                       if (ch == 'F')
+                               ch = KEY_END;
+                       if (ch == 'H')
+                               ch = KEY_HOME;
+                       state = STATE_GROUND;
+                       break;
+               case STATE_CSI_ENTRY:
+                       if (ch < 0)
+                               continue;
+
+                       buf[i_buf] = ch;
+                       if (i_buf < CHB_SIZE)
+                               i_buf++;
+                       if (ch == ';') {
+                               i_param++;
+                               continue;
+                       }
+                       if (isdigit(ch)) {
+                               if (i_param < 2)
+                                       param[i_param] = param[i_param] * 10 + ch - '0';
+                               continue;
+                       }
+                       if (ch >= '@' && ch <= '~' && ch != '[') {
+                               buf[i_buf] = '\0';
+                               int_fast8_t i = 0;
+                               while (fkey_table[i].sequence) {
+                                       if (! strcmp_P (buf, fkey_table[i].sequence)) {
+                                               ch = fkey_table[i].code;
+                                               break;
+                                       }
+                                       i++;
+                               }
+                               if (fkey_table[i].sequence == NULL) {
+                                       ch = '$'; /* KEY_ESCAPE; */
+                               }
+                       }
+                       state = STATE_GROUND;
+                       break;
+               }
+               break; /* while */
+       }
+
+       return ch;
+}
+
+/************************************************************************************************/
+
+/*
+ * cmdline-editing related codes from vivi.
+ * Author: Janghoon Lyu <nandy@mizi.com>
+ */
+
+
+struct hist_node_s {
+       struct hist_node_s *next;
+       char line[];
+};
+typedef struct hist_node_s hist_node;
+
+
+static hist_node *hist_head;
+static hist_node *hist_cur;
+
+static void hist_reset(void)
+{
+       hist_cur = hist_head;
+}
+
+static hist_node *hist_search_node(char *line)
+{
+       hist_node *p = hist_head;
+
+       while (p && strcmp(p->line, line))
+               p = p->next;
+       return p;
+}
+
+#if 0
+static hist_node *hist_insert(char *line)
+{
+       hist_node *p = (hist_node *) malloc(sizeof (hist_node) + strlen(line) + 1);
+
+       if (p) {
+               strcpy(p->line, line);
+               p->next = hist_head;
+               hist_head = p;
+       }
+       return p;
+}
+#endif
+
+static hist_node *hist_new(char *line)
+{
+       hist_node *p = (hist_node *) malloc(sizeof (hist_node) + strlen(line) + 1);
+
+       if (p) {
+               strcpy(p->line, line);
+               p->next = NULL;
+       }
+       return p;
+}
+
+static hist_node *hist_delete(void)
+{
+       hist_node *p = NULL;
+       hist_node *q = hist_head;
+
+       if (q) {
+               while(q->next) {
+                       p = q;
+                       q = q->next;
+               }
+               free(q);
+               if (p)
+                       p->next = NULL;
+       }
+       return p;
+}
+
+static hist_node *hist_unlink(hist_node *pos)
+{
+       hist_node *p = NULL;
+       hist_node *q = hist_head;
+
+       while(q && q != pos) {
+               p = q;
+               q = q->next;
+       }
+       if (q) {
+               if (p)
+                       p->next = q->next;
+               else
+                       hist_head = q->next;
+               q->next = NULL;
+       }
+       return q;
+}
+
+static uint_fast8_t hist_count(void)
+{
+       hist_node *p = hist_head;
+       uint_fast8_t n = 0;
+
+       while (p) {
+               ++n;
+               p = p->next;
+       }
+       return n;
+}
+
+static hist_node *cread_add_to_hist(char *line)
+{
+       hist_node * p;
+
+       p = hist_search_node(line);
+       if (p)
+               hist_unlink(p);
+       else
+               p = hist_new(line);
+
+       if (p) {
+               p->next = hist_head;
+               hist_head = p;
+       }
+
+       if (hist_count() > CONFIG_SYS_HIST_MAX)
+               hist_delete();
+       return p;
+}
+
+static char *hist_prev(void)
+{
+       hist_node *p = hist_cur;
+
+       if (p == NULL)
+               return NULL;
+       hist_cur = p->next;
+
+       return  p->line;
+}
+
+static char *hist_next(void)
+{
+       hist_node *p = NULL;
+       hist_node *q = hist_head;
+
+       if(q == hist_cur)
+               return NULL;
+
+       while(q->next != hist_cur) {
+               p = q;
+               q = q->next;
+       }
+       hist_cur = q;
+
+       return p ? p->line : "";
+}
+
+static char *hist_search_backward(char* buf, uint8_t num)
+{
+       hist_node *p = hist_cur;
+
+       if (p == NULL)
+               return NULL;
+
+       while (p->next && strncmp(p->line, buf, num))
+               p = p->next;
+
+       if(!strncmp(p->line, buf, num)) {
+               hist_cur = p->next;
+               return  p->line;
+       }
+       return NULL;
+}
+
+static char *hist_search_forward (char* buf, uint8_t num)
+{
+       hist_node *p = NULL;
+       hist_node *match = NULL;
+       hist_node *q = hist_head;
+
+       if(q == hist_cur)
+               return NULL;
+
+       while(q->next != hist_cur) {
+               p = q;
+               q = q->next;
+               if (p && !strncmp(p->line, buf, num))
+                       match = p;
+       }
+
+       if(match) {
+               hist_cur = match->next;
+               return  match->line;
+       }
+       return NULL;
+}
+
+static void putnstr(char *str, int n)
+{
+       /* printf_P(PSTR("%.*s"), (int)n, str) */
+       while (n-- && *str)
+               putchar(*str++);
+}
+
+static void getcmd_putch(int ch) { putchar(ch);}
+static int  getcmd_getch(void) { return vt_parse();}
+static void getcmd_cbeep(void) { getcmd_putch('\a');}
+
+static void beginning_of_line(uint8_t *num)
+{
+       while (*num) {
+               getcmd_putch(CTL_BACKSPACE);
+               (*num)--;
+       }
+}
+
+static void erase_to_eol(uint_fast8_t *num, uint_fast8_t *eol_num)
+{
+       if (*num < *eol_num) {
+               /* printf_P(PSTR("%*S"), (int)(*eol_num - *num), PSTR("")); */
+               print_blanks(*eol_num - *num);
+               do {
+                       getcmd_putch(CTL_BACKSPACE);
+               } while (--(*eol_num) > *num);
+       }
+}
+
+static void refresh_to_eol(char *buf, uint_fast8_t *num, uint_fast8_t *eol_num)
+{
+       if (*num < *eol_num) {
+               uint_fast8_t wlen = *eol_num - *num;
+               putnstr(buf + *num, wlen);
+               *num = *eol_num;
+       }
+}
+
+static void cread_add_char(char ichar, bool insert, uint_fast8_t *num,
+              uint_fast8_t *eol_num, char *buf, uint_fast8_t len)
+{
+       uint_fast8_t wlen;
+
+       /* room ??? */
+       if (insert || *num == *eol_num) {
+               if (*eol_num > len - 1) {
+                       getcmd_cbeep();
+                       return;
+               }
+               (*eol_num)++;
+       }
+
+       if (insert) {
+               wlen = *eol_num - *num;
+               if (wlen > 1)
+                       memmove(&buf[*num+1], &buf[*num], wlen-1);
+
+               buf[*num] = ichar;
+               putnstr(buf + *num, wlen);
+               (*num)++;
+               while (--wlen)
+                       getcmd_putch(CTL_BACKSPACE);
+       } else {
+               /* echo the character */
+               buf[*num] = ichar;
+               putnstr(buf + *num, 1);
+               (*num)++;
+       }
+}
+
+static void cread_add_str(char *str, bool insert, uint_fast8_t *num,
+                               uint_fast8_t *eol_num, char *buf, uint_fast8_t len)
+{
+       char c;
+
+       while ((c = *str++) != '\0')
+               cread_add_char(c, insert, num, eol_num, buf, len);
+}
+
+static int cread_line(const FLASH char *const prompt, char *buf,
+                       uint_fast8_t len, bool enable_history)
+{
+       uint_fast8_t num = 0;
+       uint_fast8_t eol_num = 0;
+       bool insert = 1;
+
+       (void) prompt;
+
+       if (buf[0])
+               cread_add_str(buf, 1, &num, &eol_num, buf, len);
+
+       hist_reset();
+
+       while (1) {
+               int ichar = getcmd_getch();
+
+               if ((ichar == '\n') || (ichar == '\r')) {
+                       putchar('\n');
+                       break;
+               }
+
+
+               switch (ichar) {
+
+               case KEY_HOME:
+               case CTL_CH('a'):
+                       beginning_of_line(&num);
+                       break;
+               case CTL_CH('c'):                       /* ^C - break */
+                       putchar('\n');
+                       *buf = '\0';                    /* discard input */
+                       return -1;
+               case KEY_RIGHT:
+               case CTL_CH('f'):                       /* forward-char */
+                       if (num < eol_num) {
+                               getcmd_putch(buf[num]);
+                               num++;
+                       }
+                       break;
+               case KEY_LEFT:
+               case CTL_CH('b'):                       /* backward-char */
+                       if (num) {
+                               getcmd_putch(CTL_BACKSPACE);
+                               num--;
+                       }
+                       break;
+               case KEY_DC:
+               case CTL_CH('d'):                       /* delete-char */
+                       if (num < eol_num) {
+                               uint_fast8_t wlen = eol_num - num - 1;
+                               if (wlen) {
+                                       memmove(&buf[num], &buf[num+1], wlen);
+                                       putnstr(buf + num, wlen);
+                               }
+
+                               getcmd_putch(' ');
+                               do {
+                                       getcmd_putch(CTL_BACKSPACE);
+                               } while (wlen--);
+                               eol_num--;
+                       }
+                       break;
+               case CTL_CH('k'):                       /* kill-line */
+                       erase_to_eol(&num, &eol_num);
+                       break;
+               case KEY_END:
+               case CTL_CH('e'):
+                       refresh_to_eol(buf, &num, &eol_num);
+                       break;
+               case KEY_IC:
+               case CTL_CH('o'):
+                       insert = !insert;
+                       break;
+               case CTL_CH('x'):
+               case CTL_CH('u'):                       /* kill-whole-line */
+                       beginning_of_line(&num);
+                       erase_to_eol(&num, &eol_num);
+                       break;
+               case DEL:
+               case DEL7:
+               case 8:                                         /* backward-delete-char */
+                       if (num) {
+                               uint_fast8_t wlen = eol_num - --num;
+                               buf[eol_num] = ' ';
+                               memmove(&buf[num], &buf[num+1], wlen);
+                               getcmd_putch(CTL_BACKSPACE);
+                               putnstr(buf + num, wlen);
+                               do {
+                                       getcmd_putch(CTL_BACKSPACE);
+                               } while (--wlen);
+                               eol_num--;
+                       }
+                       break;
+               case KEY_UP:
+               case CTL_CH('p'):                       /* previous-history */
+               case KEY_DOWN:
+               case CTL_CH('n'):                       /* next-history */
+                       if (enable_history) {
+                               char *hline;
+
+                               if (ichar == CTL_CH('p') || ichar == KEY_UP)
+                                       hline = hist_prev();
+                               else
+                                       hline = hist_next();
+
+                               if (hline) {
+                                       /* first, go home */
+                                       beginning_of_line(&num);
+                                       /* overwrite current line */
+                                       cread_add_str(hline, 0, &num, &eol_num, buf, len);
+                                       /* erase to end of line */
+                                       erase_to_eol(&num, &eol_num);
+
+                               } else {
+                                       getcmd_cbeep();
+                               }
+                       } else {
+                               getcmd_cbeep();
+                       }
+                       break;
+               case KEY_PPAGE:                 /* history-search-backward */
+               case KEY_NPAGE:                 /* history-search-forward */
+                       if (enable_history) {
+                               char *hline;
+                               if (ichar == KEY_PPAGE)
+                                       hline = hist_search_backward(buf, num);
+                               else
+                                       hline = hist_search_forward(buf, num);
+
+                               if (hline) {
+                                       uint_fast8_t num2 = num;
+                                       /* overwrite current line from cursor position */
+                                       cread_add_str(hline+num, 0, &num2, &eol_num, buf, len);
+                                       /* erase to end of line */
+                                       erase_to_eol(&num2, &eol_num);
+                                       /* cursor back */
+                                       while (num2-- > num)
+                                               getcmd_putch(CTL_BACKSPACE);
+                               } else {
+                                       getcmd_cbeep();
+                               }
+                       } else {
+                               getcmd_cbeep();
+                       }
+                       break;
+#ifdef CONFIG_AUTO_COMPLETE
+               case '\t': {
+                       int num2, col;
+
+                       /* do not autocomplete when in the middle */
+                       if (num < eol_num) {
+                               getcmd_cbeep();
+                               break;
+                       }
+
+                       buf[num] = '\0';
+                       col = strlen_P(prompt) + eol_num;
+                       num2 = num;
+                       if (cmd_auto_complete(prompt, buf, &num2, &col)) {
+                               col = num2 - num;
+                               num += col;
+                               eol_num += col;
+                       }
+                       break;
+               }
+#endif
+               default:
+                       if (isprint(ichar))
+                               cread_add_char(ichar, insert, &num, &eol_num, buf, len);
+                       break;
+               }
+       }
+       while (eol_num && buf[eol_num-1] == ' ')
+               --eol_num;                      /* remove trailing blanks */
+       buf[eol_num] = '\0';    /* lose the newline */
+
+       if (enable_history && buf[0])
+               cread_add_to_hist(buf);
+       return eol_num;
+}
+
+/****************************************************************************/
+
+int cli_readline(const FLASH char *const prompt, bool enable_history)
+{
+       /*
+        * If console_buffer isn't 0-length the user will be prompted to modify
+        * it instead of entering it from scratch as desired.
+        */
+       console_buffer[0] = '\0';
+
+       if (prompt)
+               my_puts_P(prompt);
+
+       return cread_line(prompt, console_buffer, CONFIG_SYS_CBSIZE, enable_history);
+}
diff --git a/avr/cmd_attach.c b/avr/cmd_attach.c
new file mode 100644 (file)
index 0000000..e9b5ccd
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * (C) Copyright 2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+/*
+ * attach channels to devices
+ */
+
+#include "common.h"
+#include <string.h>
+#include <stdbool.h>
+
+#include "command.h"
+#include "z180-serv.h"
+#include "getopt-min.h"
+
+
+static const FLASH char * const FLASH rc_messages[] = {
+                       FSTR("OK"),
+                       FSTR("Unknown error"),
+                       FSTR("Disk number out of range 0..7"),
+                       FSTR("Disk allready attached"),
+                       FSTR("Disk not attached"),
+                       FSTR("File not found"),
+                       FSTR("Not enough memory"),
+                       FSTR("Error opening file"),
+                       FSTR("File allready attached to other drive"),
+               };
+
+static
+void printerror(int rc, uint8_t unit, char *fn)
+{
+       if (rc < 0 || (unsigned) rc >= ARRAY_SIZE(rc_messages))
+               rc = 1;
+
+#if GCC_BUG_61443
+               printf_P(PSTR("Attachment of '%s' to dsk%d failed: "), fn, unit);
+               my_puts_P(rc_messages[rc]);
+               my_puts_P(PSTR("!\n"));
+#else
+               printf_P(PSTR("Attachment of '%s' to dsk%d failed: %S!\n"),
+                               fn, unit, rc_messages[rc]);
+#endif
+}
+
+/*
+ * attach [[options] [unit [diskfile]]]
+ *
+ * detach unit
+ * attach -d unit
+ *
+ * attach -o reattach unit
+ * attach -o reattach unit diskfile
+ *
+ * attach unit diskfile
+ *
+ */
+
+command_ret_t do_attach(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint8_t unit;
+       char *filename = NULL;
+       bool detach = false;
+       bool detach_all = false;
+       drv_opt_t options = 0;
+       int res;
+
+       (void) cmdtp; (void) flag;
+
+
+       if (argv[0][0] == 'd') {
+               /* we are called as 'detach' */
+               detach = true;
+       } else if (argc == 1) {
+               /* no arguments */
+               drv_list();
+               return CMD_RET_SUCCESS;
+       }
+
+       /* reset getopt() */
+       optind = 0;
+
+       int opt;
+       while ((opt = getopt(argc, argv, PSTR("darwo:"))) != -1) {
+               switch (opt) {
+               case 'd':
+                       detach = true;
+                       break;
+               case 'a':
+                       detach_all = true;
+                       break;
+               case 'r':
+                       options |= DRV_OPT_RO;
+                       break;
+               case 'w':
+                       options &= ~DRV_OPT_RO;
+                       break;
+               case 'o':
+                       {
+                               static const FLASH char delim[] = {", "};
+                               char *p = strtok_P(optarg, delim);
+                               while (p != NULL) {
+                                       if (!strcmp_P(p, PSTR("ro")))
+                                               options |= DRV_OPT_RO;
+                                       else if (!strcmp_P(p, PSTR("rw")))
+                                               options &= ~DRV_OPT_RO;
+                                       else if (!strcmp_P(p, PSTR("debug")))
+                                               options |= DRV_OPT_DEBUG;
+                                       else if (!strcmp_P(p, PSTR("nodebug")))
+                                               options &= ~DRV_OPT_DEBUG;
+                                       else if (!strcmp_P(p, PSTR("reattach")))
+                                               options |= DRV_OPT_REATTATCH;
+                                       else
+                                               return CMD_RET_USAGE;
+
+                                       p = strtok_P(NULL, delim);
+                               }
+                       }
+                       break;
+               default: /* '?' */
+                       return CMD_RET_USAGE;
+               }
+       }
+
+       /* remaining arguments */
+       argc -= optind;
+       if ( !( (argc == 0 && detach && detach_all) ||
+                       (argc == 1 && detach) ||
+                       (argc == 1 && (options & DRV_OPT_REATTATCH)) ||
+                        argc == 2) )
+               return CMD_RET_USAGE;
+
+       if (argc > 0 && ((strlen(argv[optind]) != 4) ||
+                       strncmp_P(argv[optind], PSTR("dsk"), 3) ||
+                       (unit = argv[optind][3] - '0') >= CONFIG_CPM_MAX_DRIVE)) {
+
+               printf_P(PSTR("Unknown device: '%s'\n"), argv[optind]);
+               return CMD_RET_FAILURE;
+       }
+
+       if (detach) {
+               if (detach_all)
+                       for (uint8_t i = 0; i < CONFIG_CPM_MAX_DRIVE; i++)
+                               drv_detach(i);
+               else
+                       drv_detach(unit);
+               return CMD_RET_SUCCESS;
+       }
+
+       if (argc == 2)
+               filename = argv[++optind];
+
+       res = drv_attach(unit, filename, options);
+       if (res)
+               printerror(res, unit, filename);
+
+       return res ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
diff --git a/avr/cmd_boot.c b/avr/cmd_boot.c
new file mode 100644 (file)
index 0000000..a83968f
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2000-2003
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+/*
+ * Misc boot support
+ */
+#include "common.h"
+#include <ctype.h>
+#include <util/atomic.h>
+
+#include "command.h"
+#include "cli_readline.h"      /* console_buffer[] */
+#include "cli.h"                       /* run_command() */
+#include "env.h"
+#include "eval_arg.h"
+#include "con-utils.h"
+#include "getopt-min.h"
+#include "z80-if.h"
+#include "z180-serv.h" /* restart_z180_serv() */
+#include "debug.h"
+
+/* ugly hack to get Z180 loadfile into flash memory */
+#define const const FLASH
+#include "../z180/hdrom.h"
+#include "../z180/cfboot.h"
+#undef const
+
+
+
+static void z80_load_mem(int_fast8_t verbosity,
+                               const FLASH unsigned char data[],
+                               const FLASH unsigned long *sections,
+                               const FLASH unsigned long address[],
+                               const FLASH unsigned long length_of_sections[])
+{
+       uint32_t sec_base = 0;
+
+       if (verbosity > 1)
+               printf_P(PSTR("Loading Z180 memory... \n"));
+
+       for (unsigned sec = 0; sec < *sections; sec++) {
+               if (verbosity > 0) {
+                       printf_P(PSTR("   From: 0x%.5lX to: 0x%.5lX    (%5li bytes)\n"),
+                                       address[sec],
+                                       address[sec]+length_of_sections[sec] - 1,
+                                       length_of_sections[sec]);
+               }
+
+               z80_write_block_P((const FLASH unsigned char *) &data[sec_base],  /* src */
+                               address[sec],                  /* dest */
+                               length_of_sections[sec]);      /* len */
+               sec_base += length_of_sections[sec];
+       }
+}
+
+command_ret_t do_loadf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       (void) cmdtp; (void) flag; (void) argc; (void) argv;
+
+       if (z80_bus_state() & ZST_RUNNING) {
+               my_puts_P(PSTR("Can't load while CPU is running!\n"));
+               return CMD_RET_FAILURE;
+       }
+       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+               my_puts_P(PSTR("Bus timeout\n"));
+               return  CMD_RET_FAILURE;
+       }
+       z80_load_mem(2, hdrom,
+                               &hdrom_sections,
+                               hdrom_address,
+                               hdrom_length_of_sections);
+
+       z80_bus_cmd(Release);
+
+       return CMD_RET_SUCCESS;
+}
+
+
+void print_vars(char *title)
+{
+       uint8_t buf[5];
+       zstate_t state = z80_bus_state();
+
+       if((state & ZST_ACQUIRED) == 0)
+               z80_bus_cmd(Request);
+
+       z80_read_block(buf,     9, sizeof buf);
+
+       if((state & ZST_ACQUIRED) == 0)
+               z80_bus_cmd(Release);
+
+       printf_P(PSTR("%s: stage: %d, flag: 0x%.02x, result: %d, IDE stat/error: 0x%.02x/0x%.02x\n"),
+                               title, buf[0], buf[1], buf[2], buf[3], buf[4]);
+}
+
+
+/*
+ *  bootcf [options]
+ *
+ *             -a      address                 (100h)
+ *             -s      start sector    (0)
+ *             -c      sector count    (7)
+ *             -i      Partition id    (52)
+ *             -n  load only
+ *             -t      timeout                 (10000)
+ *             -v      verbose
+ */
+
+command_ret_t do_bootcf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct {
+               uint8_t  jr[2];
+               uint16_t loadaddr;
+               uint8_t  sec_start;
+               uint8_t  sec_cnt;
+               uint8_t  part_id;
+               uint16_t timeout;
+               uint8_t  stages;
+       } boot_param;
+
+       struct {
+               uint8_t  stages;
+               uint8_t  done;
+               uint8_t  result;
+               uint8_t  ide_stat;
+               uint8_t  ide_error;
+       } boot_res;
+
+       int_fast8_t verbosity = 0;
+       uint8_t default_stages;
+       uint32_t val;
+
+       (void) cmdtp; (void) flag;
+
+       /* get default values */
+       memcpy_P(&boot_param, cfboot, sizeof boot_param);
+       default_stages = boot_param.stages;
+
+       /* reset getopt() */
+       optind = 0;
+
+       int opt;
+       while ((opt = getopt(argc, argv, PSTR("vna:s:c:t:i:"))) != -1) {
+               switch (opt) {
+               case 'v':
+                       verbosity++;
+                       break;
+               case 'n':
+                       if (boot_param.stages > 0)
+                               boot_param.stages--;
+                       break;
+               case 'a':
+                       val = eval_arg(optarg, NULL);
+                       if (val < 0x100 || val > 0xFE00) {
+                               printf_P(PSTR("Address out of range: 0x%.4lX\n"), val);
+                               return CMD_RET_FAILURE;
+                       }
+                       boot_param.loadaddr = val;
+                       break;
+               case 's':
+                       val = eval_arg(optarg, NULL);
+                       if (val > 255) {
+                               printf_P(PSTR("Start sector out of range: 0x%lX\n"), val);
+                               return CMD_RET_FAILURE;
+                       }
+                       boot_param.sec_start = val;
+                       break;
+               case 'c':
+                       val = eval_arg(optarg, NULL);
+                       if (val > 127) {
+                               printf_P(PSTR("Sector count out of range: 0x%lX\n"), val);
+                               return CMD_RET_FAILURE;
+                       }
+                       boot_param.sec_cnt = val;
+                       break;
+               case 't':
+                       val = eval_arg(optarg, NULL);
+                       if (val < 0x1 || val > 0xFFFF) {
+                               printf_P(PSTR("Timeout value out of range: 0x%lX\n"), val);
+                               return CMD_RET_FAILURE;
+                       }
+                       boot_param.timeout = val;
+                       break;
+               case 'i':
+                       val = eval_arg(optarg, NULL);
+                       if (val < 0x01 || val > 0xFF) {
+                               printf_P(PSTR("Partition id out of range: 0x%lX\n"), val);
+                               return CMD_RET_FAILURE;
+                       }
+                       boot_param.part_id = val;
+                       break;
+               default: /* '?' */
+                       return CMD_RET_USAGE;
+               }
+       }
+
+       /* remaining arguments */
+       argc -= optind;
+       if (argc) {
+               my_puts_P(PSTR("Argument error!\n"));
+               return CMD_RET_USAGE;
+       }
+
+       if ((val = (uint32_t) boot_param.loadaddr + boot_param.sec_cnt * 512) >= 0xFF00) {
+               printf_P(PSTR("Top address out of range: 0x%.4lX\n"), val);
+               return CMD_RET_FAILURE;
+       }
+
+
+
+       if (z80_bus_state() & ZST_RUNNING) {
+               my_puts_P(PSTR("CPU is allready running!\n"));
+               return CMD_RET_FAILURE;
+       }
+       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+               my_puts_P(PSTR("Bus timeout\n"));
+               return  CMD_RET_FAILURE;
+       }
+       z80_load_mem(verbosity, cfboot,
+                               &cfboot_sections,
+                               cfboot_address,
+                               cfboot_length_of_sections);
+
+       z80_write_block((const uint8_t *) &boot_param,
+                               cfboot_address[0], sizeof boot_param);
+       z80_bus_cmd(Release);
+
+       if (boot_param.stages == 0) {
+               printf_P(PSTR("Bootloader loaded at: 0x%.4X\n"), (uint16_t) cfboot_address[0]);
+       } else {
+               printf_P(PSTR("Executing %d of %d Bootloader stages...\n"),
+                               boot_param.stages, default_stages);
+
+               z80_bus_cmd(Run);
+               z80_bus_cmd(Release);
+
+               clear_ctrlc();          /* forget any previous Control C */
+               for (boot_res.done = 0; boot_res.done != 0xFF;) {
+                       _delay_ms(8);
+                       /* check for ctrl-c to abort... */
+                       if (had_ctrlc() || ctrlc()) {
+                               break;
+                       }
+                       z80_bus_cmd(Request);
+                       z80_read_block((uint8_t *) &boot_res,
+                                       cfboot_address[0]+sizeof boot_param - 1, sizeof boot_res);
+                       z80_bus_cmd(Release);
+               }
+
+               if (boot_res.done != 0xFF) {
+                       z80_bus_cmd(Reset);
+                       my_puts_P(PSTR("Abort\n"));
+               } else {
+                       if (boot_param.stages == default_stages &&
+                                       boot_res.stages == 0 &&
+                                       boot_res.result == 0) {
+                               my_puts_P(PSTR("Booting...\n"));
+                       } else {
+                               z80_bus_cmd(Reset);
+                               boot_res.stages++;
+                               printf_P(PSTR("Bootloader stopped at stage %d, result: %d, IDE stat/error: 0x%.02x/0x%.02x\n"),
+                                       boot_param.stages - boot_res.stages,
+                                       boot_res.result, boot_res.ide_stat, boot_res.ide_error);
+                       }
+               }
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_busreq_pulse(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint16_t count=1;
+
+       (void) cmdtp; (void) flag;
+
+       if (!(z80_bus_state() & ZST_RUNNING)) {
+               printf_P(PSTR("## CPU is not running!\n"));
+               return CMD_RET_FAILURE;
+       }
+
+       if (argc > 1)
+               count = (uint16_t) eval_arg(argv[1], NULL);
+
+       z80_bus_cmd(Request);
+       while (count--)
+               z80_bus_cmd(M_Cycle);
+
+       return CMD_RET_SUCCESS;
+}
+
+
+command_ret_t do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint32_t addr;
+
+       (void) cmdtp; (void) flag;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+       addr = eval_arg(argv[1], NULL);
+       if (addr >= (1UL<<16)) {
+               printf_P(PSTR("## Startaddress 0x%05lx too high.\n"
+                       "   (Out of logical address space (0x00000-0x0ffff))\n"),
+                       addr);
+               return CMD_RET_FAILURE;
+       }
+
+       if (z80_bus_state() & ZST_RUNNING) {
+               printf_P(PSTR("## CPU allready running!\n"));
+               return CMD_RET_FAILURE;
+       }
+
+       printf_P(PSTR("## Starting application at 0x%04lx ...\n"), addr);
+
+       if (addr != 0) {
+               uint8_t tmp[3];
+
+               z80_bus_cmd(Request);
+               z80_read_block (tmp, 0, 3);
+               z80_write(0, 0xc3);
+               z80_write(1, addr);
+               z80_write(2, (addr >> 8));
+
+               z80_bus_cmd(Run);
+               z80_bus_cmd(M_Cycle);
+               z80_bus_cmd(M_Cycle);
+               z80_write_block(tmp, 0, 3);
+       } else
+               z80_bus_cmd(Run);
+
+       z80_bus_cmd(Release);
+
+       return CMD_RET_SUCCESS;
+}
+
+static
+void reset_cpu(bus_cmd_t mode)
+{
+       restart_z180_serv();
+       z80_bus_cmd(mode);
+}
+
+
+command_ret_t do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       (void) cmdtp; (void) flag; (void) argc; (void) argv;
+
+       printf_P(PSTR("CPU now in reset state.\n"));
+
+       reset_cpu(Reset);
+       return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_restart(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       (void) cmdtp; (void) flag; (void) argc; (void) argv;
+
+       reset_cpu(Restart);
+
+       return CMD_RET_SUCCESS;
+}
+
+static
+void print_con_usage(char esc)
+{      printf_P(PSTR("\n"
+               "------------------------------------------------\n"
+               " ?,H - This Help\n"
+               " Q,X - Return to command line\n"
+               " R   - Reset (Restart) CPU\n"
+               " :   - Execute monitor command\n"
+               " \\   - code input:\n"
+               "       \\nnn   3 decimal digits character code\n"
+               "       \\Xhh   2 hexadecimal digits character code\n"
+               " ^%c  - (Escape char) Type again to send itself\n"
+               "key>"
+       ), esc + 0x40);
+}
+
+command_ret_t do_console(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       int ch;
+       uint8_t pending;
+//     uint8_t help_prompt = 0;
+       uint8_t code = 0;
+       uint8_t state = 0;
+       char esc_char = (char) getenv_ulong(PSTR(ENV_ESC_CHAR), 16, CONFIG_ESC_CHAR);
+
+       (void) cmdtp; (void) flag; (void) argc; (void) argv;
+
+       printf_P(PSTR("Connecting to CPU. Escape character is '^%c'.\n"),
+                                       esc_char + 0x40);
+
+       while (1) {
+
+               ATOMIC_BLOCK(ATOMIC_FORCEON) {
+                       pending = (Stat & S_CON_PENDING) != 0;
+                       Stat &= ~S_CON_PENDING;
+               }
+               if (pending) {
+                       uint8_t count = 100;
+                       while ((ch = z80_memfifo_getc(fifo_conout)) >= 0 && --count)
+                               putchar(ch);
+               }
+
+               if ((ch = my_getchar(0)) >= 0) {
+                       switch (state) {
+                       case 0:
+                               if (ch == esc_char) {
+                                       state = 1;
+                                       /* TODO: Timer starten */
+                               } else {
+                                       z80_memfifo_putc(fifo_conin, ch);
+                               }
+                               break;
+                       case 2:
+                               printf_P(PSTR("\n"
+                                 "------------------------------------------------\n"));
+                       case 1:
+                               state = 0;
+                               switch (toupper(ch)) {
+
+                               case '?':
+                               case 'H':
+                                       print_con_usage(esc_char);
+                                       state = 2;
+                                       break;
+
+                               case 'R':
+                                       reset_cpu(Restart);
+                                       break;
+
+                               case 'X':
+                               case 'Q':
+                                       printf_P(PSTR("\n"));
+                                       goto quit;
+                                       break;
+
+                               case ':':
+                                               putchar('\n');
+                                               int cmdlen = cli_readline(PSTR(": "), 1);
+                                               if (cmdlen > 0)
+                                                       run_command(console_buffer, 0);
+                                       break;
+
+                               case '\\':
+                                       code = 0;
+                                       state = 3;
+                                       break;
+
+                               default:
+                                       if (ch == esc_char)
+                                               z80_memfifo_putc(fifo_conin, ch);
+                                       break;
+                               }
+                               break;
+                       case 3:
+                               if (toupper(ch) == 'X') {
+                                       state = 6;
+                                       break;
+                               }
+                               /* fall thru */
+                       case 4:
+                       case 5:
+                               if (isdigit(ch)) {
+                                       code = code * 10 + ch - '0';
+                                       state++;
+                               } else {
+                                       if (state > 3)
+                                               z80_memfifo_putc(fifo_conin, code);
+                                       z80_memfifo_putc(fifo_conin, ch);
+                                       state = 0;
+                               }
+                               if (state > 5) {
+                                       z80_memfifo_putc(fifo_conin, code);
+                                       state = 0;
+                               }
+                               break;
+                       case 6:
+                       case 7:
+                               if (isxdigit(ch)) {
+                                       ch = toupper(ch);
+                                       if (ch >= 'A')
+                                               ch -= 'A' - 10;
+                                       code = code * 16 + ch - '0';
+                                       state++;
+                               }else {
+                                       if (state > 6)
+                                               z80_memfifo_putc(fifo_conin, code);
+                                       z80_memfifo_putc(fifo_conin, ch);
+                                       state = 0;
+                               }
+                               if (state > 7) {
+                                       z80_memfifo_putc(fifo_conin, code);
+                                       state = 0;
+                               }
+                               break;
+                       }
+               }
+       }
+quit:
+       return CMD_RET_SUCCESS;
+}
diff --git a/avr/cmd_date.c b/avr/cmd_date.c
new file mode 100644 (file)
index 0000000..3e2e016
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * RTC, Date & Time support: get and set date & time
+ */
+#include "common.h"
+#include <string.h>
+#include "time.h"
+#include "rtc.h"
+#include "command.h"
+
+
+/*
+ * simple conversion of two-digit string with error checking
+ */
+static int cnvrt2 (const char *str, int *valp)
+{
+       int val;
+
+       if ((*str < '0') || (*str > '9'))
+               return (-1);
+
+       val = *str - '0';
+
+       ++str;
+
+       if ((*str < '0') || (*str > '9'))
+               return (-1);
+
+       *valp = 10 * val + (*str - '0');
+
+       return (0);
+}
+
+/*
+ * Convert date string: MMDDhhmm[[CC]YY][.ss]
+ *
+ * Some basic checking for valid values is done, but this will not catch
+ * all possible error conditions.
+ */
+int mk_date (const char *datestr, struct tm *tmp)
+{
+       int len, val;
+       char *ptr;
+
+       ptr = strchr (datestr,'.');
+       len = strlen (datestr);
+
+       /* Set seconds */
+       if (ptr) {
+               int sec;
+
+               *ptr++ = '\0';
+               if ((len - (ptr - datestr)) != 2)
+                       return (-1);
+
+               len = strlen (datestr);
+
+               if (cnvrt2 (ptr, &sec))
+                       return (-1);
+
+               tmp->tm_sec = sec;
+       } else {
+               tmp->tm_sec = 0;
+       }
+
+       if (len == 12) {                        /* MMDDhhmmCCYY */
+               int year, century;
+
+               if (cnvrt2 (datestr+ 8, &century) ||
+                   cnvrt2 (datestr+10, &year) ) {
+                       return (-1);
+               }
+               tmp->tm_year = 100 * century + year - 1900;
+       } else if (len == 10) {         /* MMDDhhmmYY   */
+               int year, century;
+
+               century = (tmp->tm_year + 1900) / 100;
+               if (cnvrt2 (datestr+ 8, &year))
+                       return (-1);
+               tmp->tm_year = 100 * century + year -1900;
+       }
+
+       switch (len) {
+       case 8:                                 /* MMDDhhmm     */
+               /* fall thru */
+       case 10:                                /* MMDDhhmmYY   */
+               /* fall thru */
+       case 12:                                /* MMDDhhmmCCYY */
+               if (cnvrt2 (datestr+0, &val) ||
+                   val > 12) {
+                       break;
+               }
+               tmp->tm_mon  = val - 1;
+               if (cnvrt2 (datestr+2, &val) ||
+                   val > ((tmp->tm_mon==2-1) ? 29 : 31)) {
+                       break;
+               }
+               tmp->tm_mday = val;
+
+               if (cnvrt2 (datestr+4, &val) ||
+                   val > 23) {
+                       break;
+               }
+               tmp->tm_hour = val;
+
+               if (cnvrt2 (datestr+6, &val) ||
+                   val > 59) {
+                       break;
+               }
+               tmp->tm_min  = val;
+
+               return (0);
+       default:
+               break;
+       }
+
+       return (-1);
+}
+
+command_ret_t do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       struct tm t;
+       char buf[30];
+       int rc;
+       command_ret_t rcode = CMD_RET_FAILURE;
+
+       (void) cmdtp; (void) flag;
+
+       switch (argc) {
+       case 2:                 /* set date & time */
+               /* initialize t with current time */
+               if(rtc_get(&t) < 0) {
+                       my_puts_P(PSTR("## Get date failed\n"));
+                       break;
+               } else {
+                       /* insert new date & time */
+                       if (mk_date (argv[1], &t) != 0) {
+                               my_puts_P(PSTR("## Bad date format\n"));
+                               break;
+                       }
+
+                       time_t time;
+                       time = mk_gmtime(&t);
+                       gmtime_r(&time, &t);
+
+                       /* and write to RTC */
+                       if(rtc_set(&t) < 0) {
+                               my_puts_P(PSTR("## Set date failed\n"));
+                               break;
+                       }
+               }
+               /* FALL TROUGH */
+       case 1:                 /* get date & time */
+               rc = rtc_get(&t);
+               if (rc >= 0) {
+                       asctime_r(&t, buf);
+                       printf_P(PSTR("%s"), buf);
+                       if (rc == 1)
+                               printf_P(PSTR("  (Invalid)"));
+                       putchar('\n');
+                       rcode = CMD_RET_SUCCESS;
+               } else {
+                       my_puts_P(PSTR("## Get date failed\n"));
+               }
+               break;
+
+       default:
+               rcode = CMD_RET_USAGE;
+       }
+
+       return rcode;
+}
diff --git a/avr/cmd_fat.c b/avr/cmd_fat.c
new file mode 100644 (file)
index 0000000..fcf5cbc
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+ * (C) Copyright 2014,2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+/*
+ * FAT filesystem commands
+ */
+
+#include "common.h"
+#include <string.h>
+#include <stdbool.h>
+
+#include "command.h"
+#include "ff.h"
+#include "z80-if.h"
+#include "eval_arg.h"
+#include "con-utils.h"
+#include "print-utils.h"
+#include "time.h"
+#include "timer.h"
+#include "debug.h"
+
+/* TODO: use memory size test function (cmd_mem.c) */
+#define MAX_MEMORY     (1ul << 19)
+#define BUFFER_SIZE    512
+
+
+DWORD get_fattime (void)
+{
+       time_t timer;
+       struct tm tm_timer;
+
+       time(&timer);
+       gmtime_r(&timer, &tm_timer);
+
+       return fatfs_time(&tm_timer);
+}
+
+
+static bool check_abort(void)
+{
+       bool ret = ctrlc();
+
+       if (ret)
+               printf_P(PSTR("Abort\n"));
+
+       return ret;
+}
+
+
+static const FLASH char * const FLASH rc_names[] = {
+                       FSTR("OK"),
+                       FSTR("DISK_ERR"),
+                       FSTR("INT_ERR"),
+                       FSTR("NOT_READY"),
+                       FSTR("NO_FILE"),
+                       FSTR("NO_PATH"),
+                       FSTR("INVALID_NAME"),
+                       FSTR("DENIED"),
+                       FSTR("EXIST"),
+                       FSTR("INVALID_OBJECT"),
+                       FSTR("WRITE_PROTECTED"),
+                       FSTR("INVALID_DRIVE"),
+                       FSTR("NOT_ENABLED"),
+                       FSTR("NO_FILE_SYSTEM"),
+                       FSTR("MKFS_ABORTED"),
+                       FSTR("TIMEOUT"),
+                       FSTR("LOCKED"),
+                       FSTR("NOT_ENOUGH_CORE"),
+                       FSTR("TOO_MANY_OPEN_FILES"),
+                       FSTR("INVALID_PARAMETER")
+               };
+
+static
+void put_rc (FRESULT rc)
+{
+#if GCC_BUG_61443
+       printf_P(PSTR("rc=%u FR_"), rc);
+       my_puts_P(rc < ARRAY_SIZE(rc_names) ? rc_names[rc] : PSTR(" Unknown Error"));
+       my_puts_P(PSTR("\n"));
+#else
+       printf_P(PSTR("rc=%u FR_%S\n"), rc,
+       rc < ARRAY_SIZE(rc_names) ? rc_names[rc] : PSTR(" Unknown Error"));
+#endif
+}
+
+
+static void swirl(void)
+{
+       static const FLASH char swirlchar[] = { '-','\\','|','/' };
+       static uint_fast8_t cnt;
+       static uint32_t tstamp;
+
+       if (get_timer(0) > tstamp) {
+               printf_P(PSTR("\b%c"), swirlchar[cnt]);
+               cnt = (cnt+1) % ARRAY_SIZE(swirlchar);
+               tstamp = get_timer(0) + 250;
+       }
+}
+
+/* Work register for fs command */
+struct stat_dat_s {
+       DWORD AccSize;
+       WORD  AccFiles, AccDirs;
+       FILINFO Finfo;
+};
+
+static
+FRESULT scan_files (
+       char *path,                     /* Pointer to the working buffer with start path */
+       struct stat_dat_s *statp
+)
+{
+       DIR dirs;
+       FRESULT res;
+       int i;
+       char *fn;
+
+       res = f_opendir(&dirs, path);
+       swirl();
+       if (res == FR_OK) {
+               i = strlen(path);
+               while (((res = f_readdir(&dirs, &statp->Finfo)) == FR_OK) &&
+                                       statp->Finfo.fname[0]) {
+                       if (_FS_RPATH && statp->Finfo.fname[0] == '.')
+                               continue;
+                       fn = statp->Finfo.fname;
+                       if (statp->Finfo.fattrib & AM_DIR) {
+                               statp->AccDirs++;
+                               path[i] = '/';
+                               strcpy(path+i+1, fn);
+                               res = scan_files(path, statp);
+                               path[i] = '\0';
+                               if (res != FR_OK)
+                                       break;
+                       } else {
+                               //printf_P(PSTR("%s/%s\n"), path, fn);
+                               statp->AccFiles++;
+                               statp->AccSize += statp->Finfo.fsize;
+                       }
+                       if (check_abort()) {
+                               res = 255;
+                               break;
+                       }
+               }
+       }
+
+       return res;
+}
+
+
+/*
+ * fatstat path - Show logical drive status
+ *
+ */
+command_ret_t do_fat_stat(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       FATFS *fs;
+       DWORD nfreeclst;
+       FRESULT res;
+       char *path;
+       struct stat_dat_s statp;
+
+       (void) cmdtp; (void) flag; (void) argc;
+
+       path = (char *) malloc(BUFFER_SIZE);
+       if (path == NULL) {
+               printf_P(PSTR("fatstat: Out of Memory!\n"));
+               free(path);
+               return CMD_RET_FAILURE;
+       }
+
+       res = f_getfree(argv[1], &nfreeclst, &fs);
+       if (!res) {
+               printf_P(PSTR(
+                                       "FAT type:                %u\n"
+                                       "Bytes/Cluster:           %lu\n"
+                                       "Number of FATs:          %u\n"
+                                       "Root DIR entries:        %u\n"
+                                       "Sectors/FAT:             %lu\n"
+                                       "Number of clusters:      %lu\n"
+                                       "FAT start (lba):         %lu\n"
+                                       "DIR start (lba,cluster): %lu\n"
+                                       "Data start (lba):        %lu\n"),
+                               fs->fs_type, (DWORD)fs->csize * 512, fs->n_fats,
+                               fs->n_rootdir, fs->fsize, fs->n_fatent - 2,
+                               fs->fatbase, fs->dirbase, fs->database);
+
+#if _USE_LABEL
+               TCHAR label[12];
+               DWORD serial;
+               res = f_getlabel(argv[1], label, &serial);
+               if (!res) {
+                       printf_P(PSTR(
+                                               "Volume name:             %s\n"
+                                               "Volume S/N:              %04X-%04X\n"),
+                                       label, (WORD)(serial >> 16), (WORD)(serial & 0xFFFF));
+               }
+#endif
+               if (!res) {
+                       my_puts_P(PSTR("\nCounting...  "));
+                       statp.AccSize = statp.AccFiles = statp.AccDirs = 0;
+                       strcpy(path, argv[1]);
+
+                       res = scan_files(path, &statp);
+               }
+               if (!res) {
+                       printf_P(PSTR("\r%u files, %lu bytes.\n%u folders.\n"
+                                                "%lu KB total disk space.\n%lu KB available.\n"),
+                                       statp.AccFiles, statp.AccSize, statp.AccDirs,
+                                       (fs->n_fatent - 2) * (fs->csize / 2), nfreeclst * (fs->csize / 2)
+                       );
+               }
+       }
+
+       free(path);
+       if (res) {
+               put_rc(res);
+               return CMD_RET_FAILURE;
+       }
+       return CMD_RET_SUCCESS;
+}
+
+
+/*
+ * fatls path - Directory listing
+ *
+ */
+command_ret_t do_fat_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       FATFS *fs;
+       DIR Dir;                                        /* Directory object */
+       FILINFO Finfo;
+       unsigned long p1;
+       unsigned int s1, s2;
+       FRESULT res;
+
+       (void) cmdtp; (void) flag; (void) argc;
+
+       res = f_opendir(&Dir, argv[1]);
+       if (res) {
+               put_rc(res);
+               return CMD_RET_FAILURE;
+       }
+
+       p1 = s1 = s2 = 0;
+       for(;;) {
+               res = f_readdir(&Dir, &Finfo);
+               if ((res != FR_OK) || !Finfo.fname[0])
+                       break;
+               if (Finfo.fattrib & AM_DIR) {
+                       s2++;
+               } else {
+                       s1++; p1 += Finfo.fsize;
+               }
+               printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu  %s\n"),
+                                       (Finfo.fattrib & AM_DIR) ? 'D' : '-',
+                                       (Finfo.fattrib & AM_RDO) ? 'R' : '-',
+                                       (Finfo.fattrib & AM_HID) ? 'H' : '-',
+                                       (Finfo.fattrib & AM_SYS) ? 'S' : '-',
+                                       (Finfo.fattrib & AM_ARC) ? 'A' : '-',
+                                       (Finfo.fdate >> 9) + 1980, (Finfo.fdate >> 5) & 15, Finfo.fdate & 31,
+                                       (Finfo.ftime >> 11), (Finfo.ftime >> 5) & 63,
+                                       Finfo.fsize, Finfo.fname);
+               if (check_abort())
+                       break;
+       }
+
+       if (res == FR_OK) {
+               printf_P(PSTR("%4u File(s),%10lu bytes total\n%4u Dir(s)"), s1, p1, s2);
+               if (f_getfree(argv[1], (DWORD*)&p1, &fs) == FR_OK)
+                       printf_P(PSTR(", %10luK bytes free\n"), p1 * fs->csize / 2);
+       }
+
+       if (res) {
+               put_rc(res);
+               return CMD_RET_FAILURE;
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
+static
+FRESULT mkpath(TCHAR *path)
+{
+       /* TODO: */
+       (void) path;
+#if 0
+       FILINFO fd
+       TCHAR *p, *q;
+       FRESULT ret;
+
+       res = f_stat (path, &fd)
+
+       p = strchr(path, ':');
+       if (p == NULL || *++p == '\0' || *p++ != '/')
+               return FR_OK;
+
+       while ((q = strchr(p, '/')) != NULL) {
+               *q = '\0';
+               ret = f_mkdir(path);
+               *q = '/';
+                       if (ret != FR_OK && ret != FR_EXIST)
+                               return ret;
+               p = q + 1;
+       }
+#endif
+
+       return FR_OK;
+}
+
+/*
+ * fatread/write - load binary file to/from a dos filesystem
+ *             read  <d:/path/filename> <addr> [bytes [pos]]
+ *             write <d:/path/filename> <addr> <bytes>
+ */
+command_ret_t do_fat_rw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       FIL File;
+       uint32_t addr;
+       unsigned long bytes;
+       unsigned long pos;
+       unsigned long bytes_rw;
+
+       bool dowrite = (argv[0][3] == 'w');
+       FRESULT res = FR_OK;
+       bool buserr = 0;
+       uint32_t timer;
+       uint8_t *buffer;
+
+       (void) cmdtp; (void) flag;
+
+       if (argc < (dowrite ? 4 : 3))
+               return CMD_RET_USAGE;
+
+       addr = eval_arg(argv[2], NULL);
+       if (addr >= MAX_MEMORY) {
+               printf_P(PSTR("address too high: 0x%0lx\n"), addr);
+               return CMD_RET_FAILURE;
+       }
+       if (argc > 3)
+               bytes = eval_arg(argv[3], NULL);
+       else
+               bytes = MAX_MEMORY;
+       if (argc > 4)
+               pos = eval_arg(argv[4], NULL);
+       else
+               pos = 0;
+
+       if (addr + bytes > MAX_MEMORY)
+               bytes = MAX_MEMORY - addr;
+
+       buffer = (uint8_t *) malloc(BUFFER_SIZE);
+       if (buffer == NULL) {
+               printf_P(PSTR("fatstat: Out of Memory!\n"));
+               free(buffer);
+               return CMD_RET_FAILURE;
+       }
+
+       if (dowrite) {
+               res = mkpath(argv[1]);
+       }
+       if (!res) {
+               res = f_open(&File, argv[1], dowrite ? FA_WRITE | FA_CREATE_ALWAYS
+                                                                                        : FA_READ );
+
+               if (!res) {
+                       res = f_lseek(&File, pos);
+                       if (!res) {
+                               bytes_rw = 0;
+                               timer = get_timer(0);
+                               while (bytes) {
+                                       unsigned int cnt, br;
+
+                                       if (bytes >= BUFFER_SIZE)       {
+                                               cnt = BUFFER_SIZE;
+                                               bytes -= BUFFER_SIZE;
+                                       } else {
+                                               cnt = bytes; bytes = 0;
+                                       }
+                                       if (dowrite) {
+                                               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                                                       buserr = 1;
+                                                       break;
+                                               }
+                                               z80_read_block(buffer, addr, cnt);
+                                               z80_bus_cmd(Release);
+                                               res = f_write(&File, buffer, cnt, &br);
+                                               if (res != FR_OK)
+                                                       break;
+                                       } else {
+                                               res = f_read(&File, buffer, cnt, &br);
+                                               if (res != FR_OK)
+                                                       break;
+                                               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                                                       buserr = 1;
+                                                       break;
+                                               }
+                                               z80_write_block(buffer, addr, br);
+                                               z80_bus_cmd(Release);
+                                       }
+                                       addr += br;
+
+                                       bytes_rw += br;
+                                       if (cnt != br) {
+                                               if (dowrite)
+                                                       printf_P(PSTR("Disk full?\n"));
+                                               break;
+                                       }
+                                       if (check_abort())
+                                               break;
+                               }
+
+                               FRESULT fr = f_close(&File);
+                               if (!res)
+                                       res = fr;
+                               timer = get_timer(timer);
+                               printf_P(PSTR("%lu (0x%lx) bytes read/written with %lu bytes/sec.\n"),
+                                                       bytes_rw, bytes_rw, timer ? (bytes_rw * 1000 / timer) : 0);
+                       }
+               }
+       }
+
+       free(buffer);
+
+       if (buserr)
+               my_puts_P(PSTR("Bus timeout\n"));
+       if (res)
+               put_rc(res);
+       if (buserr || res)
+               return CMD_RET_FAILURE;
+
+       return CMD_RET_SUCCESS;
+}
diff --git a/avr/cmd_gpio.c b/avr/cmd_gpio.c
new file mode 100644 (file)
index 0000000..5cc02d0
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "common.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "command.h"
+#include "print-utils.h"
+#include "getopt-min.h"
+#include "env.h"
+#include "gpio.h"
+//#include "debug.h"
+
+
+
+static const int namestr = GPIO_MAX;
+static char *pin_names[GPIO_MAX+1];
+static uint_least8_t pin_names_width;
+
+static void pinnames_get(void)
+{
+       static const FLASH char delim1[] = {":= "};
+       static const FLASH char delim2[] = {", "};
+       char *lp;
+       char *ptr;
+       uint_fast8_t i;
+
+       if (pin_names[namestr] != NULL)
+               free(pin_names[namestr]);
+       memset(pin_names, 0, sizeof(pin_names));
+       pin_names_width = 0;
+
+/* TODO: enters endless loop on wrong parameters */
+
+       if ((lp = getenv_str(PSTR(ENV_PINALIAS))) != NULL) {
+               pin_names[namestr] = strdup(lp);
+               ptr = strtok_P(pin_names[namestr], delim1);
+               while (ptr != NULL) {
+                       if (((i = strtoul(ptr, &lp, 10)) < GPIO_MAX) &&
+                                       lp != ptr &&
+                                       (ptr = strtok_P(NULL, delim2)) != NULL ) {
+                               pin_names[i] = ptr;
+                               ptr = strtok_P(NULL, delim1);
+                       }
+               }
+
+               for (i = 0; i < GPIO_MAX; i++)
+                       if (strlen(pin_names[i]) > pin_names_width)
+                               pin_names_width = strlen(pin_names[i]);
+       }
+}
+
+
+static size_t xstrlen(char *s)
+{
+       if (s == NULL)
+               return 0;
+       else
+               return strlen(s);
+}
+
+static const FLASH char * const FLASH pinconf_str[] = {
+                       FSTR("?"),
+                       FSTR("Input"),
+                       FSTR("Pullup"),
+                       FSTR("Output"),
+                       FSTR("Clock"),
+               };
+
+static const FLASH char * const FLASH pinlevel_str[] = {
+                       FSTR("Low"),
+                       FSTR("High"),
+                       FSTR(""),
+               };
+
+static int print_pin(int pin, int multi)
+{
+       int pinconf;
+       const FLASH char *levelp;
+       long div;
+
+       pinconf = gpio_config_get(pin);
+       if (pinconf == OUTPUT_TIMER) {
+               div = gpio_clockdiv_get(pin);
+               levelp = pinlevel_str[2];
+       } else
+               levelp = pinlevel_str[gpio_read(pin)];
+
+       if (multi) {
+               printf_P(PSTR("%3d "), pin);
+               if (pin_names_width) {
+                       printf_P(PSTR("%s "), pin_names[pin]);
+                       print_blanks(pin_names_width - xstrlen(pin_names[pin]));
+               }
+               my_puts_P(pinconf_str[pinconf]);
+               print_blanks(7 - strlen_P(pinconf_str[pinconf]));
+               my_puts_P(levelp);
+               print_blanks(5 - strlen_P(levelp));
+               if (pinconf == OUTPUT_TIMER)
+                       printf_P(PSTR("%8ld  %8ld"),
+                               div, F_CPU/div);
+       } else {
+               printf_P(PSTR("%d: \"%s\", "), pin, pin_names[pin] ? pin_names[pin] : 0);
+               my_puts_P(pinconf_str[pinconf]);
+               printf_P(PSTR(", "));
+               my_puts_P(levelp);
+
+               if (pinconf == OUTPUT_TIMER)
+                       printf_P(PSTR("divide by %ld (%ldHz)"),
+                               div, F_CPU/div);
+       }
+       printf_P(PSTR("\n"));
+
+       return 0;
+}
+
+static int_fast8_t pinarg_insert(int pin, uint_fast8_t count, uint_fast8_t pinarg[])
+{
+       uint_fast8_t pos;
+
+       if (pin < 0 || pin >= GPIO_MAX)
+               return -1;
+
+       for (pos = 0; pos < count; pos++) {
+               if (pin == pinarg[pos])
+                       return 0;
+               if (pin <  pinarg[pos])
+                       break;
+       }
+       for (uint_fast8_t i = count-1; i == pos ; i--)
+               pinarg[i+1] = pinarg[i];
+       pinarg[pos] = pin;
+
+       return 1;
+}
+
+static uint_fast8_t pinarg_get(char * arg, uint_fast8_t pinarg[])
+{
+       char *endp;
+       uint_fast8_t pin1;
+       int_fast8_t rc;
+       uint_fast8_t count = 0;
+
+       while (1) {
+               pin1 = strtoul(arg, &endp, 10);
+               if (endp != arg && *endp == '-') {
+                       arg = endp+1;
+                       uint_fast8_t pin2 = (int) strtoul(arg, &endp, 10);
+                       if (pin1 < pin2)
+                               for (; pin1 < pin2; pin1++)
+                                       if ((rc = pinarg_insert(pin1, count, pinarg)) >= 0)
+                                               count += rc;
+                                       else
+                                               return 0;
+                       else
+                               return 0;
+               }
+               if (endp != arg) {
+                       if ((*endp == ',' || *endp == '\0') &&
+                                       (rc = pinarg_insert(pin1, count, pinarg)) >= 0) {
+                               count += rc;
+                               if (*endp == '\0')
+                                       return count;
+                       } else
+                                       return 0;
+               } else
+                       return 0;
+
+               arg = endp+1;
+       }
+}
+
+
+command_ret_t do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+       char printheader = 1;
+       uint_fast8_t pinarg[GPIO_MAX];
+       uint_fast8_t pinargc;
+
+       (void) cmdtp; (void) flag;
+
+       /* reset getopt() */
+       optind = 0;
+
+       int opt;
+       while ((opt = getopt(argc, argv, PSTR("s"))) != -1) {
+               switch (opt) {
+               case 's':
+                       printheader = 0;
+                       break;
+               default: /* '?' */
+                       return CMD_RET_USAGE;
+               }
+       }
+
+       /* remaining arguments */
+       argc -= optind;
+
+       pinnames_get();
+
+       if (argc == 0) {
+               /* print cofig of all pins */
+               for (pinargc = 0; pinargc < GPIO_MAX; pinargc++)
+                       pinarg[pinargc] = pinargc;
+       } else {
+               /* get first arg */
+               pinargc = pinarg_get(argv[optind++], pinarg);
+               if (pinargc == 0)
+                       return CMD_RET_USAGE;
+               else
+                       argc--;
+       }
+
+       if (argc == 0) {
+               /* no more args, print config */
+               if (pinargc == 1)
+                       print_pin(pinarg[0], 0);
+               else {
+                       if (printheader) {
+                               if (pin_names_width > 0) {
+                                       if ( strlen("Name") > pin_names_width)
+                                               pin_names_width = strlen("Name");
+                                       char s[pin_names_width+1];
+                                       memset(s, ' ', pin_names_width);
+                                       s[pin_names_width] = '\0';
+                                       strncpy_P(s, PSTR("Name"), 4);
+                                       printf_P(PSTR("Pin %s Config Level Divider  Frequency/Hz\n"),s);
+                                       memset(s, '-', pin_names_width);
+                                       printf_P(PSTR("----%s-----------------------------------\n"), s);
+                               } else
+                                       printf_P(PSTR("Pin Config Level Divider  Frequency/Hz\n"
+                                                     "--------------------------------------\n"));
+                       }
+                       for (uint_fast8_t i = 0; i < pinargc; i++)
+                               print_pin(pinarg[i], 1);
+               }
+               return CMD_RET_SUCCESS;
+       }
+
+       /* arguments must be in pairs: pins conf */
+       if (argc % 2 != 1)
+               return CMD_RET_USAGE;
+
+       while (argc > 0) {
+               char *endp;
+               gpiomode_t mode = NONE;
+               int level = 0;
+               unsigned long value = 0;
+               uint8_t hz_flag = 0;
+
+               switch (toupper(argv[optind][0])) {
+               case 'H':
+                       level = 1;
+               case 'L':
+                       mode = OUTPUT;
+                       break;
+               case 'P':
+                       mode = INPUT_PULLUP;
+                       break;
+               case 'I':
+               case 'T':
+                       mode = INPUT;
+                       break;
+
+               default:
+                       value = strtoul(argv[optind], &endp, 10);
+                       switch (*endp) {
+                       case 'M':
+                               value *= 1000;
+                       case 'K':
+                               value *= 1000;
+                               endp++;
+                       }
+
+                       if (*endp && strcmp_P(endp, PSTR("Hz")) == 0) {
+                               hz_flag = 1;
+                               endp += 2;
+                       }
+
+                       if (*endp != '\0') {
+                               printf_P(PSTR("invalid parameter: '%s'\n"), argv[optind]);
+                               return CMD_RET_USAGE;
+                       }
+
+                       if (value == 0) {
+                               printf_P(PSTR("invalid value: %lu \n"));
+                               return CMD_RET_USAGE;
+                       }
+
+                       if (hz_flag) {
+                               if (value > F_CPU / 2) {
+                                       printf_P(PSTR("Max frequency is: %luHz\n"), F_CPU/2);
+                                       return CMD_RET_USAGE;
+                               }
+                               value = F_CPU/value;
+                       }
+                       mode = OUTPUT_TIMER;
+
+               }
+
+               if (mode == NONE)
+                       return CMD_RET_USAGE;
+
+               for (uint_fast8_t i = 0; i < pinargc; i++) {
+                       switch (mode) {
+                       case OUTPUT:
+                               gpio_write(pinarg[i], level);
+                               /* fall thru */
+                       case INPUT:
+                       case INPUT_PULLUP:
+                               gpio_config(pinarg[i], mode);
+                               break;
+                       case OUTPUT_TIMER:
+                               if (gpio_clockdiv_set(pinarg[i], value) < 0) {
+                                       printf_P(PSTR("Setting pin %d to %lu failed.\n"),
+                                                               pinarg[i], value);
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               optind++;
+               pinargc = pinarg_get(argv[optind++], pinarg);
+               argc -= 2;
+       }
+
+       return CMD_RET_SUCCESS;
+}
diff --git a/avr/cmd_help.c b/avr/cmd_help.c
new file mode 100644 (file)
index 0000000..010339d
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "common.h"
+#include "command.h"
+
+command_ret_t do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       const int len = cmd_tbl_item_count();
+       return _do_help(cmd_tbl, len, cmdtp, flag, argc, argv);
+}
diff --git a/avr/cmd_loadcpm3.c b/avr/cmd_loadcpm3.c
new file mode 100644 (file)
index 0000000..e6e2cdc
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * (C) Copyright 2015,2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+/*
+ * See CP/M 3 System Manual, Appendix D: CPM3.SYS File Format
+ */
+
+#include "common.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "command.h"
+#include "env.h"
+#include "ff.h"
+#include "eval_arg.h"
+#include "con-utils.h"
+#include "z80-if.h"
+#include "debug.h"
+
+
+#define RS             128             /* CP/M record size */
+
+#define FSIZE_t DWORD
+
+/*
+ *     Load Routine
+ *
+ *     Input:  addr = Page Address of load top
+ *                     len  = Length in pages of module to read
+ *
+ */
+int load(FIL *File, uint32_t addr, uint8_t len)
+{
+       uint8_t buffer[RS];
+       unsigned int br;                                        /* bytes read */
+       int res;
+
+       len *= 2;               /* length in records of module */
+       //debug("## load: addr: 0x%.4X, records: 0x%.4X, (%u)\n", addr, len, len);
+
+       for (; len; len--) {
+               addr -= RS;
+               res = f_read(File, buffer, RS, &br);
+               if (res || br != RS) {
+                       return 1;
+               }
+
+               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                       my_puts_P(PSTR("Bus timeout\n"));
+                       return 2;
+               }
+               z80_write_block(buffer, addr, RS);
+               z80_bus_cmd(Release);
+               //debug("## written: 0x%.4X\n", addr);
+       }
+
+       return 0;
+}
+
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+
+command_ret_t do_loadcpm3(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint16_t mem_top;
+       uint8_t res_len;
+       uint16_t bank_top;
+       uint8_t bank_len;
+       uint16_t osentry_addr = 0;
+       uint32_t common_base = 0;
+       uint32_t banked_base;
+       char *fname;
+       FIL File;
+       char default_fname[] = CONFIG_CPM3_SYSFILE;
+       unsigned int br;                                        /* bytes read */
+       uint8_t buffer[RS];
+       int res;
+
+       (void) cmdtp; (void) flag;
+
+
+       //common_base = getenv_ulong(PSTR(ENV_CPM3_COMMON_BASE), 16,
+       //                                      CONFIG_CPM3_COMMON_BASE);
+       banked_base = getenv_ulong(PSTR(ENV_CPM3_BANKED_BASE), 16,
+                                               CONFIG_CPM3_BANKED_BASE);
+
+       if (argc > 3)
+               banked_base = eval_arg(argv[3], NULL);
+       if (argc > 2)
+               common_base = eval_arg(argv[2], NULL);
+
+       fname = getenv_str(PSTR(ENV_CPM3_SYSFILE));
+       if (argc > 1) {
+               fname = argv[1];
+       }
+       if (fname == NULL || *fname == '\0')
+               fname = default_fname;
+
+       res = f_open(&File, fname, FA_READ );
+       if (res) {
+               printf_P(PSTR("Error: failed to open '%s'\n"), fname);
+               return CMD_RET_FAILURE;
+       }
+
+       printf_P(PSTR("Loading: '%s'...\n"), fname);
+
+       /* read the load record */
+       res = f_read(&File, buffer, RS, &br);
+       if (res || br != RS)
+               goto out;
+
+       mem_top = buffer[0] << 8;
+       res_len = buffer[1];
+       bank_top = buffer[2] << 8;
+       bank_len = buffer[3];
+       osentry_addr = buffer[4] + (buffer[5] << 8);
+
+       /* read display info */
+       res = f_read(&File, buffer, RS, &br);
+       if (res || br != RS)
+               goto out;
+
+       /* print the info */
+       buffer[RS-1] = '$';
+       uint8_t *p = memchr(buffer, '$', RS);
+       *p = '\0';
+       my_puts((char *)buffer);
+
+       if (common_base == 0) {
+               /* read common base
+                * http://www.seasip.info/Cpm/scb.html
+                */
+               FSIZE_t common_base_ofs = ((res_len - 6) << 8)  + 2*RS + RS-7;
+               FSIZE_t cur_pos = f_tell(&File);
+               if ((res = f_lseek(&File, common_base_ofs)) ||
+                               (res = f_read(&File, buffer, 2, &br)) ||
+                               (br != 2) ||
+                               (res = f_lseek(&File, cur_pos)))
+                       goto out;
+               common_base = (uint16_t) buffer[0] + (buffer[1] << 8);
+               setenv_hex(PSTR(ENV_CPM3_COMMON_BASE), common_base);
+       }
+
+       setenv_hex(PSTR(ENV_CPM3_SCB), mem_top - ((res_len - (6 - 1)) << 8) + common_base);
+
+       /* Main System Load     */
+
+       /* Load Common Portion of System */
+       if ((res = load(&File, common_base + mem_top, res_len)) != 0)
+               goto out;
+
+       /* Load Banked Portion of System */
+       res = load(&File, banked_base + bank_top, bank_len);
+
+out:
+       f_close(&File);
+
+       if (res) {
+               printf_P(PSTR("Error: failed to read '%s'\n"), fname);
+               return CMD_RET_FAILURE;
+       } else {
+               if (res_len != 0) {
+                       if (osentry_addr + common_base > 0xffff) {
+                               z80_bus_cmd(Request);
+                               if (z80_read(osentry_addr + common_base) == 0xc3) {
+                                       osentry_addr = z80_read(osentry_addr+common_base+1) +
+                                                       (z80_read(osentry_addr + common_base+2) << 8);
+                               }
+                               z80_bus_cmd(Release);
+                               if (banked_base + osentry_addr > 0xffff)
+                                       osentry_addr = 0;
+                       }
+                       setenv_hex(PSTR(ENV_STARTADDRESS), osentry_addr);
+               }
+               printf_P(PSTR("Loaded: Resident: "));
+               if (res_len != 0)
+                       printf_P(PSTR("0x%.5lX-0x%.5lX, "),
+                               (common_base + mem_top) - res_len*256,
+                               (common_base + mem_top) - 1);
+               else
+                       printf_P(PSTR(" -  "));
+               printf_P(PSTR("Banked: "));
+               if (bank_len != 0)
+                       printf_P(PSTR("0x%.5lX-0x%.5lX\n"),
+                       (banked_base + bank_top) - bank_len*256,
+                       (banked_base + bank_top) - 1);
+               else
+                       printf_P(PSTR(" -  \n"));
+
+               return CMD_RET_SUCCESS;
+       }
+}
diff --git a/avr/cmd_loadihex.c b/avr/cmd_loadihex.c
new file mode 100644 (file)
index 0000000..18d5331
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * (C) Copyright 2015 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "common.h"
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdbool.h>
+
+#include "command.h"
+#include "con-utils.h"
+#include "z80-if.h"
+#include "debug.h"
+
+
+uint32_t detect_ramsize(void)
+{
+       uint32_t addr;
+       uint8_t save_addr, save_0;
+       const uint8_t PATTERN_1 = 0x55;
+       const uint8_t PATTERN_2 = ~PATTERN_1;
+
+       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+               my_puts_P(PSTR("Bus timeout\n"));
+               return  0;
+       }
+
+       save_0 = z80_read(0);
+       z80_write(0, PATTERN_1);
+
+       for (addr=1; addr < CONFIG_SYS_RAMSIZE_MAX; addr <<= 1) {
+               save_addr = z80_read(addr);
+               z80_write(addr, PATTERN_2);
+               if (z80_read(0) != PATTERN_1 || z80_read(addr) != PATTERN_2)
+                       break;
+               z80_write(addr, save_addr);
+       }
+       z80_write(0, save_0);
+       z80_bus_cmd(Release);
+
+       return addr;
+}
+
+typedef enum {
+       IHX_OK,
+       IHX_BROKEN,
+       IHX_CHKSUMERR
+} ihx_rstat_t;
+
+typedef struct {
+       ihx_rstat_t status;
+       int8_t type;
+       uint8_t len;
+       uint16_t address;
+       uint8_t data[256];
+} ihex_t;
+
+
+static
+int get_hexdigit(void) {
+
+       int c;
+       c = toupper(my_getchar(1));
+       if (isxdigit(c)) {
+               c -= '0';
+               if (c > 9)
+                       c -= ('A' - '0' - 10);
+               return c;
+       } else
+               return -1;
+}
+
+static
+int get_hexbyte(void) {
+
+       uint8_t i,j;
+
+       if ((i = (uint8_t) get_hexdigit()) < 0x10)
+               if ((j = (uint8_t) get_hexdigit()) < 0x10) {
+                       return (i<<4) + j;
+               }
+
+       return -1;
+}
+
+
+static
+int ihex_get_record(ihex_t *rec) {
+
+       int c;
+       uint8_t sum;
+
+       rec->status = IHX_BROKEN;
+       rec->len = 0;
+       rec->type = 0xff;
+
+       while ((c = my_getchar(0)) != ':') {
+               if (c == 0x03)
+                       return -1;                                      /* Control-C */
+               if (c == 0x04) {
+                       rec->status = IHX_OK;
+                       return 0;                                       /*Control-D, EOF */
+               }
+       }
+
+       if ((c = get_hexbyte()) < 0)            /* Start code */
+                       return -1;
+       sum = c;
+       rec->len = c;
+       if ((c = get_hexbyte()) < 0)            /* Byte Count */
+                       return -1;
+       sum += c;
+       rec->address = c * 256;
+       if ((c = get_hexbyte()) < 0)            /* Address */
+                       return -1;
+       sum += c;
+       rec->address += c;
+       if ((c = get_hexbyte()) < 0)            /* Record type */
+               return -1;
+       sum += c;
+       rec->type = c;
+
+       if (rec->len) {                                         /* Record Data */
+               uint8_t n;
+
+               for (n = 0; n < rec->len; n++) {
+                       if ((c = get_hexbyte()) < 0)
+                               break;
+                       sum += c;
+                       rec->data[n] = c;
+               }
+
+               if (n < rec->len) {
+                       return -1;
+               }
+       }
+
+       c = get_hexbyte();                              /* Check sum */
+
+       if (c >= 0) {
+               sum += c;
+               if (sum == 0)
+                       rec->status = IHX_OK;
+               else
+                       rec->status = IHX_CHKSUMERR;
+       }
+
+       return rec->len;
+}
+
+
+command_ret_t do_loadihex(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       long offset = 0;
+       uint32_t base_address = 0;
+       uint32_t address_max = detect_ramsize();
+       uint32_t address_high = 0;
+       uint32_t address_low = address_max;
+       command_ret_t rcode = CMD_RET_FAILURE;
+       ihex_t rec;
+       bool firstrec = true;
+
+       (void) cmdtp; (void) flag;
+
+
+       if (argc > 1)
+               offset = strtol(argv[1], NULL, 16);
+
+       printf_P(PSTR("Waiting for Intel Hex Records...\n"));
+
+       while (ihex_get_record(&rec) > 0 &&
+                               rec.status == IHX_OK &&
+                               rec.type != 1 ) {
+
+               switch (rec.type) {
+               case 0: /* Data record */
+                       if (firstrec) {
+                               printf_P(PSTR("Loading: 0x....."));
+                               firstrec = false;
+                       }
+                       if (rec.len) {
+                               uint32_t addr = base_address + rec.address + offset;
+                               if (addr < address_low)
+                                       address_low = addr;
+                               if (addr+rec.len > address_high)
+                                       address_high = addr + rec.len;
+
+//                             debug("low: 0x%.5lX, high: 0x%.5lX, max: 0x%.5lX, addr: 0x%.5lX, len: %d\n",
+//                                     address_low, address_high, address_max, addr, rec.len);
+                               printf_P(PSTR("\b\b\b\b\b%.5lX"), addr);
+                               if (addr < address_max) {
+                                       uint32_t tmplen = address_max - addr;
+                                       if (rec.len > tmplen)
+                                               rec.len = tmplen;
+
+                                       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                                               my_puts_P(PSTR("Bus timeout\n"));
+                                               return  CMD_RET_FAILURE;
+                                       }
+                                       z80_write_block(rec.data,               /* src */
+                                                       addr,                                   /* dest */
+                                                       rec.len);                               /* len */
+                                       z80_bus_cmd(Release);
+                               }
+                       }
+                       break;
+
+#if 0
+               case 1: /* EOF record */
+                       break;
+#endif
+               case 2: /* Extended Segment Address Record */
+                       base_address = (uint32_t)((rec.data[0] << 8) + rec.data[1]) << 4;
+                       break;
+
+               case 4: /* Extended Linear Address Record */
+                       base_address = (uint32_t)((rec.data[0] << 8) + rec.data[1]) << 16;
+                       break;
+
+               case 3: /* Start Segment Address Record (ignored)*/
+               case 5: /* Start Linear Address Record (ignored)*/
+                       break;
+
+               }
+       }
+
+       switch (rec.status) {
+       case IHX_OK:
+               rcode = CMD_RET_SUCCESS;
+               break;
+
+       case IHX_BROKEN:
+       case IHX_CHKSUMERR:
+               printf_P(PSTR("Broken Hex Record or loading interrupted!\n"));
+               break;
+       }
+
+
+       for (uint_fast8_t i=0; i<100; ++i) {
+               /* flush input buffer */
+               while (my_getchar(0) > 0)
+                       ;
+               udelay(1000);
+       }
+
+
+       printf_P(PSTR("\nData loaded: "));
+       if (address_low >= MIN(address_high, address_max))
+               printf_P(PSTR("None.\n"));
+       else
+               printf_P(PSTR("low: 0x%.5lX high: 0x%.5lX\n"), address_low,
+                               MIN(address_high, address_max) - 1);
+
+       if (address_high > address_max)
+               printf_P(PSTR("Data above highest RAM address "
+                       "(in range 0x%.5lX - 0x%.5lX) ignored!\n"), address_max, address_high - 1);
+
+       return rcode;
+}
diff --git a/avr/cmd_mem.c b/avr/cmd_mem.c
new file mode 100644 (file)
index 0000000..315cd71
--- /dev/null
@@ -0,0 +1,797 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+/*
+ * Memory Functions
+ *
+ * Copied from FADS ROM, Dan Malek (dmalek@jlc.net)
+ */
+
+#include "common.h"
+#include <ctype.h>
+#include <avr/interrupt.h>
+
+#include "command.h"
+#include "cli_readline.h"
+#include "print-utils.h"
+#include "con-utils.h"
+#include "getopt-min.h"
+#include "eval_arg.h"
+#include "timer.h"
+#include "z80-if.h"
+#include "debug.h"
+
+
+#ifndef CONFIG_SYS_MEMTEST_SCRATCH
+#define CONFIG_SYS_MEMTEST_SCRATCH 0
+#endif
+
+/* Display values from last command.
+ * Memory modify remembered values are different from display memory.
+ */
+static uint32_t        dp_last_addr;
+static uint32_t        dp_last_length = 0x100;
+static uint32_t        mm_last_addr;
+
+static uint32_t        base_address = 0;
+
+/*--------------------------------------------------------------------------*/
+
+int z180_read_buf(uint8_t *buf, uint32_t addr, uint8_t count)
+{
+       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED))
+               return -1;
+
+       z80_read_block (buf, addr, count);
+       z80_bus_cmd(Release);
+       return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Memory Display
+ *
+ * Syntax:
+ *     md {addr} {len}
+ */
+command_ret_t do_mem_md(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint32_t addr, length;
+
+       (void) cmdtp;
+
+#if 0
+       printf_P(PSTR("flag: %d, argc: %d"), flag, argc);
+       for (int i = 0; i < argc; i++) {
+               printf_P(PSTR(", argv[%d]: %s"), i, argv[i] ? argv[i] : "<NULL>");
+       }
+       putchar('\n');
+#endif
+
+       /* We use the last specified parameters, unless new ones are
+        * entered.
+        */
+       addr = dp_last_addr;
+       length = dp_last_length;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       if ((flag & CMD_FLAG_REPEAT) == 0) {
+               /* Address is specified since argc > 1 */
+               addr = eval_arg(argv[1], NULL);
+               addr += base_address;
+
+               /* If another parameter, it is the length to display. */
+               if (argc > 2)
+                       length = eval_arg(argv[2], NULL);
+       }
+
+       /* Print the lines. */
+       int ret = dump_mem(addr, addr, length, z180_read_buf, NULL);
+       if (ret == -2)  { /* TODO: Error codes */
+               my_puts_P(PSTR("Bus timeout\n"));
+               return  CMD_RET_FAILURE;
+       }
+
+       if (ret >= 0) {
+               dp_last_addr = addr + length;
+               dp_last_length = length;
+       }
+       return CMD_RET_SUCCESS;
+}
+
+/* Modify memory.
+ *
+ * Syntax:
+ *     mm {addr}
+ *     nm {addr}
+ */
+static command_ret_t
+mod_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[])
+{
+       uint32_t addr;
+       uint8_t data;
+       int nbytes;
+
+       (void) cmdtp;
+
+       if (argc != 2)
+               return CMD_RET_USAGE;
+
+       /* We use the last specified parameters, unless new ones are
+        * entered.
+        */
+       addr = mm_last_addr;
+
+       if ((flag & CMD_FLAG_REPEAT) == 0) {
+               /* New command specified.
+                */
+
+               /* Address is specified since argc > 1
+               */
+               addr = eval_arg(argv[1], NULL);
+               addr += base_address;
+       }
+
+       /* Print the address, followed by value.  Then accept input for
+        * the next value.  A non-converted value exits.
+        */
+       do {
+               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                       my_puts_P(PSTR("Bus timeout\n"));
+                       return  CMD_RET_FAILURE;
+               }
+               data = z80_read(addr);
+               z80_bus_cmd(Release);
+               printf_P(PSTR("%05lx: %02x"), addr, data);
+
+               nbytes = cli_readline(PSTR(" ? "), 0);
+               if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
+                       /* <CR> pressed as only input, don't modify current
+                        * location and move to next. "-" pressed will go back.
+                        */
+                       if (incrflag)
+                               addr += nbytes ? -1 : 1;
+                       nbytes = 1;
+
+               } else {
+                       char *endp;
+                       data = eval_arg(console_buffer, &endp);
+                       nbytes = endp - console_buffer;
+                       if (nbytes) {
+                               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                                       my_puts_P(PSTR("Bus timeout\n"));
+                                       return  CMD_RET_FAILURE;
+                               }
+                               z80_write(addr, data);
+                               z80_bus_cmd(Release);
+                               if (incrflag)
+                                       addr++;
+                       }
+               }
+       } while (nbytes > 0);
+
+       mm_last_addr = addr;
+       return CMD_RET_SUCCESS;
+}
+
+
+command_ret_t do_mem_mm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       return mod_mem (cmdtp, 1, flag, argc, argv);
+}
+command_ret_t do_mem_nm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       return mod_mem (cmdtp, 0, flag, argc, argv);
+}
+
+command_ret_t do_mem_mw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint32_t writeval;
+       uint32_t addr;
+       uint32_t count = 1;
+       uint_fast8_t width = 1;
+
+       (void) cmdtp; (void) flag;
+
+       /* reset getopt() */
+       optind = 0;
+
+       int opt;
+       while ((opt = getopt(argc, argv, PSTR("bwl"))) != -1) {
+               switch (opt) {
+               case 'b':
+                       width = 1;
+                       break;
+               case 'w':
+                       width = 2;
+                       break;
+               case 'l':
+                       width = 4;
+                       break;
+               default: /* '?' */
+                       return CMD_RET_USAGE;
+               }
+       }
+
+       /* remaining arguments */
+       argc -= optind;
+       if ((argc < 2) || (argc > 3))
+               return CMD_RET_USAGE;
+
+       /* Address and value are specified since (adjusted) argc >= 2 */
+       addr = eval_arg(argv[optind++], NULL);
+       addr += base_address;
+       writeval = eval_arg(argv[optind++], NULL);
+
+       /* Count ? */
+       if (argc == 3)
+               count = eval_arg(argv[optind], NULL);
+
+       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+               my_puts_P(PSTR("Bus timeout\n"));
+               return  CMD_RET_FAILURE;
+       }
+
+       if (width == 1)
+               z80_memset(addr, writeval, count);
+       else {
+               while (count--) {
+                       z80_write_block((const uint8_t *) &writeval, addr, width);
+                       addr += width;
+               }
+       }
+       z80_bus_cmd(Release);
+
+       return CMD_RET_SUCCESS;
+}
+
+#ifdef CONFIG_MX_CYCLIC
+command_ret_t do_mem_mdc ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint32_t count;
+       uint32_t ts;
+
+       (void) cmdtp;
+       (void) flag;
+
+       optind = 0;
+       if (argv[0][1] != 'd') {
+               int opt;
+               while ((opt = getopt(argc, argv, PSTR("bwl"))) != -1)
+                       if (opt == '?')
+                               return CMD_RET_USAGE;
+               --optind;
+       }
+
+       if (argc-optind != 4)
+               return CMD_RET_USAGE;
+
+       count = eval_arg(argv[optind + 3], NULL);
+
+       clear_ctrlc();          /* forget any previous Control C */
+       for (;;) {
+
+               if (argv[0][1] == 'd')
+                       do_mem_md (NULL, 0, argc-1, argv);              /* memory display */
+               else
+                       do_mem_mw (NULL, 0, argc-1, argv);              /* memory write */
+
+
+               /* delay for <count> ms... */
+               ts = get_timer(0);
+               do {
+                       /* check for ctrl-c to abort... */
+                       if (had_ctrlc() || ctrlc()) {
+                               my_puts_P(PSTR("Abort\n"));
+                               return CMD_RET_SUCCESS;
+                       }
+               } while (get_timer(ts) < count);
+       }
+
+       return CMD_RET_SUCCESS;
+}
+#endif /* CONFIG_MX_CYCLIC */
+
+command_ret_t do_mem_cmp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint32_t addr1, addr2, count, ngood;
+       command_ret_t rcode = CMD_RET_SUCCESS;
+       uint8_t byte1, byte2;
+
+       (void) cmdtp;
+       (void) flag;
+
+       if (argc != 4)
+               return CMD_RET_USAGE;
+
+
+       addr1 = eval_arg(argv[1], NULL);
+       addr1 += base_address;
+       addr2 = eval_arg(argv[2], NULL);
+       addr2 += base_address;
+       count = eval_arg(argv[3], NULL);
+
+       for (ngood = 0; ngood < count; ++ngood) {
+               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                       my_puts_P(PSTR("Bus timeout\n"));
+                       rcode =  CMD_RET_FAILURE;
+                       break;
+               }
+               byte1 = z80_read(addr1);
+               byte2 = z80_read(addr2);
+               z80_bus_cmd(Release);
+               if (byte1 != byte2) {
+                       printf_P(PSTR("byte at 0x%05lx (%#02x) != "
+                               "byte at 0x%05lx (%#02x)\n"),
+                               addr1, byte1, addr2, byte2);
+                       rcode = CMD_RET_FAILURE;
+                       break;
+               }
+               addr1++;
+               addr2++;
+
+               /* check for ctrl-c to abort... */
+               if (ctrlc()) {
+                       my_puts_P(PSTR("Abort\n"));
+                       return CMD_RET_SUCCESS;
+               }
+       }
+
+       printf_P(PSTR("Total of %ld byte(s) (0x%lx) were the same\n"), ngood, ngood);
+       return rcode;
+}
+
+command_ret_t do_mem_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint32_t src, dest, count;
+       int_fast8_t step;
+
+       (void) cmdtp;
+       (void) flag;
+
+       if (argc != 4)
+               return CMD_RET_USAGE;
+
+       src = eval_arg(argv[1], NULL);
+       src += base_address;
+       dest = eval_arg(argv[2], NULL);
+       dest += base_address;
+       count = eval_arg(argv[3], NULL);
+
+       if (count == 0) {
+               my_puts_P(PSTR("Zero length?\n"));
+               return CMD_RET_FAILURE;
+       }
+
+       if (dest > src) {
+               src += count - 1;
+               dest += count - 1;
+               step = -1;
+       } else
+               step = 1;
+
+       while (count-- > 0) {
+               uint8_t data;
+               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                       my_puts_P(PSTR("Bus timeout\n"));
+                       return  CMD_RET_FAILURE;
+               }
+               data = z80_read(src);
+               z80_write(dest, data);
+               z80_bus_cmd(Release);
+               src += step;
+               dest += step;
+
+               /* check for ctrl-c to abort... */
+               if (ctrlc()) {
+                       my_puts_P(PSTR("Abort\n"));
+                       return CMD_RET_SUCCESS;
+               }
+       }
+       return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_mem_base(cmd_tbl_t *cmdtp, int flag, int argc,
+                      char * const argv[])
+{
+       (void) cmdtp;
+       (void) flag;
+
+       if (argc > 1) {
+               /* Set new base address. */
+               base_address = eval_arg(argv[1], NULL);
+       }
+       /* Print the current base address. */
+       printf_P(PSTR("Base Address: 0x%05lx\n"), base_address);
+       return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_mem_loop(cmd_tbl_t *cmdtp, int flag, int argc,
+                      char * const argv[])
+{
+       uint32_t addr, length;
+
+       (void) cmdtp;
+       (void) flag;
+
+       if (argc < 3)
+               return CMD_RET_USAGE;
+
+       /* Address is always specified. */
+       addr = eval_arg(argv[1], NULL);
+
+       /* Length is the number of bytes. */
+       length = eval_arg(argv[2], NULL);
+
+
+       /* We want to optimize the loops to run as fast as possible.
+        * If we have only one object, just run infinite loops.
+        */
+       if (length == 1) {
+               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                       my_puts_P(PSTR("Bus timeout\n"));
+                       return  CMD_RET_FAILURE;
+               }
+               cli();
+               for (;;)
+                       z80_read(addr);
+       }
+
+       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+               my_puts_P(PSTR("Bus timeout\n"));
+               return  CMD_RET_FAILURE;
+       }
+       cli();
+       for (;;) {
+               uint32_t i = length;
+               uint32_t p = addr;
+               while (i-- > 0)
+                       z80_read(p++);
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_mem_loopw (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint32_t addr, length;
+       uint8_t data;
+
+       (void) cmdtp;
+       (void) flag;
+
+       if (argc < 4)
+               return CMD_RET_USAGE;
+
+       /* Address is always specified. */
+       addr = eval_arg(argv[1], NULL);
+
+       /* Length is the number of bytes. */
+       length = eval_arg(argv[2], NULL);
+
+       data = eval_arg(argv[3], NULL);
+
+       /*
+        * We want to optimize the loops to run as fast as possible.
+        * If we have only one object, just run infinite loops.
+        */
+       if (length == 1) {
+               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                       my_puts_P(PSTR("Bus timeout\n"));
+                       return  CMD_RET_FAILURE;
+               }
+               cli();
+               for (;;)
+                       z80_write(addr, data);
+       }
+
+       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+               my_puts_P(PSTR("Bus timeout\n"));
+               return  CMD_RET_FAILURE;
+       }
+       cli();
+       for (;;) {
+               uint32_t i = length;
+               uint32_t p = addr;
+               while (i-- > 0)
+                       z80_write(p++, data);
+       }
+}
+
+//#define CONFIG_SYS_ALT_MEMTEST
+
+#ifdef CONFIG_CMD_MEMTEST
+static uint32_t mem_test_alt(uint32_t start_addr, uint32_t end_addr)
+{
+       uint32_t addr;
+       uint32_t dummy;
+       uint32_t errs = 0;
+       uint32_t offset;
+       uint32_t test_offset;
+       uint8_t pattern;
+       uint8_t anti_pattern;
+       uint8_t temp;
+       uint32_t num_bytes;
+
+       static const FLASH uint8_t bitpattern[] = {
+               0x01,   /* single bit */
+               0x03,   /* two adjacent bits */
+               0x07,   /* three adjacent bits */
+               0x0F,   /* four adjacent bits */
+               0x05,   /* two non-adjacent bits */
+               0x15,   /* three non-adjacent bits */
+               0x55,   /* four non-adjacent bits */
+               0xaa,   /* alternating 1/0 */
+       };
+
+       /*
+        * Data line test: write a pattern to the first
+        * location, write the 1's complement to a 'parking'
+        * address (changes the state of the data bus so a
+        * floating bus doesn't give a false OK), and then
+        * read the value back. Note that we read it back
+        * into a variable because the next time we read it,
+        * it might be right (been there, tough to explain to
+        * the quality guys why it prints a failure when the
+        * "is" and "should be" are obviously the same in the
+        * error message).
+        *
+        * Rather than exhaustively testing, we test some
+        * patterns by shifting '1' bits through a field of
+        * '0's and '0' bits through a field of '1's (i.e.
+        * pattern and ~pattern).
+        */
+       addr = start_addr;
+       dummy = start_addr+1;
+       for (unsigned int j = 0; j < ARRAY_SIZE(bitpattern); j++) {
+               pattern = bitpattern[j];
+               for (; pattern != 0; pattern <<= 1) {
+                       anti_pattern = ~pattern;
+                       z80_write(addr, pattern);
+                       z80_write(dummy, anti_pattern); /* clear the test data off the bus */
+                       temp = z80_read(addr);
+                       if (temp != pattern) {
+                               printf_P(PSTR("FAILURE (data line): "
+                                       "expected %02x, actual %02x\n"),
+                                               pattern, temp);
+                               errs++;
+                       }
+                       z80_write(addr, anti_pattern);
+                       z80_write(dummy, pattern); /* clear the test data off the bus */
+                       temp = z80_read(addr);
+                       if (temp != anti_pattern) {
+                               printf_P(PSTR("FAILURE (data line): "
+                                       "Is %02x, should be %02x\n"),
+                                               temp, anti_pattern);
+                               errs++;
+                       }
+               }
+
+               if (ctrlc())
+                       return -1;
+       }
+
+       if (errs)
+               return errs;
+
+       /*
+        * Based on code whose Original Author and Copyright
+        * information follows: Copyright (c) 1998 by Michael
+        * Barr. This software is placed into the public
+        * domain and may be used for any purpose. However,
+        * this notice must not be changed or removed and no
+        * warranty is either expressed or implied by its
+        * publication or distribution.
+        */
+
+       /*
+       * Address line test
+
+        * Description: Test the address bus wiring in a
+        *              memory region by performing a walking
+        *              1's test on the relevant bits of the
+        *              address and checking for aliasing.
+        *              This test will find single-bit
+        *              address failures such as stuck-high,
+        *              stuck-low, and shorted pins. The base
+        *              address and size of the region are
+        *              selected by the caller.
+
+        * Notes:       For best results, the selected base
+        *              address should have enough LSB 0's to
+        *              guarantee single address bit changes.
+        *              For example, to test a 64-Kbyte
+        *              region, select a base address on a
+        *              64-Kbyte boundary. Also, select the
+        *              region size as a power-of-two if at
+        *              all possible.
+        *
+        * Returns:     0 if the test succeeds, 1 if the test fails.
+        */
+
+       num_bytes = (end_addr - start_addr) / sizeof(uint8_t);
+
+       pattern = 0xaa;
+       anti_pattern = 0x55;
+
+//     debug("## %s:%d: length = 0x%.5lx\n", __func__, __LINE__, num_bytes);
+       /*
+        * Write the default pattern at each of the
+        * power-of-two offsets.
+        */
+       for (offset = 1; offset < num_bytes; offset <<= 1)
+               z80_write(addr+offset, pattern);
+
+       /*
+        * Check for address bits stuck high.
+        */
+       z80_write(start_addr, anti_pattern);
+
+       for (offset = 1; offset < num_bytes; offset <<= 1) {
+               temp = z80_read(start_addr + offset);
+               if (temp != pattern) {
+                       printf_P(PSTR("FAILURE: Address bit stuck high @ 0x%.5lx:"
+                               " expected 0x%.2x, actual 0x%.2x\n"),
+                               start_addr + offset, pattern, temp);
+                       errs++;
+                       if (ctrlc())
+                               return -1;
+               }
+       }
+       z80_write(start_addr, pattern);
+
+       /*
+        * Check for addr bits stuck low or shorted.
+        */
+       for (test_offset = 1; test_offset < num_bytes; test_offset <<= 1) {
+               z80_write(start_addr + test_offset, anti_pattern);
+
+               for (offset = 1; offset < num_bytes; offset <<= 1) {
+                       temp = z80_read(start_addr + offset);
+                       if ((temp != pattern) && (offset != test_offset)) {
+                               printf_P(PSTR("FAILURE: Address bit stuck low or shorted"
+                                       " @ 0x%.5lx: expected 0x%.2x, actual 0x%.2x\n"),
+                                       start_addr + offset, pattern, temp);
+                               errs++;
+                               if (ctrlc())
+                                       return -1;
+                       }
+               }
+               z80_write(start_addr + test_offset, pattern);
+       }
+
+       if (errs)
+               return errs;
+
+       /*
+        * Description: Test the integrity of a physical
+        *              memory device by performing an
+        *              increment/decrement test over the
+        *              entire region. In the process every
+        *              storage bit in the device is tested
+        *              as a zero and a one. The base address
+        *              and the size of the region are
+        *              selected by the caller.
+        *
+        * Returns:     0 if the test succeeds, 1 if the test fails.
+        */
+       num_bytes++;
+
+       /*
+        * Fill memory with a known pattern.
+        */
+       for (pattern = 1, addr = start_addr; addr <= end_addr; pattern++, addr++)
+               z80_write(addr, pattern);
+
+       /*
+        * Check each location and invert it for the second pass.
+        */
+       for (pattern = 1, addr = start_addr; addr <= end_addr; pattern++, addr++) {
+               temp = z80_read(addr);
+               if (temp != pattern) {
+                       printf_P(PSTR("FAILURE (read/write) @ 0x%.5lx:"
+                               " expected 0x%.2x, actual 0x%.2x)\n"),
+                               addr, pattern, temp);
+                       errs++;
+                       if (ctrlc())
+                               return -1;
+               }
+
+               anti_pattern = ~pattern;
+               z80_write(addr, anti_pattern);
+       }
+
+       /*
+        * Check each location for the inverted pattern and zero it.
+        */
+       for (pattern = 1, addr = start_addr; addr <= end_addr; pattern++, addr++) {
+               anti_pattern = ~pattern;
+               temp = z80_read(addr);
+               if (temp != anti_pattern) {
+                       printf_P(PSTR("FAILURE (read/write) @ 0x%.5lx:"
+                               " expected 0x%.2x, actual 0x%.2x)\n"),
+                               start_addr,     anti_pattern, temp);
+                       errs++;
+                       if (ctrlc())
+                               return -1;
+               }
+               z80_write(addr, 0);
+       }
+
+       return errs;
+}
+
+/*
+ * Perform a memory test. A more complete alternative test can be
+ * configured using CONFIG_SYS_ALT_MEMTEST. The complete test loops until
+ * interrupted by ctrl-c or by a failure of one of the sub-tests.
+ */
+command_ret_t do_mem_mtest(cmd_tbl_t *cmdtp, int flag, int argc,
+                       char * const argv[])
+{
+       uint32_t start = 0;
+       uint32_t end;
+       unsigned int iteration_limit = 0;
+       unsigned int iteration;
+       uint32_t errs = 0;      /* number of errors */
+       int ret;
+
+       (void) cmdtp;
+       (void) flag;
+
+       if (argc > 1)
+               start = eval_arg(argv[1], NULL);
+
+       if (argc > 2)
+               end = eval_arg(argv[2], NULL);
+       else
+               end = CONFIG_SYS_RAMSIZE_MAX - 1;
+
+       if (argc > 3)
+               iteration_limit = (unsigned int) eval_arg(argv[3], NULL);
+
+       printf_P(PSTR("Testing %05lx ... %05lx:\n"), start, end);
+//     debug("## %s:%d: start %#05lx end %#05lx\n", __func__, __LINE__, start, end);
+
+       clear_ctrlc();          /* forget any previous Control C */
+
+       for (iteration = 0;
+                       !iteration_limit || iteration < iteration_limit;
+                       iteration++) {
+
+               printf_P(PSTR("Iteration: %6d\r"), iteration + 1);
+//             debug("\n");
+
+               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                       my_puts_P(PSTR("Bus timeout\n"));
+                       return  CMD_RET_FAILURE;
+               }
+               errs += mem_test_alt(start, end);
+               z80_bus_cmd(Release);
+
+               if (had_ctrlc() || ctrlc()) {
+                       break;
+               }
+       }
+
+       if (had_ctrlc()) {
+               /* Memory test was aborted - write a newline to finish off */
+               putchar('\n');
+               ret = CMD_RET_FAILURE;
+       } else {
+               printf_P(PSTR("Tested %d iteration(s) with %lu errors.\n"),
+                       iteration, errs);
+               ret = errs ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+       }
+
+       return ret;
+}
+#endif /* CONFIG_CMD_MEMTEST */
diff --git a/avr/cmd_misc.c b/avr/cmd_misc.c
new file mode 100644 (file)
index 0000000..9061b5a
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * (C) Copyright 2014,2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include "common.h"
+#include "eval_arg.h"
+#include <stdbool.h>
+
+#include "command.h"
+#include "timer.h"
+#include "con-utils.h"
+#include "getopt-min.h"
+
+
+command_ret_t do_echo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       bool put_newline = true;
+
+       (void) cmdtp; (void) flag;
+
+       /* reset getopt() */
+       optind = 0;
+
+       int opt;
+       while ((opt = getopt(argc, argv, PSTR("n"))) != -1) {
+               switch (opt) {
+               case 'n':
+                       put_newline = false;
+                       break;
+               default: /* '?' */
+                       return CMD_RET_USAGE;
+               }
+       }
+
+       for (uint_fast8_t i = optind; i < argc; i++) {
+
+               if (i != optind)
+                       putchar(' ');
+
+               my_puts(argv[i]);
+       }
+
+       if (put_newline)
+               putchar('\n');
+
+       return CMD_RET_SUCCESS;
+}
+
+
+command_ret_t do_sleep(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       unsigned long start = get_timer(0);
+       unsigned long delay;
+       char *sp;
+       uint_fast8_t millisec = 0;
+
+       (void) cmdtp; (void) flag;
+
+       if (argc != 2)
+               return CMD_RET_USAGE;
+
+       delay = eval_arg(argv[1], &sp);
+
+       if (*sp == 'm') {
+               millisec = 1;
+               sp++;
+       }
+       if (*sp == 's')
+               sp++;
+       if (*sp != '\0')
+               return CMD_RET_USAGE;
+
+       if (!millisec)
+               delay *= 1000;
+
+       while (get_timer(start) < delay) {
+               if (ctrlc())
+                       return CMD_RET_FAILURE;
+
+               udelay(100);
+       }
+
+       return CMD_RET_SUCCESS;
+}
diff --git a/avr/cmd_run.c b/avr/cmd_run.c
new file mode 100644 (file)
index 0000000..8593ef5
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * (C) Copyright 2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include "common.h"
+#include <string.h>
+#include <stdio.h>
+
+#include "ff.h"
+#include "config.h"
+#include "command.h"
+#include "cli_readline.h"      /* console_buffer[] */
+#include "cli.h"                       /* run_command() */
+#include "env.h"
+
+
+command_ret_t do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       int i;
+       (void) cmdtp;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       for (i = 1; i < argc; ++i) {
+               char *arg;
+
+               arg = getenv_str(argv[i]);
+               if (arg == NULL) {
+                       printf_P(PSTR("## Error: \"%s\" is not set\n"), argv[i]);
+                       return CMD_RET_FAILURE;
+               }
+
+               if (run_command(arg, flag) != 0)
+                       return CMD_RET_FAILURE;
+       }
+       return CMD_RET_SUCCESS;
+}
+
+static int source(FIL *fp, int flag, int argc, char * const argv[])
+{
+       int lineno = 0;
+       int res = 0;
+
+       (void)argc; (void)argv;
+
+       while (!f_eof(fp) && !f_error(fp) && !res) {
+               lineno++;
+               if (f_gets(console_buffer, CONFIG_SYS_CBSIZE, fp)) {
+                       int i = strlen(console_buffer) - 1;
+                       if (i != 0) {
+                               if (i > 0) {
+                                       if (console_buffer[i] != '\n') {
+                                               printf_P(PSTR("Error: line %d to long\n"), lineno);
+                                               res = -1;
+                                               break;
+                                       }
+                               }
+                               console_buffer[i] = 0;
+                               res = run_command(console_buffer, flag);
+                       }
+               }
+       }
+       return !f_eof(fp) || res;
+}
+
+command_ret_t do_source(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       FIL File;
+       int res;
+
+       (void) cmdtp;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       res = f_open(&File, argv[1], FA_READ );
+       if (res) {
+               printf_P(PSTR("Error: failed to open script '%s'\n"), argv[1]);
+               return CMD_RET_FAILURE;
+       }
+
+       printf_P(PSTR("Executing script: '%s'...\n"), argv[1]);
+       res = source(&File, flag, --argc, ++argv);
+       f_close(&File);
+       if (res != 0) {
+               return CMD_RET_FAILURE;
+       }
+       return CMD_RET_SUCCESS;
+}
diff --git a/avr/cmd_sd.c b/avr/cmd_sd.c
new file mode 100644 (file)
index 0000000..b84c4be
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "common.h"
+//#include <stdlib.h>
+
+#include "command.h"
+#include "diskio.h"
+#include "ff.h"
+#include "eval_arg.h"
+#include "print-utils.h"
+#include "z80-if.h"
+
+
+/*
+ * status <pd#> - Show socket status
+ *
+ */
+static
+command_ret_t do_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       DSTATUS res;
+       BYTE dev;
+
+       (void) cmdtp; (void) flag;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       dev = (BYTE) eval_arg(argv[1], NULL);
+       res = disk_status(dev);
+       printf_P(PSTR("Socket status: %02x\n"), res);
+
+       return CMD_RET_SUCCESS;
+}
+
+/*
+ * init <pd#> - Initialize disk
+ *
+ */
+static
+command_ret_t do_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       DSTATUS res;
+       BYTE dev;
+
+       (void) cmdtp; (void) flag;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       dev = (BYTE) eval_arg(argv[1], NULL);
+
+       if (disk_status(dev) & STA_NODISK) {
+               printf_P(PSTR("No Disk\n"));
+               return CMD_RET_FAILURE;
+       }
+
+       res = disk_initialize(dev);
+       printf_P(PSTR("rc=%.2x\n"), res);
+
+       if (res & (STA_NODISK | STA_NOINIT))
+               return CMD_RET_FAILURE;
+
+       return CMD_RET_SUCCESS;
+}
+
+/*
+ * info <pd#> - Show disk info
+ *
+ */
+static
+command_ret_t do_info(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       DSTATUS res;
+       BYTE dev;
+
+       union {
+               unsigned char uca[64];
+               unsigned long ul;
+               unsigned char uc;
+       } dat;
+
+       (void) cmdtp; (void) flag;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       dev = (BYTE) eval_arg(argv[1], NULL);
+
+       res = disk_status(dev);
+       if (res & (STA_NODISK | STA_NOINIT)) {
+               printf_P(res & STA_NODISK ?
+                               PSTR("No disk\n") : PSTR("Not initialized\n"));
+               return CMD_RET_FAILURE;
+       }
+
+       if (disk_ioctl(dev, GET_SECTOR_COUNT, &dat.ul) == RES_OK)
+               printf_P(PSTR("Drive size: %lu sectors\n"), dat.ul);
+       if (disk_ioctl(dev, GET_BLOCK_SIZE, &dat.ul) == RES_OK)
+               printf_P(PSTR("Erase block: %lu sectors\n"), dat.ul);
+       if (disk_ioctl(dev, MMC_GET_TYPE, &dat.uc) == RES_OK)
+               printf_P(PSTR("Card type: %u\n"), dat.uc);
+       if (disk_ioctl(dev, MMC_GET_CSD, dat.uca) == RES_OK)
+               dump_ram(dat.uca, 0, 16, "CSD:");
+       if (disk_ioctl(dev, MMC_GET_CID, dat.uca) == RES_OK)
+               dump_ram(dat.uca, 0, 16, "CID:");
+       if (disk_ioctl(dev, MMC_GET_OCR, dat.uca) == RES_OK)
+               dump_ram(dat.uca, 0, 4, "OCR:");
+       if (disk_ioctl(dev, MMC_GET_SDSTAT, dat.uca) == RES_OK)
+               dump_ram(dat.uca, 0, 64, "SD Status:");
+
+       return CMD_RET_SUCCESS;
+}
+
+
+/*
+ * dump <pd#> [<sector> [count]] - Dump sector
+ *
+ */
+static
+command_ret_t do_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       static BYTE dev_last;
+       static  DWORD sec_last;
+       BYTE buffer[_MAX_SS];
+       char header[20];
+
+       DRESULT res;
+       BYTE dev;
+       DWORD sec;
+       UINT count;
+
+       (void) cmdtp; (void) flag;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       dev = (BYTE) eval_arg(argv[1], NULL);
+       if (dev != dev_last)
+               sec_last = 0;
+       sec = sec_last;
+       count = 1;
+
+       if ((flag & CMD_FLAG_REPEAT) == 0) {
+               /* If another parameter, it is the sector to dump. */
+               if (argc > 2)
+                       sec = eval_arg(argv[2], NULL);
+               if (argc > 3)
+                       count = (UINT) eval_arg(argv[3], NULL);
+       }
+
+       for ( ; count; count--, sec++) {
+               res = disk_read(dev, buffer, sec, 1);
+
+               if (res) {
+                       printf_P(PSTR("rc=%.2x\n"), res);
+                       return CMD_RET_FAILURE;
+               }
+
+               sprintf_P(header, PSTR("Sector: %lu"), sec);
+               dump_ram(buffer, 0, _MAX_SS, header);
+       }
+       dev_last = dev;
+       sec_last = sec;
+
+       return CMD_RET_SUCCESS;
+}
+
+/*
+ * read drive sector count memaddr - Read disk into memory
+ *
+ */
+static
+command_ret_t do_read(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       DRESULT res;
+       BYTE dev;
+       DWORD sec;
+       uint32_t addr;
+       int count, nr;
+       BYTE buffer[_MAX_SS];
+
+       static DWORD sec_last;
+       static uint32_t addr_last;
+
+       (void) cmdtp;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       dev = (BYTE) eval_arg(argv[1], NULL);
+       sec = sec_last;
+       count = 1;
+       addr = addr_last;
+
+       if ((flag & CMD_FLAG_REPEAT) == 0) {
+               /* If another parameter, it is the sector to dump. */
+               if (argc > 2)
+                       sec = eval_arg(argv[2], NULL);
+               if (argc > 3)
+                       count = eval_arg(argv[3], NULL);
+               if (argc > 4)
+                       addr = eval_arg(argv[4], NULL);
+       }
+
+       for (nr = 0; nr < count;) {
+               nr++;
+               if ((res = disk_read(dev, buffer, sec, 1)) == RES_OK) {
+                       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                               my_puts_P(PSTR("Bus timeout\n"));
+                               return  CMD_RET_FAILURE;
+                       }
+                       z80_write_block(buffer, addr /*+ base*/, _MAX_SS);
+                       z80_bus_cmd(Release);
+                       sec++; addr += _MAX_SS;
+               } else
+                       break;
+       }
+
+       printf_P(PSTR("Read %d sector(s), rc=%.2x.\n"), nr, res);
+       if (res)
+               printf_P(PSTR("Last sector not written!\n"));
+
+       sec_last = sec;
+       addr_last = addr;
+
+       return res ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+
+/*
+ * write <pd#> <sector> <memaddr> [<n>] - Write memory to disk
+ *
+ */
+static
+command_ret_t do_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       DRESULT res;
+       BYTE dev;
+       DWORD sec;
+       uint32_t addr;
+       int count, nr;
+       BYTE buffer[_MAX_SS];
+
+       static DWORD sec_last;
+       static uint32_t addr_last;
+
+       (void) cmdtp;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       dev = (BYTE) eval_arg(argv[1], NULL);
+       sec = sec_last;
+       addr = addr_last;
+       count = 1;
+
+       if ((flag & CMD_FLAG_REPEAT) == 0) {
+               /* If another parameter, it is the sector to dump. */
+               if (argc > 2)
+                       sec = eval_arg(argv[2], NULL);
+               if (argc > 3)
+                       count = eval_arg(argv[3], NULL);
+               if (argc > 4)
+                       addr = eval_arg(argv[4], NULL);
+       }
+
+       for (nr = 0; nr < count;) {
+               nr++;
+               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                       my_puts_P(PSTR("Bus timeout\n"));
+                       return  CMD_RET_FAILURE;
+               }
+               z80_read_block(buffer, addr /*+ base*/, _MAX_SS);
+               z80_bus_cmd(Release);
+
+               res = disk_write(dev, buffer, sec, 1);
+               if (res != RES_OK)
+                       break;
+               sec++; addr += _MAX_SS;
+       }
+
+       printf_P(PSTR("%d sector(s) written, rc=%.2x.\n"), nr, res);
+
+       sec_last = sec;
+       addr_last = addr;
+
+       return res ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+
+
+/*
+ * Disk ioctl
+ * sync <pd#> - CTRL_SYNC
+ *
+ */
+static
+command_ret_t do_ioctl_sync(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       BYTE dev;
+
+       (void) cmdtp; (void) flag;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       dev = (BYTE) eval_arg(argv[1], NULL);
+       printf_P(PSTR("rc=%.2x\n"), disk_ioctl(dev, CTRL_SYNC, 0));
+
+       return CMD_RET_SUCCESS;
+}
+
+
+static
+command_ret_t do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+cmd_tbl_t cmd_sd_sub[] = {
+CMD_TBL_ITEM(
+       status, 2,                      1,      do_status,
+       "Socket staus",
+       "drive"
+),
+CMD_TBL_ITEM(
+       init,   2,                      1,      do_init,
+       "Initialize disk",
+       "drive"
+),
+CMD_TBL_ITEM(
+       info,   2,                      1,      do_info,
+       "Disk info",
+       "drive"
+),
+CMD_TBL_ITEM(
+       dump,   CONFIG_SYS_MAXARGS,     1,      do_dump,
+       "Dump sector(s)",
+       "drive [sector [count ]]"
+),
+CMD_TBL_ITEM(
+       read,   2,                      1,      do_read,
+       "Read disk sector(s) into meomory",
+       "drive [sector [count [memaddr]]]"
+),
+CMD_TBL_ITEM(
+       write,  2,                      1,      do_write,
+       "Write sector(s) from meomory to disk",
+       "drive [sector [count [memaddr]]]"
+),
+CMD_TBL_ITEM(
+       sync,   2,                      1,      do_ioctl_sync,
+       "Device control: SYNC",
+       "drive"
+),
+
+CMD_TBL_ITEM(
+       help,   CONFIG_SYS_MAXARGS,     1,      do_help,
+       "Print sub command description/usage",
+       "\n"
+       "       - print brief description of all sub commands\n"
+       "sd help command ...\n"
+       "       - print detailed usage of sub cmd 'command'"
+),
+
+/* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
+       {FSTR("?"),   CONFIG_SYS_MAXARGS, 1, do_help,
+        FSTR("Alias for 'help'"),
+#ifdef  CONFIG_SYS_LONGHELP
+       FSTR(""),
+#endif /* CONFIG_SYS_LONGHELP */
+#ifdef CONFIG_AUTO_COMPLETE
+       0,
+#endif
+},
+};
+
+static
+command_ret_t do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       return _do_help(cmd_sd_sub, ARRAY_SIZE(cmd_sd_sub), cmdtp, flag, argc, argv);
+}
+
+
+command_ret_t do_sd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       cmd_tbl_t *cp;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       /* drop initial "sd" arg */
+       argc--;
+       argv++;
+
+       cp = find_cmd_tbl(argv[0], cmd_sd_sub, ARRAY_SIZE(cmd_sd_sub));
+
+       if (cp)
+               return cp->cmd(cmdtp, flag, argc, argv);
+
+       return CMD_RET_USAGE;
+}
diff --git a/avr/command.c b/avr/command.c
new file mode 100644 (file)
index 0000000..cd2ee39
--- /dev/null
@@ -0,0 +1,552 @@
+/*
+ * (C) Copyright 2014, 2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+/*
+ *  Command Processor Table
+ */
+
+#include "command.h"
+#include "common.h"
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <setjmp.h>
+
+#include "config.h"
+#include "print-utils.h"
+#include "con-utils.h"
+#include "env.h"
+#include "debug.h"
+
+
+jmp_buf cmd_jbuf;
+
+
+static void print_usage_line(const FLASH char *name, int width,
+                               const FLASH char *usage)
+{
+       width -= strlen_P(name);
+       if (width < 0)
+               width = 0;
+       my_puts_P(name);
+       print_blanks(width);
+       my_puts_P(PSTR(" - "));
+       my_puts_P(usage);
+       my_puts_P(PSTR("\n"));
+}
+
+int strcmp_PP(const FLASH char *s1, const FLASH char *s2)
+{
+       unsigned char c1, c2;
+
+       while ((c1 = *(const FLASH unsigned char *)s1++)
+                       == (c2 = *(const FLASH unsigned char *)s2++))
+               if (c1 == 0)
+                       return 0;
+
+       return c1 - c2;
+}
+
+int cmpstring_PP(const void *p1, const void *p2)
+{
+       return strcmp_PP((*(const FLASH cmd_tbl_t **) p1)->name,
+                        (*(const FLASH cmd_tbl_t **) p2)->name);
+}
+
+int cmd_tbl_item_count(void)
+{
+       cmd_tbl_t * p = cmd_tbl;
+       int count = 0;
+
+       while (p->name != NULL) {
+               p++; count++;
+       }
+       return count;
+}
+
+/*
+ * Use puts() instead of printf() to avoid printf buffer overflow
+ * for long help messages
+ */
+
+command_ret_t _do_help(cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp,
+               int flag, int argc, char * const argv[])
+{
+       uint_fast8_t i, max_len = 0;
+       command_ret_t rcode = CMD_RET_SUCCESS;
+
+       (void) flag;
+
+       char *optenv = getenv_str(PSTR("cmd"));
+       bool opt_debug = optenv && strstr_P(optenv, PSTR("debug")) != NULL;
+
+       if (argc == 1) {        /*show list of commands */
+               cmd_tbl_t *cmd_array[cmd_items];
+               int i;
+
+               /* Make array of commands from .uboot_cmd section */
+               cmdtp = cmd_start;
+               for (i = 0; i < cmd_items; i++) {
+                       cmd_array[i] = cmdtp++;
+                       uint_fast8_t l = strlen_P(cmd_array[i]->name);
+                       if (l > max_len)
+                               max_len = l;
+               }
+
+               /* Sort command list */
+               qsort(cmd_array, cmd_items, sizeof (cmd_tbl_t *), cmpstring_PP);
+
+               /* print short help (usage) */
+               for (i = 0; i < cmd_items; i++) {
+                       if (opt_debug || cmd_array[i]->name[0] != '!') {
+                               const FLASH char *usage = cmd_array[i]->usage;
+
+                               /* allow user abort */
+                               if (ctrlc ())
+                                       return CMD_RET_FAILURE;
+                               if (usage == NULL)
+                                       continue;
+#ifdef GCC_BUG_61443
+                               print_usage_line(cmd_array[i]->name, max_len, usage);
+#else
+                               printf_P(PSTR("%-" stringify(8) /*FIXME*/ "S - %S\n"),
+                                               cmd_array[i]->name, usage);
+#endif
+                       }
+               }
+               return CMD_RET_SUCCESS;
+       }
+       /*
+        * command help (long version)
+        */
+       for (i = 1; i < argc; ++i) {
+               if ((cmdtp = find_cmd_tbl (argv[i], cmd_start, cmd_items )) != NULL &&
+                                       (opt_debug || cmdtp->name[0] != '!')) {
+                       cmd_usage(cmdtp);
+               } else {
+                       printf_P(PSTR("Unknown command '%s' - try 'help'"
+                               " without arguments.\n\n"), argv[i]
+                               );
+                       rcode = CMD_RET_FAILURE;
+               }
+       }
+       return rcode;
+}
+
+/***************************************************************************
+ * find command table entry for a command
+ */
+cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
+{
+       cmd_tbl_t *cmdtp;
+       cmd_tbl_t *cmdtp_temp = table;  /*Init value */
+       size_t len;
+       uint_fast8_t n_found = 0;
+
+       char *optenv = getenv_str(PSTR("cmd"));
+       bool opt_debug = optenv && strstr_P(optenv, PSTR("debug")) != NULL;
+
+       if (!cmd)
+               return NULL;
+
+       len = strlen(cmd);
+
+       for (cmdtp = table;
+            cmdtp != table + table_len;
+            cmdtp++) {
+               if (strncmp_P(cmd, cmdtp->name, len) == 0 &&
+                                       (opt_debug || cmdtp->name[0] != '!')) {
+                       if (len == strlen_P(cmdtp->name))
+                               return cmdtp;   /* full match */
+
+                       cmdtp_temp = cmdtp;     /* abbreviated command ? */
+                       n_found++;
+               }
+       }
+       if (n_found == 1)                       /* exactly one match */
+               return cmdtp_temp;
+
+       return NULL;    /* not found or ambiguous command */
+}
+
+
+cmd_tbl_t *find_cmd (const char *cmd)
+{
+       return find_cmd_tbl(cmd, cmd_tbl, cmd_tbl_item_count());
+}
+
+
+command_ret_t cmd_usage(const FLASH cmd_tbl_t *cmdtp)
+{
+//     printf("%s - %s\n\n", cmdtp->name, cmdtp->usage);
+       print_usage_line(cmdtp->name, 0, cmdtp->usage);
+#if 0
+       my_puts_P(cmdtp->name);
+       print_blanks(/*FIXME*/ 8 - strlen_P(cmdtp->name));
+       my_puts_P(PSTR(" - "));
+       my_puts_P(cmdtp->usage);
+       my_puts_P(PSTR("\n\n"));
+#endif
+#ifdef CONFIG_SYS_LONGHELP
+//     printf("Usage:\n%s ", cmdtp->name);
+       my_puts_P(PSTR("Usage:\n"));
+       my_puts_P(cmdtp->name);
+       my_puts_P(PSTR(" "));
+
+       if (!cmdtp->help) {
+               my_puts_P(PSTR(" - No additional help available.\n"));
+               return CMD_RET_FAILURE;
+       }
+
+       my_puts_P(cmdtp->help);
+       my_puts_P(PSTR("\n"));
+#endif /* CONFIG_SYS_LONGHELP */
+       return CMD_RET_FAILURE;
+}
+
+#ifdef CONFIG_AUTO_COMPLETE
+
+int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
+{
+       static char tmp_buf[CONFIG_SYS_CBSIZE];
+       int space;
+
+       space = last_char == '\0' || isblank(last_char);
+
+       if (space && argc == 1)
+               return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
+
+       if (!space && argc == 2)
+               return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
+
+       return 0;
+}
+
+/*************************************************************************************/
+
+/* TODO: cmdtp points to FLASH */
+
+static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
+{
+       cmd_tbl_t *cmdtp = cmd_tbl;
+//     const int count = ARRAY_SIZE(cmd_tbl);
+//     const cmd_tbl_t *cmdend = cmdtp + count;
+//     const char *p;
+       int len, clen;
+       int n_found = 0;
+       const char *cmd;
+
+       /* sanity? */
+       if (maxv < 2)
+               return -2;
+
+       cmdv[0] = NULL;
+
+       if (argc == 0) {
+               /* output full list of commands */
+               for (; cmdtp->name[0] != '\0'; cmdtp++) {
+                       if (n_found >= maxv - 2) {
+                               cmdv[n_found++] = "...";
+                               break;
+                       }
+                       cmdv[n_found++] = cmdtp->name;
+               }
+               cmdv[n_found] = NULL;
+               return n_found;
+       }
+
+       /* more than one arg or one but the start of the next */
+       if (argc > 1 || (last_char == '\0' || isblank(last_char))) {
+               cmdtp = find_cmd(argv[0]);
+               if (cmdtp == NULL || cmdtp->complete == NULL) {
+                       cmdv[0] = NULL;
+                       return 0;
+               }
+               return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
+       }
+
+       cmd = argv[0];
+
+       len = strlen(cmd);
+
+       /* return the partial matches */
+       for (; cmdtp->name[0] != '\0'; cmdtp++) {
+
+               clen = strlen(cmdtp->name);
+               if (clen < len)
+                       continue;
+
+               if (memcmp(cmd, cmdtp->name, len) != 0)
+                       continue;
+
+               /* too many! */
+               if (n_found >= maxv - 2) {
+                       cmdv[n_found++] = "...";
+                       break;
+               }
+
+               cmdv[n_found++] = cmdtp->name;
+       }
+
+       cmdv[n_found] = NULL;
+       return n_found;
+}
+
+static int make_argv(char *s, int argvsz, char *argv[])
+{
+       int argc = 0;
+
+       /* split into argv */
+       while (argc < argvsz - 1) {
+
+               /* skip any white space */
+               while (isblank(*s))
+                       ++s;
+
+               if (*s == '\0') /* end of s, no more args       */
+                       break;
+
+               argv[argc++] = s;       /* begin of argument string     */
+
+               /* find end of string */
+               while (*s && !isblank(*s))
+                       ++s;
+
+               if (*s == '\0')         /* end of s, no more args       */
+                       break;
+
+               *s++ = '\0';            /* terminate current arg         */
+       }
+       argv[argc] = NULL;
+
+       return argc;
+}
+
+static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char * const argv[])
+{
+       int ll = leader != NULL ? strlen(leader) : 0;
+       int sl = sep != NULL ? strlen(sep) : 0;
+       int len, i;
+
+       if (banner) {
+               my_puts_P(PSTR("\n"));
+               my_puts(banner);
+       }
+
+       i = linemax;    /* force leader and newline */
+       while (*argv != NULL) {
+               len = strlen(*argv) + sl;
+               if (i + len >= linemax) {
+                       my_puts_P(PSTR("\n"));
+                       if (leader)
+                               my_puts(leader);
+                       i = ll - sl;
+               } else if (sep)
+                       my_puts(sep);
+               my_puts(*argv++);
+               i += len;
+       }
+       my_puts_P(PSTR("\n"));
+}
+
+static int find_common_prefix(char * const argv[])
+{
+       int i, len;
+       char *anchor, *s, *t;
+
+       if (*argv == NULL)
+               return 0;
+
+       /* begin with max */
+       anchor = *argv++;
+       len = strlen(anchor);
+       while ((t = *argv++) != NULL) {
+               s = anchor;
+               for (i = 0; i < len; i++, t++, s++) {
+                       if (*t != *s)
+                               break;
+               }
+               len = s - anchor;
+       }
+       return len;
+}
+
+static char tmp_buf[CONFIG_SYS_CBSIZE];        /* copy of console I/O buffer   */
+
+
+int cmd_auto_complete(const FLASH char *const prompt, char *buf, int *np, int *colp)
+{
+       int n = *np, col = *colp;
+       char *argv[CONFIG_SYS_MAXARGS + 1];             /* NULL terminated      */
+       char *cmdv[20];
+       char *s, *t;
+       const char *sep;
+       int i, j, k, len, seplen, argc;
+       int cnt;
+       char last_char;
+
+       if (strcmp_PP(prompt, CONFIG_SYS_PROMPT) != 0)
+               return 0;       /* not in normal console */
+
+       cnt = strlen(buf);
+       if (cnt >= 1)
+               last_char = buf[cnt - 1];
+       else
+               last_char = '\0';
+
+       /* copy to secondary buffer which will be affected */
+       strcpy(tmp_buf, buf);
+
+       /* separate into argv */
+       argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
+
+       /* do the completion and return the possible completions */
+       i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv);
+
+       /* no match; bell and out */
+       if (i == 0) {
+               if (argc > 1)   /* allow tab for non command */
+                       return 0;
+               putchar('\a');
+               return 1;
+       }
+
+       s = NULL;
+       len = 0;
+       sep = NULL;
+       seplen = 0;
+       if (i == 1) { /* one match; perfect */
+               k = strlen(argv[argc - 1]);
+               s = cmdv[0] + k;
+               len = strlen(s);
+               sep = " ";
+               seplen = 1;
+       } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) {      /* more */
+               k = strlen(argv[argc - 1]);
+               j -= k;
+               if (j > 0) {
+                       s = cmdv[0] + k;
+                       len = j;
+               }
+       }
+
+       if (s != NULL) {
+               k = len + seplen;
+               /* make sure it fits */
+               if (n + k >= CONFIG_SYS_CBSIZE - 2) {
+                       putchar('\a');
+                       return 1;
+               }
+
+               t = buf + cnt;
+               for (i = 0; i < len; i++)
+                       *t++ = *s++;
+               if (sep != NULL)
+                       for (i = 0; i < seplen; i++)
+                               *t++ = sep[i];
+               *t = '\0';
+               n += k;
+               col += k;
+               my_puts(t - k);
+               if (sep == NULL)
+                       putchar('\a');
+               *np = n;
+               *colp = col;
+       } else {
+               print_argv(NULL, "  ", " ", 78, cmdv);
+
+               my_puts_P(prompt);
+               my_puts(buf);
+       }
+       return 1;
+}
+
+#endif /* CONFIG_AUTO_COMPLETE */
+
+
+
+/**
+ * Call a command function. This should be the only route in U-Boot to call
+ * a command, so that we can track whether we are waiting for input or
+ * executing a command.
+ *
+ * @param cmdtp                Pointer to the command to execute
+ * @param flag         Some flags normally 0 (see CMD_FLAG_.. above)
+ * @param argc         Number of arguments (arg 0 must be the command text)
+ * @param argv         Arguments
+ * @return 0 if command succeeded, else non-zero (CMD_RET_...)
+ */
+command_ret_t cmd_call(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       command_ret_t result;
+
+       result = (cmdtp->cmd)(cmdtp, flag, argc, argv);
+//     if (result != CMD_RET_SUCCESS)
+//             debug("Command failed, result=%d\n", result);
+       return result;
+}
+
+command_ret_t cmd_process(int flag, int argc, char * const argv[],
+                              uint_fast8_t *repeatable)
+{
+       command_ret_t rc = CMD_RET_SUCCESS;
+       cmd_tbl_t *cmdtp;
+
+       /* Look up command in command table */
+       cmdtp = find_cmd(argv[0]);
+       if (cmdtp == NULL) {
+               printf_P(PSTR("Unknown command '%s' - try 'help'\n"), argv[0]);
+               return CMD_RET_FAILURE;
+       }
+       if (!cmdtp->cmd) {
+               debug("### Command '%s' found, but ->cmd == NULL \n", argv[0]);
+               return CMD_RET_FAILURE;
+       }
+
+       /* found - check max args */
+       if (argc > cmdtp->maxargs)
+               rc = CMD_RET_USAGE;
+
+#if defined(CONFIG_CMD_BOOTD)
+       /* avoid "bootd" recursion */
+       else if (cmdtp->cmd == do_bootd) {
+               if (flag & CMD_FLAG_BOOTD) {
+                       my_puts_P(PSTR("'bootd' recursion detected\n"));
+                       rc = CMD_RET_FAILURE;
+               } else {
+                       flag |= CMD_FLAG_BOOTD;
+               }
+       }
+#endif
+
+       if (setjmp(cmd_jbuf) != 0)
+               return CMD_RET_FAILURE;
+
+       /* If OK so far, then do the command */
+       if (!rc) {
+               rc = cmd_call(cmdtp, flag, argc, argv);
+               *repeatable &= cmdtp->repeatable;
+       }
+       if (rc == CMD_RET_USAGE)
+               rc = cmd_usage(cmdtp);
+       return rc;
+}
+
+int cmd_process_error(cmd_tbl_t *cmdtp, int err)
+{
+       char buf[strlen_P(cmdtp->name) + 1];
+       strcpy_P(buf, cmdtp->name);
+
+       if (err) {
+               printf_P(PSTR("Command '%s' failed: Error %d\n"), buf, err);
+               return 1;
+       }
+
+       return 0;
+}
diff --git a/avr/command_tbl.c b/avr/command_tbl.c
new file mode 100644 (file)
index 0000000..ed14db9
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include "common.h"
+#include "command.h"
+#include "cmd_mem.h"
+
+extern command_ret_t do_help(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_echo(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_sleep(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_env_print(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_env_default(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_env_set(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_env_save(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_loadf(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_bootcf(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_loadcpm3(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_loadihex(cmd_tbl_t *, int, int, char * const []);
+#if defined(CONFIG_CMD_LOADB)
+extern command_ret_t do_load_serial_bin(cmd_tbl_t *, int, int, char * const []);
+#endif
+extern command_ret_t do_go(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_restart(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_console(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_dump_mem(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_mem_mm_avr(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_mem_nm_avr(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_eep_cp(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_busreq_pulse(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_date(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_gpio(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_sd(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_fat_stat(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_fat_ls(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_fat_rw(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_run(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_source(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_attach(cmd_tbl_t *, int, int, char * const []);
+
+#ifdef CONFIG_SYS_LONGHELP
+const FLASH char sd_help_text[] =
+       "bla \t- do bla\n"
+       ;
+#endif /* CONFIG_SYS_LONGHELP */
+
+
+cmd_tbl_t cmd_tbl[] = {
+
+CMD_TBL_ITEM(
+       date,   2,      1,      do_date,
+       "get/set date & time",
+       "[MMDDhhmm[[CC]YY][.ss]]\n"
+       "  - without arguments: print date & time\n"
+       "  - with numeric argument: set the system date & time\n"
+),
+
+#ifdef DEBUG
+
+CMD_TBL_ITEM(
+       !mdr,   3,      1,      do_dump_mem,
+       "RAM dump",
+       "address [count]"
+),
+CMD_TBL_ITEM(
+       !mde,   3,      1,      do_dump_mem,
+       "EEPROM dump",
+       "address [count]"
+),
+CMD_TBL_ITEM(
+       !mdf,   3,      1,      do_dump_mem,
+       "FLASH dump",
+       "address [count]"
+),
+CMD_TBL_ITEM(
+       !cpe,   4,      0,      do_eep_cp,
+       "EEPROM copy",
+       "source target count"
+),
+CMD_TBL_ITEM(
+       !mm,    2,      1,      do_mem_mm_avr,
+       "avr memory modify (auto-incrementing address)",
+       "address"
+),
+CMD_TBL_ITEM(
+       !nm,    2,      1,      do_mem_nm_avr,
+       "avr memory modify (constant address)",
+       "address"
+),
+#endif
+CMD_TBL_ITEM(
+       mstep,  2,      1,      do_busreq_pulse,
+       "execute one M cycle",
+       "[count]\n"
+       "     - repeat count times"
+),
+CMD_TBL_ITEM(
+       echo,   CONFIG_SYS_MAXARGS,     1,      do_echo,
+       "display a line of text",
+       "[-n] [argument ...]\n"
+       "- echo the argument(s) to console.\n"
+       "  -n  do not output the trailing newline"
+),
+CMD_TBL_ITEM(
+       sleep ,    2,    1,     do_sleep,
+       "delay execution for some time",
+       "N[m][s]\n"
+       "    - delay execution for decimal N (milli) seconds"
+),
+CMD_TBL_ITEM_COMPLETE(
+       run,    CONFIG_SYS_MAXARGS,     1,      do_run,
+       "run commands in an environment variable",
+       "var [...]\n"
+       "    - run the commands in the environment variable(s) 'var'",
+       var_complete
+),
+CMD_TBL_ITEM_COMPLETE(
+       source, CONFIG_SYS_MAXARGS,     1,      do_source,
+       "run commands from a file",
+       "filename\n"
+       "    - run the commands in the script file 'filename'",
+       var_complete
+),
+CMD_TBL_ITEM_COMPLETE(
+       printenv, CONFIG_SYS_MAXARGS,   1,      do_env_print,
+       "print environment variables",
+       "\n"
+       "    - print values of all environment variables\n"
+       "printenv name ...\n"
+       "    - print value of environment variable 'name'",
+       var_complete
+),
+CMD_TBL_ITEM_COMPLETE(
+       setenv, CONFIG_SYS_MAXARGS,     0,      do_env_set,
+       "set environment variables",
+       "name value ...\n"
+       "    - set environment variable 'name' to 'value ...'\n"
+       "setenv name\n"
+       "    - delete environment variable 'name'",
+       var_complete
+),
+CMD_TBL_ITEM(
+       saveenv,        1,      0,      do_env_save,
+       "save environment variables to persistent storage",
+       ""
+),
+CMD_TBL_ITEM(
+       defaultenv,     1,      0,      do_env_default,
+       "set all environment variables to their default values",
+       ""
+),
+
+CMD_TBL_ITEM(
+       loadf,  1,      0,      do_loadf,
+       "load srec_cat prepared image from controller flash",
+       ""
+),
+CMD_TBL_ITEM(
+       bootcf, CONFIG_SYS_MAXARGS,     0,      do_bootcf,
+       "boot from cf card",
+       "[options]\n"
+       "    Load a number of sectors from the first CP/M partition and jump to\n"
+       "    the load address.\n"
+       "    -a ADDRESS\n"
+       "            Load and start address (default 100 hex)\n"
+       "    -s NUM\n"
+       "            First sector of partition to load (0..255, default 0)\n"
+       "    -c NUM\n"
+       "            Number of sectors to load (1..127, default 7)\n"
+       "    -i NUM\n"
+       "            Partition type to look for (default 52 hex)\n"
+       "    -n\n"
+       "            Load only, do not execute\n"
+       "    -t NUM\n"
+       "            Timeout for IDE commands (1..65535, default 10000)\n"
+       "    -v verbose\n"
+       "            TODO: be verbose"
+),
+CMD_TBL_ITEM(
+       loadcpm3, 3,    0,      do_loadcpm3,
+       "load CPM3.SYS file",
+       "[filename [common-base [banked-base]]] \n"
+       "    - Load CP/M 3 system file from FAT filesystem. This command makes\n"
+       "      CPMLDR superfluous. Uses the following environment variables if set:\n"
+       "         '"ENV_CPM3_SYSFILE"' File to load. Default is '"CONFIG_CPM3_SYSFILE"'.\n"
+       "         '"ENV_CPM3_BANKED_BASE"' Default is '"CONFIG_CPM3_BANKED_BASE_STR"'.\n"
+       "      Sets the following environment variables after loading:\n"
+       "         '"ENV_CPM3_COMMON_BASE"'\n"
+       "         '"ENV_STARTADDRESS"'"
+),
+CMD_TBL_ITEM(
+       loadi,  2,      0,      do_loadihex,
+       "load intel hex file over serial line",
+       "[[-]offset]\n"
+       "    - load Intel-Hex-Record file over serial line with offset 'offset'"
+),
+
+#if defined(CONFIG_CMD_LOADB)
+CMD_TBL_ITEM(
+       loadb, 1, 0,    do_load_serial_bin,
+       "load binary file over serial line (kermit mode)",
+       "    - load binary file over serial line"
+),
+
+CMD_TBL_ITEM(
+       loadx, 1, 0,    do_load_serial_bin,
+       "load binary file over serial line (xmodem mode)",
+       "    - load binary file over serial line"
+),
+
+CMD_TBL_ITEM(
+       loady, 1, 0,    do_load_serial_bin,
+       "load binary file over serial line (ymodem mode)",
+       "    - load binary file over serial line"
+),
+#endif /* CONFIG_CMD_LOADB */
+
+CMD_TBL_ITEM(
+       go,     2,      0,      do_go,
+       "start application at address 'addr'",
+       "addr\n"
+       "    - start application at address 'addr'"
+//     "\n"
+//     "      passing 'arg' as arguments"
+),
+CMD_TBL_ITEM(
+       reset,  1,      0,      do_reset,
+       "Keep CPU in RESET state",
+       ""
+),
+CMD_TBL_ITEM(
+       restart, 1, 1,  do_restart,
+       "Perform RESET of the CPU",
+       ""
+),
+CMD_TBL_ITEM(
+       connect, 1, 0,  do_console,
+       "Connect to CPU console i/o",
+       "\n"
+       "    - type the escape character followed by Q to close the connection, \n"
+       "      or followed by ? to see other options. The default escape character \n"
+       "      is Ctrl-^ (0x1E). It can be changed by setting env var '"ENV_ESC_CHAR"'."
+
+),
+
+CMD_TBL_ITEM(
+       pin, CONFIG_SYS_MAXARGS, 1,     do_gpio,
+       "Set or query pin state",
+       "[-s] [<pins>]\n"
+       "    - print cofiguration and state or frequency of pins\n"
+       "      print all pins, if argument is omitted\n"
+       "pin <pins> h[igh]|l[ow]\n"
+       "    - config pins as output and set to level high or low\n"
+       "pin <pins> ts|i[n]|p[ullup]\n"
+       "    - config pins as input/tristate or input with pullup\n"
+       "pin <pins> value[K|M][Hz]\n"
+       "    - output a clock on pins\n"
+       "      value is system clock divider or frequency, if 'Hz' is appended\n"
+       "      divider is rounded down to next possible value (depends on pin)\n"
+       "\n"
+       "<pins> is a comma separated list of numbers or ranges, i.e. \"0,9,3-6\"\n"
+),
+
+CMD_TBL_ITEM(
+       md,     3,      1,      do_mem_md,
+       "memory display",
+       "address [# of objects]"
+),
+CMD_TBL_ITEM(
+       mm,     2,      1,      do_mem_mm,
+       "memory modify (auto-incrementing address)",
+       "address"
+),
+CMD_TBL_ITEM(
+       nm,     2,      1,      do_mem_nm,
+       "memory modify (constant address)",
+       "address"
+),
+CMD_TBL_ITEM(
+       mw,     CONFIG_SYS_MAXARGS,     1,      do_mem_mw,
+       "memory write (fill)",
+       "[-bwl] address value [count]\n"
+       "   -b  write value as byte (8 bit, default)\n"
+       "   -w  write value as word (16 bit)\n"
+       "   -l  write value as long (32 bit)"
+),
+CMD_TBL_ITEM(
+       cp,     4,      1,      do_mem_cp,
+       "memory copy",
+       "source target count"
+),
+CMD_TBL_ITEM(
+       cmp,    4,      1,      do_mem_cmp,
+       "memory compare",
+       "addr1 addr2 count"
+),
+CMD_TBL_ITEM(
+       base,   2,      0,      do_mem_base,
+       "print or set address offset",
+       "\n"
+       "    - print address offset for memory commands\n"
+       "base offset\n"
+       "    - set address offset for memory commands to 'offset'"
+),
+CMD_TBL_ITEM(
+       mloop,  3,      1,      do_mem_loop,
+       "infinite loop on address range",
+       "address number_of_bytes"
+),
+CMD_TBL_ITEM(
+       mloopw, 4,      1,      do_mem_loopw,
+       "infinite write loop on address range",
+       "address number_of_bytes data_to_write"
+),
+
+#ifdef CONFIG_CMD_MEMTEST
+CMD_TBL_ITEM(
+       mtest,  4,      1,      do_mem_mtest,
+       "simple RAM read/write test",
+       "[start [end [iterations]]]"
+),
+#endif /* CONFIG_CMD_MEMTEST */
+
+#ifdef CONFIG_MX_CYCLIC
+CMD_TBL_ITEM(
+       mdc,    4,      1,      do_mem_mdc,
+       "memory display cyclic",
+       "address count delay(ms)"
+),
+CMD_TBL_ITEM(
+       mwc,    CONFIG_SYS_MAXARGS,     1,      do_mem_mdc,
+       "memory write cyclic",
+       "[-bwl] address value delay(ms)\n"
+       "   -b  write value as byte (8 bit, default)\n"
+       "   -w  write value as word (16 bit)\n"
+       "   -l  write value as long (32 bit)"
+),
+#endif /* CONFIG_MX_CYCLIC */
+
+CMD_TBL_ITEM(
+       sd,   CONFIG_SYS_MAXARGS, 1, do_sd,
+       "SD/MMC card handling commands",
+       "<subcommand> args ...\n"
+       "sd help\n"
+       "    - print help on subcommands"
+),
+
+CMD_TBL_ITEM(
+       fatstat,        2,      1,      do_fat_stat,
+       "Show logical drive status",
+       "dev"
+),
+CMD_TBL_ITEM(
+       fatls,  2,      1,      do_fat_ls,
+       "Directory listing",
+       "path"
+),
+CMD_TBL_ITEM(
+       fatload,        5,      0,      do_fat_rw,
+       "load binary file from a dos filesystem",
+       "<d:/path/filename> <addr> [bytes [pos]]\n"
+       "    - Load binary file 'path/filename' on logical drive 'd'\n"
+       "      to address 'addr' from dos filesystem.\n"
+       "      'pos' gives the file position to start loading from.\n"
+       "      If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n"
+       "      'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n"
+       "      the load stops on end of file."
+),
+CMD_TBL_ITEM(
+       fatwrite,       4,      0,      do_fat_rw,
+       "write file into a dos filesystem",
+       "<d:/path/filename> <addr> <bytes>\n"
+       "    - Write file to 'path/filename' on logical drive 'd' from RAM\n"
+       "      starting at address 'addr'.\n"
+),
+CMD_TBL_ITEM(
+       attach, CONFIG_SYS_MAXARGS,     1,      do_attach,
+       "attach filesystem image file to CP/M drive",
+       "[-rw] [-o options] dsk<n> diskfile\n"
+       "    Attach diskfile to dsk<n>, where n in 0..7\n"
+       "    -r      File is read only (write protected)\n"
+       "    -w      File is read/write (default)\n"
+       "    -o options\n"
+       "            Options is a comma-separated list of\n"
+       "            ro, rw, debug, nodebug\n"
+       "\n"
+       "attach [-rw] -o reattach[,other options] dsk<n>\n"
+       "    Change options for dsk<n>.\n"
+       "    Options as above.\n"
+       "\n"
+       "attach -d -a|dsk<n>\n"
+       "detach -a|dsk<n>\n"
+       "    Detach diskfile from dsk<n>.\n"
+       "    -a      Detach all.\n"
+       "\n"
+       "attach\n"
+       "    Without arguments, list current assignments\n"
+),
+CMD_TBL_ITEM(
+       detach, 2,      1,      do_attach,
+       "detach file from CP/M drive",
+       "dsk<n>]\n"
+       "    - alias for 'attach -d dsk<n>'"
+),
+
+CMD_TBL_ITEM(
+       help,   CONFIG_SYS_MAXARGS,     1,      do_help,
+       "print command description/usage",
+       "\n"
+       "       - print brief description of all commands\n"
+       "help command ...\n"
+       "       - print detailed usage of 'command'"
+),
+
+/* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
+       {FSTR("?"),   CONFIG_SYS_MAXARGS, 1, do_help,
+        FSTR("alias for 'help'"),
+#ifdef  CONFIG_SYS_LONGHELP
+       FSTR(""),
+#endif /* CONFIG_SYS_LONGHELP */
+#ifdef CONFIG_AUTO_COMPLETE
+       0,
+#endif
+},
+/* Mark end of table */
+{ 0 },
+};
diff --git a/avr/con-utils.c b/avr/con-utils.c
new file mode 100644 (file)
index 0000000..4a96771
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "common.h"
+#include <string.h>
+#include <avr/wdt.h>
+
+#include "config.h"
+#include "serial.h"
+#include "background.h"
+#include "con-utils.h"
+
+uint_fast8_t tstc(void)
+{
+       bg_shed();
+       return serial_tstc();
+}
+
+int my_getchar(uint_fast8_t waitforchar)
+{
+       int c;
+
+       do {
+               bg_shed();
+               c = serial_getc();
+       } while ((c < 0) && waitforchar);
+
+#ifdef CONFIG_SYS_FBOOTSIG
+       if (c < 0)
+               return c;
+
+       static const FLASH unsigned char bootsig[] = {CONFIG_SYS_FBOOTSIG};
+       static uint8_t pb;
+       unsigned char uc = c;
+
+
+       if (bootsig[pb] == 0) {
+               if (uc == 0xff) {
+                       wdt_enable(WDTO_15MS);
+                       for(;;)
+                               ;
+               } else
+                       pb = 0;
+
+       } else {
+               if (bootsig[pb] == uc)
+                       pb++;
+               else
+                       pb = 0;
+       }
+#endif
+
+       return c;
+}
+
+
+/* test if ctrl-c was pressed */
+
+static uint_fast8_t ctrlc_disabled;    /* see disable_ctrl() */
+static uint_fast8_t ctrlc_was_pressed;
+
+uint_fast8_t ctrlc(void)
+{
+       bg_shed();
+       if (!ctrlc_disabled) {
+               switch (serial_getc()) {
+               case 0x03:              /* ^C - Control C */
+                       ctrlc_was_pressed = 1;
+                       return 1;
+               default:
+                       break;
+               }
+       }
+       return 0;
+}
+
+/* Reads user's confirmation.
+   Returns 1 if user's input is "y", "Y", "yes" or "YES"
+*/
+uint_fast8_t confirm_yesno(void)
+{
+       unsigned int i;
+       char str_input[5];
+
+       /* Flush input */
+       while (serial_getc())
+               ;
+       i = 0;
+       while (i < sizeof(str_input)) {
+               str_input[i] = my_getchar(1);
+               putchar(str_input[i]);
+               if (str_input[i] == '\r')
+                       break;
+               i++;
+       }
+       putchar('\n');
+       if (strncmp(str_input, "y\r", 2) == 0 ||
+           strncmp(str_input, "Y\r", 2) == 0 ||
+           strncmp(str_input, "yes\r", 4) == 0 ||
+           strncmp(str_input, "YES\r", 4) == 0)
+               return 1;
+       return 0;
+}
+
+/* pass 1 to disable ctrlc() checking, 0 to enable.
+ * returns previous state
+ */
+uint_fast8_t disable_ctrlc(uint_fast8_t disable)
+{
+       uint_fast8_t prev = ctrlc_disabled;     /* save previous state */
+
+       ctrlc_disabled = disable;
+       return prev;
+}
+
+uint_fast8_t had_ctrlc (void)
+{
+       return ctrlc_was_pressed;
+}
+
+void clear_ctrlc(void)
+{
+       ctrlc_was_pressed = 0;
+}
diff --git a/avr/debug.c b/avr/debug.c
new file mode 100644 (file)
index 0000000..1b4ecc2
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * (C) Copyright 2014,2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include "debug.h"
+#include "common.h"
+#include <stdlib.h>                    /* __malloc_margin */
+#include <string.h>
+#include <ctype.h>
+#include <avr/eeprom.h>
+
+#include "command.h"
+#include "cli_readline.h"
+#include "eval_arg.h"
+#include "print-utils.h"
+
+/*
+ * Debugging
+ */
+
+#ifdef DEBUG
+
+
+#if 0
+void dump_heap(void)
+{
+       extern unsigned int __brkval;
+
+       dump_ram(__malloc_heap_start,
+               __brkval - (unsigned int) __malloc_heap_start,
+               "=== Heap:");
+}
+#endif
+
+
+/*
+ * Memory Display
+ *     md addr {len}
+ */
+command_ret_t do_dump_mem(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       int (*readwhat)(uint8_t *buf, uint32_t addr, uint8_t count);
+
+       (void) cmdtp; (void) flag;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       uint32_t addr;
+       uint32_t length = 128;
+
+       switch (argv[0][3]) {
+       case 'r':
+               readwhat = ram_read_buf;
+               break;
+       case 'e':
+               readwhat = eeprom_read_buf;
+               break;
+       case 'f':
+               readwhat = flash_read_buf;
+               break;
+       default:
+               return CMD_RET_USAGE;
+       }
+
+       /* Address is specified since argc > 1 */
+       addr =  eval_arg(argv[1], NULL);
+
+       /* If another parameter, it is the length to display. */
+       if (argc > 2)
+               length = (uint16_t) eval_arg(argv[2], NULL);
+
+       /* Print the lines. */
+       dump_mem(addr, addr, length, readwhat, NULL);
+
+       return CMD_RET_SUCCESS;
+}
+
+command_ret_t do_eep_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint16_t src, dest, count;
+       int_fast8_t step;
+
+       (void) cmdtp;
+       (void) flag;
+
+       if (argc != 4)
+               return CMD_RET_USAGE;
+
+       src   = (size_t) eval_arg(argv[1], NULL);
+       dest  = (size_t) eval_arg(argv[2], NULL);
+       count = (size_t) eval_arg(argv[3], NULL);
+
+       if (src > E2END) {
+               debug("src > EEPROM size: 0x%04x\n", src);
+               return CMD_RET_FAILURE;
+       }
+       if (dest > E2END) {
+               debug("dest > EEPROM size: 0x%04x\n", dest);
+               return CMD_RET_FAILURE;
+       }
+       if (count > E2END+1) {
+               debug("count > EEPROM size: 0x%04x\n", count);
+               return CMD_RET_FAILURE;
+       }
+       if (count == 0) {
+               debug("Zero length?\n");
+               return CMD_RET_FAILURE;
+       }
+
+       if (dest > src) {
+               src += count - 1;
+               dest += count - 1;
+               step = -1;
+       } else
+               step = 1;
+
+       while (count-- > 0) {
+               uint8_t data;
+               data = eeprom_read_byte((uint8_t *) src);
+               eeprom_write_byte((uint8_t *) dest, data);
+               src += step;
+               dest += step;
+
+       }
+       return CMD_RET_SUCCESS;
+}
+
+
+/* Modify memory.
+ *
+ * Syntax:
+ *     !mm {addr}
+ *     !nm {addr}
+ */
+
+ static uint8_t        *mm_last_addr;
+
+static command_ret_t
+mod_mem_avr(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[])
+{
+       uint8_t *addr;
+       uint8_t data;
+       int nbytes;
+
+       (void) cmdtp;
+
+       if (argc != 2)
+               return CMD_RET_USAGE;
+
+       /* We use the last specified parameters, unless new ones are
+        * entered.
+        */
+       addr = mm_last_addr;
+
+       if ((flag & CMD_FLAG_REPEAT) == 0) {
+               /* New command specified.
+                */
+
+               /* Address is specified since argc > 1
+               */
+               addr = (uint8_t *) (size_t) eval_arg(argv[1], NULL);
+       }
+
+       /* Print the address, followed by value.  Then accept input for
+        * the next value.  A non-converted value exits.
+        */
+       do {
+               data = *addr;
+               printf_P(PSTR("%04x: %02x"), addr, data);
+
+               nbytes = cli_readline(PSTR(" ? "), 0);
+               if (nbytes == 0 || (nbytes == 1 && console_buffer[0] == '-')) {
+                       /* <CR> pressed as only input, don't modify current
+                        * location and move to next. "-" pressed will go back.
+                        */
+                       if (incrflag)
+                               addr += nbytes ? -1 : 1;
+                       nbytes = 1;
+
+               } else {
+                       char *endp;
+                       data = eval_arg(console_buffer, &endp);
+                       nbytes = endp - console_buffer;
+                       if (nbytes) {
+                               *addr = data;
+                               if (incrflag)
+                                       addr++;
+                       }
+               }
+       } while (nbytes > 0);
+
+       mm_last_addr = addr;
+       return CMD_RET_SUCCESS;
+}
+
+
+command_ret_t do_mem_mm_avr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       return mod_mem_avr (cmdtp, 1, flag, argc, argv);
+}
+command_ret_t do_mem_nm_avr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       return mod_mem_avr (cmdtp, 0, flag, argc, argv);
+}
+
+/*------------------------------------------------------------------------------*/
+
+#if 1
+
+struct __freelist {
+       size_t sz;
+       struct __freelist *nx;
+};
+
+extern char *__brkval;         /* first location not yet allocated */
+extern struct __freelist *__flp; /* freelist pointer (head of freelist) */
+
+#define STACK_POINTER() ((char *)AVR_STACK_POINTER_REG)
+
+void
+printfreelist(const char * title)
+{
+       struct __freelist *fp1;
+       int i;
+       unsigned int freesum = 0;
+
+/* TODO: printf_P */
+
+       if (!__flp) {
+               printf("%s no free list\n", title ? title : "");
+       } else {
+               printf("Free list: %s\n", title ? title : "");
+               for (i = 0, fp1 = __flp; fp1; i++, fp1 = fp1->nx) {
+                       printf("    entry %d @ %04x: size %4u, next ",
+                              i, (size_t)fp1, fp1->sz);
+                       if (fp1->nx)
+                               printf("%04x\n", (size_t)fp1->nx);
+                       else
+                               printf("NULL\n");
+                       freesum += fp1->sz;
+               }
+       }
+
+       freesum +=  (size_t) STACK_POINTER() - __malloc_margin - (size_t) __brkval;
+
+       printf("SP: %04x, __brkval: %04x, Total free: %04u\n",
+               (size_t) STACK_POINTER(), (size_t) __brkval, freesum);
+}
+
+#endif
+
+#endif /* DEBUG */
diff --git a/avr/env.c b/avr/env.c
new file mode 100644 (file)
index 0000000..952c88a
--- /dev/null
+++ b/avr/env.c
@@ -0,0 +1,744 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include "common.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <avr/eeprom.h>
+
+#include "config.h"
+#include "debug.h"
+#include "xmalloc.h"
+#include "crc.h"
+#include "command.h"
+#include "env.h"
+
+
+#define ENV_SIZE       (CONFIG_ENV_SIZE - sizeof(uint16_t) -1)
+#define ACTIVE_FLAG    1
+#define OBSOLETE_FLAG  0
+
+#define ENVLIST_DELETE (1<<0)
+
+
+/*
+ * Default Environment
+ */
+
+#define DELIM          "\0"
+
+const FLASH char default_env[] = {
+       ENV_BAUDRATE      "=" "115200" DELIM
+       ENV_BOOTDELAY     "=" "3" DELIM
+       ENV_BOOTCMD               "=" "pin ${pins}; loadcpm3; go ${startaddress}" DELIM
+       ENV_CPM3_SYSFILE  "=" CONFIG_CPM3_SYSFILE DELIM
+       ENV_PINALIAS      "=" "0:PG5,1:PG4,2:PB4,3:PB5,4:PB6,5:PB7,"
+                                                 "6:PG3,7:PG2,8:PG1,9:PG0,10:PE7" DELIM
+       ENV_STARTADDRESS  "=" "0" DELIM
+       "pins"                    "=" "2,8 low 9 high 3 2" DELIM
+       DELIM
+};
+
+
+/* EEPROM storage */
+typedef struct environment_s {
+       uint16_t        crc;            /* CRC16 over data bytes        */
+       uint8_t         flags;          /* active/obsolete flags        */
+       char            data[ENV_SIZE]; /* Environment data             */
+} env_t;
+
+
+/* */
+typedef struct env_item_s {
+       char * envvar;
+} env_item_t;
+
+
+static uint8_t env_valid;
+static env_item_t env_list[CONFIG_ENVVAR_MAX];
+static int entrycount;
+
+
+static
+char env_get_char(uint16_t index)
+{
+       unsigned int off = CONFIG_ENV_OFFSET;
+       char ret;
+
+       switch (env_valid) {
+       case 2:
+               off += CONFIG_ENV_SIZE;
+       case 1:
+               ret = (char) eeprom_read_byte((const uint8_t *)off + index +
+                               offsetof(env_t, data));
+               break;
+
+       default:
+               ret = default_env[index];
+       }
+
+       return ret;
+}
+
+
+static const FLASH char *comp_key;
+
+static
+int comp_env_items(const void *m1, const void *m2)
+{
+       env_item_t *ep1 = (env_item_t *) m1;
+       env_item_t *ep2 = (env_item_t *) m2;
+
+       if (ep1 == NULL)
+               return - strcmp_P(ep2->envvar, comp_key);
+       else
+               return strcmp(ep1->envvar, ep2->envvar);
+}
+
+
+env_item_t *envlist_search(const MEMX char *name)
+{
+#ifdef __MEMX
+       if (__builtin_avr_flash_segment(name) != -1) {
+               comp_key = name;
+               return bsearch(0, env_list, entrycount,
+                               sizeof(env_item_t), comp_env_items);
+       } else {
+
+               env_item_t e;
+               e.envvar = (char *) name;
+
+               return bsearch(&e, env_list, entrycount,
+                               sizeof(env_item_t), comp_env_items);
+       }
+#else
+       env_item_t e;
+       e.envvar = (char *) name;
+
+       return bsearch(&e, env_list, entrycount,
+                               sizeof(env_item_t), comp_env_items);
+#endif /* __MEMX */
+}
+
+
+static
+env_item_t *envlist_enter(env_item_t *e)
+{
+       const size_t size = sizeof(env_item_t);
+       env_item_t *ep;
+
+       ep = bsearch(e, env_list, entrycount,
+                       size, comp_env_items);
+
+       if (ep == NULL) {
+               if (entrycount < CONFIG_ENVVAR_MAX) {
+
+                       env_list[entrycount++] = *e;
+                       qsort(env_list, entrycount, size, comp_env_items);
+                       ep = bsearch(e, env_list, entrycount,
+                                               size, comp_env_items);
+               }
+       } else {
+               free(ep->envvar);
+               ep->envvar = e->envvar;
+       }
+
+       return ep;
+}
+
+
+static
+int env_item_delete(env_item_t *ep)
+{
+       if (entrycount == 0)
+               return -1;
+
+       free(ep->envvar);
+
+       entrycount--;
+       size_t size = sizeof(env_item_t);
+       memmove(ep, ep + 1, (env_list - ep)*size + entrycount*size);
+
+       return 0;
+}
+
+static
+int envlist_delete(const MEMX char *name)
+{
+       env_item_t *ep = envlist_search(name);
+
+       if (ep != NULL)
+               return env_item_delete(ep);
+
+       return 1;
+}
+
+
+
+static
+int envlist_import(uint8_t flags)
+{
+       uint16_t index;
+
+       int len;
+       env_item_t e;
+       char *np, c;
+       uint_fast8_t ef;
+
+       if ((flags & ENVLIST_DELETE) != 0)
+               while (entrycount != 0)
+                       env_item_delete(&env_list[entrycount-1]);
+
+       for (index = 0; env_get_char(index) != '\0'; ) {
+               for (len = 0; env_get_char(index + len) != '\0'; ++len) {
+                       if ((index + len) >= ENV_SIZE)
+                               return -1;
+               }
+
+               np = (char *) xmalloc(len+1);
+               if (np == NULL) {
+                       printf_P(PSTR("## Can't malloc %d bytes\n"), len+1);
+                       return 1;
+               }
+               e.envvar = np;
+               ef = 0;
+               while ((c = env_get_char(index++)) != '\0') {
+                       if (!ef && (c == '=')) {
+                               *np = '\0';
+                               ef = 1;
+                       } else
+                               *np = c;
+                       np++;
+               }
+               *np = '\0';
+               envlist_enter(&e);
+       }
+
+
+       return 0;
+}
+
+
+static
+uint16_t env_crc(uint16_t data_offset)
+{
+       uint16_t crc;
+       uint16_t i;
+       char c, c0;
+
+       crc = 0xffff;
+       c = 0xff;
+       for (i = 0; !(c == 0 && c0 == 0) && i < ENV_SIZE; i++)
+       {
+               c0 = c;
+               c = eeprom_read_byte((const uint8_t *) data_offset + i);
+               crc = crc16(crc, c);
+       }
+       return crc ;
+}
+
+
+/**
+ * return valid env
+ */
+static
+int env_check_valid(void)
+{
+       const uint16_t offset[2] = {CONFIG_ENV_OFFSET,
+                                   CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE};
+       uint_fast8_t flags[2], crc_ok[2];
+       int rc;
+
+       /* read FLAGS */
+       flags[0] = eeprom_read_byte ((uint8_t *) offset[0] +
+                               offsetof(env_t, flags));
+       flags[1] = eeprom_read_byte ((uint8_t *) offset[1] +
+                               offsetof(env_t, flags));
+
+       /* check CRC */
+       crc_ok[0] = (
+               eeprom_read_word((uint16_t *) offset[0] +
+                               offsetof(env_t, crc))
+               == env_crc(offset[0] + offsetof(env_t, data))
+       );
+       crc_ok[1] = (
+               eeprom_read_word((uint16_t *) offset[1] +
+                               offsetof(env_t, crc))
+               == env_crc(offset[1] + offsetof(env_t, data))
+       );
+
+       if (!crc_ok[0] && !crc_ok[1]) {
+               rc = 0;
+
+       } else if (crc_ok[0] && !crc_ok[1]) {
+               rc = 1;
+       } else if (!crc_ok[0] && crc_ok[1]) {
+               rc = 2;
+       } else {
+               /* both ok - check serial */
+#if 1
+               if      (flags[1] == ACTIVE_FLAG && flags[0] != ACTIVE_FLAG)
+                       rc = 2;
+               else if (flags[1] == OBSOLETE_FLAG && flags[0] == 0xFF)
+                       rc = 2;
+               else
+                       rc = 1;
+#else
+               if (flags[0] == ACTIVE_FLAG && flags[1] == OBSOLETE_FLAG)
+                       rc = 1;
+               else if (flags[0] == OBSOLETE_FLAG && flags[1] == ACTIVE_FLAG)
+                       rc = 2;
+               else if (flags[0] == 0xFF && flags[1] == 0)
+                       rc = 2;
+               else if (flags[1] == 0xFF && flags[0] == 0)
+                       rc = 1;
+               else /* flags are equal - almost impossible */
+                       rc = 1;
+#endif
+       }
+
+       return rc;
+}
+
+
+int env_init(void)
+{
+       env_valid = env_check_valid();
+       if (env_valid == 0) {
+               printf_P(PSTR("*** Warning - bad CRC, "
+                               "using default environment\n\n"));
+       }
+
+       envlist_import(ENVLIST_DELETE);
+       return 0;
+}
+
+
+char *getenv_str(const MEMX char *name)
+{
+       env_item_t *ep;
+       char *ret = NULL;
+
+       ep = envlist_search(name);
+       if (ep != NULL)
+               ret = ep->envvar + strlen(ep->envvar) +1;
+       return ret;
+}
+
+static
+int env_item_save(env_item_t *ep, uint16_t offset, int space_left)
+{
+       int nlen, vlen;
+       char *var = ep->envvar;
+
+       nlen = strlen(var);
+       if (nlen == 0)
+               return 0;
+       vlen = strlen(var + nlen + 1);
+       if (vlen == 0)
+               return 0;
+       if (nlen + vlen + 2 > space_left)
+               return 0;
+
+       eeprom_update_block(var, (uint8_t *) offset, nlen);
+       offset += nlen;
+       eeprom_update_byte((uint8_t *) offset++, '=');
+       eeprom_update_block(var + nlen +1, (uint8_t *) offset, vlen+1);
+
+       return nlen + vlen + 2;
+}
+
+
+static
+int saveenv(void)
+{
+       unsigned int off     = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
+       unsigned int off_red = CONFIG_ENV_OFFSET;
+       unsigned int pos;
+       int len, left;
+       uint16_t crc;
+       int rc = 0;
+
+       if (env_valid == 2) {
+               off     = CONFIG_ENV_OFFSET;
+               off_red = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
+       }
+
+       eeprom_update_byte((uint8_t *) off + offsetof(env_t, flags), 0xff);
+
+       pos = off + offsetof(env_t, data);
+       left = ENV_SIZE - 1;
+       for (int i = 0 ; i < entrycount; i++) {
+               len = env_item_save(&env_list[i], pos, left);
+               if (len == 0) {
+                       return 1;
+               }
+               pos += len;
+               left -= len;
+       }
+       /* terminate list */
+       eeprom_update_byte((uint8_t *) pos, 0);
+       crc = env_crc(off + offsetof(env_t, data));
+       eeprom_update_word((uint16_t *) off + offsetof(env_t, crc), crc);
+       eeprom_update_byte((uint8_t *) off + offsetof(env_t, flags),
+                                       ACTIVE_FLAG);
+
+       if (rc == 0) {
+               eeprom_update_byte((uint8_t *) off_red + offsetof(env_t, flags),
+                                       OBSOLETE_FLAG);
+               env_valid = (env_valid == 2) ? 1 : 2;
+       }
+
+       return rc;
+}
+
+
+static
+int env_item_print(env_item_t *ep)
+{
+       int len;
+       char *ev = ep->envvar;
+
+       len = printf_P(PSTR("%s="), ev);
+       len += printf_P(PSTR("%s\n"), ev + len);
+
+       return len;
+}
+
+
+/*
+ * Command interface: print one or all environment variables
+ *
+ * Returns -1 in case of error, or length of printed string
+ */
+static
+int env_print(const MEMX char *name)
+{
+       int len = -1;
+
+       if (name) {             /* print a single name */
+
+               env_item_t *ep = envlist_search(name);
+               if (ep != NULL)
+                       len = env_item_print(ep);
+
+       } else {                /* print whole list */
+               len = 0;
+               for (int i = 0 ; i < entrycount; i++) {
+                       len += env_item_print(&env_list[i]);
+               }
+       }
+       return len;
+}
+
+
+/**
+ * Set or delete environment variable
+ *
+ * Set a new environment variable,
+ * or replace or delete an existing one.
+ *
+ * @param flag         (not used)
+ * @param argc
+ * @param argv[1]      Environment variable to set or delete
+ *                     if no more args
+ * @param argv[2] ...  Value to set it to
+ *
+ * @return 0 if ok, 1 on error
+ */
+static
+command_ret_t _do_env_set(int flag, int argc, char * const argv[])
+{
+       int i, len;
+       char *name, *value, *valp, *p;
+       env_item_t e, *ep;
+
+       (void) flag;
+
+       name = argv[1];
+       value = argv[2];
+
+       if (strchr(name, '=')) {
+               printf_P(PSTR("## Error: illegal character '='"
+                      "in variable name \"%s\"\n"), name);
+               return CMD_RET_FAILURE;
+       }
+       len = strlen(name);
+       if (len > CONFIG_SYS_ENV_NAMELEN) {
+               printf_P(PSTR("## Error: Variable name \"%s\" too long. "
+                      "(max %d characters)\n"), name, CONFIG_SYS_ENV_NAMELEN);
+               return CMD_RET_FAILURE;
+       }
+/*
+       env_id++;
+*/
+       /* Delete only ? */
+       if (argc < 3 || argv[2] == NULL) {
+               int rc = envlist_delete(name);
+               return rc ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+       }
+
+       /*
+        * Insert / replace new value
+        */
+       for (i = 2, len += 1; i < argc; ++i)
+               len += strlen(argv[i]) + 1;
+
+       value = xmalloc(len);
+       if (value == NULL) {
+               printf_P(PSTR("## Can't malloc %d bytes\n"), len);
+               return CMD_RET_FAILURE;
+       }
+       strcpy(value, name);
+       valp = value + strlen(name) + 1;
+       for (i = 2, p = valp; i < argc; ++i) {
+               char *v = argv[i];
+
+               while ((*p++ = *v++) != '\0')
+                       ;
+               *(p - 1) = ' ';
+       }
+       if (p != valp)
+               *--p = '\0';
+
+       e.envvar = value;
+       ep = envlist_enter(&e);
+       if (!ep) {
+               printf_P(PSTR("## Error inserting \"%s\" variable.\n"),
+                       name);
+               return CMD_RET_FAILURE;
+       }
+
+       return CMD_RET_SUCCESS;
+}
+
+/**
+ * Set an environment variable
+ *
+ * @param varname      Environment variable to set
+ * @param varvalue     Value to set it to
+ * @return 0 if ok, 1 on error
+ */
+static
+int setenv(const MEMX char *varname, const char *varvalue)
+{
+       int rc;
+
+#ifdef __MEMX
+       char *tmpname = NULL;
+       if (__builtin_avr_flash_segment(varname) != -1) {
+               tmpname = malloc(strlen_P(varname)+1);
+               if (tmpname == NULL) {
+                       printf_P(PSTR("setenv: Out of Memory!\n"));
+                       return 1;
+               }
+               strcpy_P(tmpname, varname);
+       } else
+               tmpname = (char *) varname;
+#endif
+
+       const char * const argv[3] = { NULL, tmpname, varvalue };
+       int argc = 3;
+
+       if (varvalue == NULL || varvalue[0] == '\0')
+               --argc;
+
+       rc = (int) _do_env_set(0, argc, (char * const *)argv);
+
+#ifdef __MEMX
+       free(tmpname);
+#endif
+       return rc;
+}
+
+/**
+ * Set an environment variable to an integer value
+ *
+ * @param name Environment variable to set
+ * @param value        Value to set it to
+ * @param radix        Base
+ * @return 0 if ok, 1 on error
+ */
+static
+int setenv_intval(const MEMX char *name, unsigned long value, int radix)
+{
+       char buf[11];
+
+       ultoa(value, buf, radix);
+
+       return setenv(name, buf);
+}
+
+/**
+ * Set an environment variable to a decimal integer value
+ *
+ * @param name Environment variable to set
+ * @param value        Value to set it to
+ * @return 0 if ok, 1 on error
+ */
+int setenv_ulong(const MEMX char *name, unsigned long value)
+{
+       return setenv_intval(name, value, 10);
+}
+
+
+/**
+ * Set an environment variable to a value in hex
+ *
+ * @param name Environment variable to set
+ * @param value        Value to set it to
+ * @return 0 if ok, 1 on error
+ */
+int setenv_hex(const MEMX char *name, unsigned long value)
+{
+       return setenv_intval(name, value, 16);
+}
+
+
+/**
+ * Decode the integer value of an environment variable and return it.
+ *
+ * @param name         Name of environemnt variable
+ * @param base         Number base to use (normally 10, or 16 for hex)
+ * @param default_val  Default value to return if the variable is not
+ *                     found
+ * @return the decoded value, or default_val if not found
+ */
+unsigned long getenv_ulong(const MEMX char *name, int base, unsigned long default_val)
+{
+       unsigned long value;
+       char *vp, *endp;
+
+       env_item_t *ep = envlist_search(name);
+
+       if (ep != NULL ) {
+               vp = ep->envvar + strlen(ep->envvar) +1;
+               value = strtoul(vp, &endp, base);
+               if (endp != vp)
+                       return value;
+       }
+
+       return default_val;
+}
+
+
+/*
+ * Read an environment variable as a boolean
+ */
+bool getenv_yesno(const MEMX char *name)
+{
+       char *s = getenv_str(name);
+
+       if (s == NULL)
+               return false;
+
+       return strchr_P(PSTR("1yYtT"), *s) != NULL;
+
+/*
+       return *s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T' ?
+               1 : 0;
+*/
+}
+
+command_ret_t do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       command_ret_t rc = CMD_RET_SUCCESS;
+
+       (void) cmdtp; (void) flag;
+
+       if (argc == 1) {
+               /* print all env vars */
+               int size = env_print(NULL);
+               if (size < 0)
+                       return CMD_RET_FAILURE;
+               printf_P(PSTR("\nEnvironment size: %d/%d bytes\n"),
+                       size, ENV_SIZE);
+               return CMD_RET_SUCCESS;
+       }
+
+       /* print selected env vars */
+       for (int i = 1; i < argc; ++i) {
+               int rc = env_print(argv[i]);
+               if (rc < 0) {
+                       printf_P(PSTR("## Error: \"%s\" not defined\n"), argv[i]);
+                       rc = CMD_RET_FAILURE;
+               }
+       }
+
+       return rc;
+}
+
+
+command_ret_t do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       (void) cmdtp;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       return _do_env_set(flag, argc, argv);
+}
+
+
+command_ret_t do_env_default(cmd_tbl_t *cmdtp, int flag,
+                         int argc, char * const argv[])
+{
+       (void) cmdtp; (void) flag; (void) argc; (void) argv;
+
+       uint8_t tmp = env_valid;
+       env_valid = 0;
+
+       /* Reset the whole environment */
+       printf_P(PSTR("## Resetting to default environment\n"));
+       envlist_import(ENVLIST_DELETE);
+
+       env_valid = tmp;
+
+       return CMD_RET_SUCCESS;
+}
+
+
+command_ret_t do_env_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       (void) cmdtp; (void) flag; (void) argc; (void) argv;
+
+       printf_P(PSTR("Saving Environment ...\n"));
+       return saveenv() ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+
+#if defined(CONFIG_AUTO_COMPLETE)
+int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf)
+{
+       ENTRY *match;
+       int found, idx;
+
+       idx = 0;
+       found = 0;
+       cmdv[0] = NULL;
+
+       while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
+               int vallen = strlen(match->key) + 1;
+
+               if (found >= maxv - 2 || bufsz < vallen)
+                       break;
+
+               cmdv[found++] = buf;
+               memcpy(buf, match->key, vallen);
+               buf += vallen;
+               bufsz -= vallen;
+       }
+
+       qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
+
+       if (idx)
+               cmdv[found++] = "...";
+
+       cmdv[found] = NULL;
+       return found;
+}
+#endif
diff --git a/avr/eval_arg.c b/avr/eval_arg.c
new file mode 100644 (file)
index 0000000..b931509
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * (C) Copyright 2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include "eval_arg.h"
+#include "common.h"
+#include <stdlib.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include "print-utils.h"
+#include "command.h"   /* jump_buf */
+
+static jmp_buf eval_jbuf;
+static char ch;
+static char *start_p;
+static char *bp;
+
+
+static long expr(void);
+
+static void print_error_pos(void)
+{
+       printf_P(PSTR("Arg: '%s'\n"
+                     "      "), start_p);
+       print_blanks(bp - start_p);
+       my_puts_P(PSTR("^syntax error!\n"));
+}
+
+static void error (void)
+{
+       --bp;
+       longjmp (eval_jbuf, 1);
+}
+
+static void next(void)
+{
+       do
+               ch = *bp++;
+       while (isspace(ch));
+}
+
+static long number (void)
+{
+       int base = 16;
+       char *end_p;
+       long n;
+
+       if (ch == '$') {                                        /* FIXME: should be '#' */
+               next();
+               base = 10;
+       }
+       if (!isdigit(ch) && !(base == 16 && isxdigit(ch)))
+               error ();
+
+       n = strtoul(bp - 1, &end_p, base);
+
+       if (end_p == bp - 1)
+               error();
+       bp = end_p;
+       next();
+
+       return n;
+}
+
+static long factor (void)
+{
+       long f;
+
+       if (ch == '(')
+       {
+               next();
+               f = expr();
+               if (ch == ')')
+                       next();
+               else
+                       error ();
+       } else {
+               char sign = ch;
+               if (sign == '+' || sign == '-') {
+                       next();
+               }
+               f = number();
+               if (sign == '-')
+                       f = -f;
+       }
+       return f;
+}
+
+static long term (void)
+{
+       long t = factor();
+
+       for (;;)
+               switch (ch) {
+               case '*':
+                       next();
+                       t *= factor();
+                       break;
+               case '/':
+                       next();
+                       t /= factor();
+                       break;
+               case '%':
+                       next();
+                       t %= factor();
+                       break;
+               default:
+                       return t;
+               }
+}
+
+
+static long expr(void)
+{
+       long e = term ();
+
+       while (ch == '+' || ch == '-') {
+               char op = ch;
+               next();
+               if (op == '-')
+                       e -= term ();
+               else
+                       e += term ();
+       }
+       return e;
+}
+
+long eval_arg(char *arg, char **end_ptr)
+{
+       long val;
+
+       start_p = arg;
+       bp = arg;
+       next();
+       if (setjmp (eval_jbuf) != 0) {
+               if (!end_ptr) {
+                       print_error_pos();
+                       longjmp(cmd_jbuf, 1);
+               }
+               val = -1;
+       } else {
+               val = expr ();
+               --bp;
+       }
+
+       if (!end_ptr) {
+               if (*bp != '\0') {
+                       print_error_pos();
+                       longjmp(cmd_jbuf, 1);
+               }
+       } else
+               *end_ptr = bp;
+
+       return val;
+}
diff --git a/avr/getopt-min.c b/avr/getopt-min.c
new file mode 100644 (file)
index 0000000..8508f40
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *     Minimum getopt, original version was:
+ */
+
+/*
+       getopt -- public domain version of standard System V routine
+
+       Strictly enforces the System V Command Syntax Standard;
+       provided by D A Gwyn of BRL for generic ANSI C implementations
+*/
+/* $Id: getopt.c,v 1.2 1992/12/07 11:12:52 nickc Exp $ */
+
+#include "common.h"            /* definition of FLASH */
+#include <string.h>
+
+int    optind = 0;                     /* next argv[] index */
+char *optarg;          /* option parameter if any */
+
+
+int
+getopt(                                /* returns letter, '?', EOF */
+       int             argc,           /* argument count from main */
+       char    *const argv[],  /* argument vector from main */
+       const FLASH char *optstring )           /* allowed args, e.g. "ab:c" */
+{
+       static int      sp;             /* position within argument */
+       int             osp;            /* saved `sp' for param test */
+       int             c;              /* option letter */
+       const FLASH char *cp;           /* -> option in `optstring' */
+
+       optarg = NULL;
+       if (optind == 0) {              /* start a new argument scan */
+               optind = 1;
+               sp = 1;
+       }
+
+       if ( sp == 1 )                  /* fresh argument */
+       {
+               if ( optind >= argc             /* no more arguments */
+                 || argv[optind][0] != '-'     /* no more options */
+                 || argv[optind][1] == '\0'    /* not option; stdin */
+                  )
+                       return -1;
+       }
+
+       c = argv[optind][sp];           /* option letter */
+       osp = sp++;                     /* get ready for next letter */
+
+       if ( argv[optind][sp] == '\0' ) /* end of argument */
+       {
+               ++optind;               /* get ready for next try */
+               sp = 1;                 /* beginning of next argument */
+       }
+
+       if ( c == ':'                   /* optstring syntax conflict */
+         || (cp = strchr_P( optstring, c )) == NULL    /* not found */
+          )
+               return '?';
+
+       if ( cp[1] == ':' )             /* option takes parameter */
+       {
+               if ( osp != 1 )
+                       return '?';
+
+               if ( sp != 1 )          /* reset by end of argument */
+                       return '?';
+
+               if ( optind >= argc )
+                       return '?';
+
+               optarg = argv[optind];  /* make parameter available */
+               ++optind;               /* skip over parameter */
+       }
+
+       return c;
+}
diff --git a/avr/gpio.c b/avr/gpio.c
new file mode 100644 (file)
index 0000000..73e9c39
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "common.h"
+#include <util/atomic.h>
+#include <limits.h>
+#include "debug.h"
+#include "gpio.h"
+
+/*
+
+Pin Name    Port    Timer   Mode    max div         max div     min f [Hz]
+--------------------------------------------------------------------------------
+0           PG5     OC0B    PWM     (2**8)*1024     262144      70.31
+1           PG4
+2   CLK2    PB4     OC2A    Toggle  (2**8)*1024*2   524288      35.16
+3   ZCLK    PB5     OC1A    PWM     (2**16)*1024    67108864    0.2746
+4           PB6     OC1B    PWM     (2**16)*1024    67108864    0.2746
+5           PB7     OC0A    Toggle  (2**8)*1024*2   524288      35.16
+6           PG3
+7           PG2
+8           PG1
+9           PG0
+10  CLKO    PE7
+--------------------------------------------------------------------------------
+
+
+pre Timer0      Timer1      Timer2
+--------------------------------------------------
+0   0           0           0
+1   1           1           1
+2   8    x8     8    x8     8    x8
+3   64   x8     64   x8     32   x4
+4   256  x4     256  x4     64   x2
+5   1024 x4     1024 x4     128  x2
+6                           256  x2
+7                           1024 x4
+--------------------------------------------------
+*/
+
+#define PWMTOGGLE      0b01
+#define PWMPOS         0b10
+#define PWMNEG         0b11
+
+
+const FLASH uint8_t prescale_factors_01[] =
+       { 8, 8, 4, 4, 0 };
+
+const FLASH uint8_t prescale_factors_2[] =
+       { 8, 4, 2, 2, 2, 4, 0 };
+
+typedef volatile struct {
+       uint8_t pin;
+       uint8_t ddr;
+       uint8_t pout;
+} port_t ;
+
+struct pindef_s {
+       port_t * const adr;
+       const uint8_t mask;
+#define NO_TIMER       0
+#define TIMER0         (1 << 0)
+#define TIMER1         (2 << 0)
+#define TIMER2         (3 << 0)
+#define TIMER          (3 << 0)
+#define T_16BIT                (1 << 3)
+#define CHANA          (1 << 4)
+#define CHANB          (0 << 4)
+       const uint8_t timer;
+};
+
+
+const FLASH struct pindef_s pinlist[GPIO_MAX] = {
+       { (port_t *) &PING, _BV(5), TIMER0 | CHANB },
+       { (port_t *) &PING, _BV(4), NO_TIMER },
+       { (port_t *) &PINB, _BV(4), TIMER2 | CHANA },
+       { (port_t *) &PINB, _BV(5), TIMER1 | CHANA | T_16BIT },
+       { (port_t *) &PINB, _BV(6), TIMER1 | CHANB | T_16BIT },
+       { (port_t *) &PINB, _BV(7), TIMER0 | CHANA },
+       { (port_t *) &PING, _BV(3), NO_TIMER },
+       { (port_t *) &PING, _BV(2), NO_TIMER },
+       { (port_t *) &PING, _BV(1), NO_TIMER },
+       { (port_t *) &PING, _BV(0), NO_TIMER },
+       { (port_t *) &PINE, _BV(7), NO_TIMER },
+};
+
+void gpio_timer_off(uint8_t timertype)
+{
+       uint8_t chan_mask;
+
+       if (timertype & CHANA)
+               chan_mask = 0xc0;
+       else
+               chan_mask = 0x30;
+
+       switch (timertype & TIMER) {
+       case TIMER0:
+               if (TCCR0A & chan_mask) {
+                       TCCR0B = 0;
+                       TCCR0A = 0;
+                       PRR0 |= _BV(PRTIM0);
+               }
+               break;
+       case TIMER1:
+               if (TCCR1A & chan_mask) {
+                       TCCR1B = 0;
+                       TCCR1A = 0;
+                       PRR0 |= _BV(PRTIM1);
+               }
+               break;
+       case TIMER2:
+               if (TCCR2A & chan_mask) {
+                       TCCR2B = 0;
+                       TCCR2A = 0;
+                       PRR0 |= _BV(PRTIM2);
+               }
+               break;
+       }
+}
+
+int gpio_config(int pin, gpiomode_t mode)
+{
+       if ((unsigned) pin >= ARRAY_SIZE(pinlist)) {
+               /* Invalid pin number */
+               return -1;
+       } else {
+
+               port_t *p = pinlist[pin].adr;
+               uint8_t bit = pinlist[pin].mask;
+
+               switch (mode) {
+               case INPUT:
+                       gpio_timer_off(pinlist[pin].timer);
+                       ATOMIC_BLOCK(ATOMIC_FORCEON) {
+                               p->ddr &= ~bit;
+                               p->pout &= ~bit;
+                       }
+                       break;
+               case INPUT_PULLUP:
+                       gpio_timer_off(pinlist[pin].timer);
+                       ATOMIC_BLOCK(ATOMIC_FORCEON) {
+                               p->ddr &= ~bit;
+                               p->pout |= bit;
+                       }
+                       break;
+               case OUTPUT:
+                       gpio_timer_off(pinlist[pin].timer);
+               case OUTPUT_TIMER:
+                       ATOMIC_BLOCK(ATOMIC_FORCEON) {
+                               p->ddr |= bit;
+                       }
+                       break;
+               default:
+                       /* Invalid pin mode */
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+void gpio_write(int pin, uint8_t val)
+{
+       port_t *p = pinlist[pin].adr;
+       uint8_t bit = pinlist[pin].mask;
+
+       ATOMIC_BLOCK(ATOMIC_FORCEON) {
+               if (val)
+                       p->pout |= bit;
+               else
+                       p->pout &= ~bit;
+       }
+}
+
+int gpio_read(int pin)
+{
+       port_t *p = pinlist[pin].adr;
+       uint8_t bit = pinlist[pin].mask;
+
+       return (p->pin & bit) != 0;
+}
+
+gpiomode_t gpio_config_get(int pin)
+{
+       uint8_t timertype = pinlist[pin].timer;
+
+       if (timertype & TIMER) {
+
+               uint8_t chan_mask;
+               if (timertype & CHANA)
+                       chan_mask = 0xc0;
+               else
+                       chan_mask = 0x30;
+
+               switch (timertype & TIMER) {
+               case TIMER0:
+                       if (TCCR0A & chan_mask)
+                               return OUTPUT_TIMER;
+                       break;
+               case TIMER1:
+                       if (TCCR1A & chan_mask)
+                               return OUTPUT_TIMER;
+                       break;
+               case TIMER2:
+                       if (TCCR2A & chan_mask)
+                               return OUTPUT_TIMER;
+                       break;
+               }
+       }
+
+       port_t *p = pinlist[pin].adr;
+       uint8_t bit = pinlist[pin].mask;
+
+       if (p->ddr & bit)
+               return OUTPUT;
+
+       if (p->pout & bit)
+               return INPUT_PULLUP;
+
+       return INPUT;
+}
+
+/*
+ * return -1: pin has no timer output
+ *        0: pin is not configured for timer output
+ *      > 0: divider
+ */
+
+long gpio_clockdiv_get(int pin)
+{
+       long divider;
+       uint8_t prescale;
+       const FLASH uint8_t *pstab;
+
+       uint8_t timertype = pinlist[pin].timer;
+       if ((timertype & TIMER) == 0)
+               return -1;
+
+       if (gpio_config_get(pin) != OUTPUT_TIMER)
+               return 0;
+
+       switch (timertype & TIMER) {
+       case TIMER0:
+               prescale = TCCR0B;
+               divider = OCR0A;
+               break;
+
+       case TIMER1:
+               prescale = TCCR1B;
+               divider = ICR1;
+               break;
+
+       case TIMER2:
+               prescale = TCCR2B;
+               divider = OCR2A;
+               break;
+       }
+
+       prescale = (prescale & 0x07) - 1;
+       divider += 1;
+
+       pstab = (timertype & TIMER) == TIMER2 ?
+                       prescale_factors_2 : prescale_factors_01;
+
+       while (prescale--)
+               divider *= pstab[prescale];
+
+       if ((timertype & (CHANA|T_16BIT)) == CHANA)
+               divider *= 2;
+
+       return divider;
+}
+
+int gpio_clockdiv_set(int pin, unsigned long divider)
+{
+       unsigned long ltop;
+       uint16_t top;
+       uint8_t prescale;
+       const FLASH uint8_t *pstab;
+
+       uint8_t timertype = pinlist[pin].timer;
+       if ((timertype & TIMER) == 0)
+               return 0;
+
+       if (divider < 2)
+               return -1;
+
+       ltop = divider;
+       if ((timertype & (CHANA|T_16BIT)) == CHANA)
+               ltop /= 2;
+
+       if (ltop > 1024 * ((timertype & T_16BIT) ? (1L<<16) : (1L<<8)))
+               return -1;
+
+       prescale = 1;
+       pstab = (timertype & TIMER) == TIMER2 ?
+                       prescale_factors_2 : prescale_factors_01;
+
+//     debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d\n",
+//             pin, ltop, prescale);
+
+       while (ltop > ((timertype & T_16BIT) ? (1L<<16) : (1L<<8)))  {
+//             debug("** clockdiv_set: pin: %d, ltop: %lu, prescale: %d, *pstab %d\n",
+//                     pin, ltop, prescale, *pstab);
+
+               if (*pstab == 0)
+                       return -1;
+               ltop /= *pstab++;
+               prescale++;
+       }
+
+       if (ltop == 0)
+               return -1;
+
+       top = ltop - 1;
+
+//     PING |= _BV(0);         /* Debug */
+
+       switch (timertype & TIMER) {
+       case TIMER0:
+               PRR0 &= ~_BV(PRTIM0);
+               TCCR0B = (1 << WGM02);
+               TCNT0 = 0;
+               OCR0A = top;
+               if (timertype & CHANA) {
+                       TCCR0A = (PWMTOGGLE << COM0A0) | (0b11 << WGM00);
+               } else {
+                       OCR0B = top/2;
+                       TCCR0A = (PWMPOS << COM0B0) | (0b11 << WGM10);
+               }
+               TCCR0B = (1 << WGM02) | (prescale << CS10);
+               break;
+
+       case TIMER1:
+               PRR0 &= ~_BV(PRTIM1);
+                       TCCR1B = (0b11 << WGM12);
+                       TCNT1 = 0;
+                       ICR1 = top;
+                       if (timertype & CHANA) {
+                               OCR1A = top/2;
+                               TCCR1A = (PWMPOS << COM1A0) | (0b10 << WGM10);
+                       } else {
+                               OCR1B = top/2;
+                               TCCR1A = (PWMPOS << COM1B0) | (0b10 << WGM10);
+                       }
+//                     debug("pin: %d, top: %u,"
+//                             " ICR1: %u, OCR1A: %u, OCR1B: %u\n",
+//                             pin, top, ICR1, OCR1A, OCR1B);
+
+                       TCCR1B = (0b11 << WGM12)  | (prescale << CS10);
+               break;
+
+       case TIMER2:
+               PRR0 &= ~_BV(PRTIM2);
+               TCCR2B = (1 << WGM22);
+               TCNT2 = 0;
+               OCR2A = top;
+               if (timertype & CHANA) {
+                       TCCR2A = (PWMTOGGLE << COM2A0) | (0b11 << WGM20);
+               } else {
+                       OCR2B = top/2;
+                       TCCR2A = (PWMPOS << COM2B0) | (0b11 << WGM10);
+               }
+               TCCR2B = (1 << WGM22) | (prescale << CS10);
+               break;
+       }
+
+//     PING |= _BV(0);         /* Debug */
+
+       gpio_config(pin, OUTPUT_TIMER);
+
+       return 0;
+}
diff --git a/avr/i2c.c b/avr/i2c.c
new file mode 100644 (file)
index 0000000..ae2f8da
--- /dev/null
+++ b/avr/i2c.c
@@ -0,0 +1,378 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * I2C (TWI) master interface.
+ */
+
+#include "common.h"
+#include <avr/interrupt.h>
+#include <string.h>
+
+#include "config.h"
+#include "timer.h"
+#include "debug.h"
+#include "i2c.h"
+
+#define  DEBUG_I2C 0
+
+#define debug_i2c(fmt, args...)                        \
+       debug_cond(DEBUG_I2C, fmt, ##args)
+
+
+/* General TWI Master status codes */
+#define TWI_START                  0x08  /* START has been transmitted */
+#define TWI_REP_START              0x10  /* Repeated START has been transmitted */
+#define TWI_ARB_LOST               0x38  /* Arbitration lost */
+
+/* TWI Master Transmitter status codes */
+#define TWI_MTX_ADR_ACK            0x18  /* SLA+W has been transmitted and ACK received */
+#define TWI_MTX_ADR_NACK           0x20  /* SLA+W has been transmitted and NACK received */
+#define TWI_MTX_DATA_ACK           0x28  /* Data byte has been transmitted and ACK received */
+#define TWI_MTX_DATA_NACK          0x30  /* Data byte has been transmitted and NACK received */
+
+/* TWI Master Receiver status codes */
+#define TWI_MRX_ADR_ACK            0x40  /* SLA+R has been transmitted and ACK received */
+#define TWI_MRX_ADR_NACK           0x48  /* SLA+R has been transmitted and NACK received */
+#define TWI_MRX_DATA_ACK           0x50  /* Data byte has been received and ACK transmitted */
+#define TWI_MRX_DATA_NACK          0x58  /* Data byte has been received and NACK transmitted */
+
+/* TWI Miscellaneous status codes */
+#define TWI_NO_STATE               0xF8  /* No relevant state information available */
+#define TWI_BUS_ERROR              0x00  /* Bus error due to an illegal START or STOP condition */
+
+
+/*
+ * TWINT: TWI Interrupt Flag
+ * TWEA:  TWI Enable Acknowledge Bit
+ * TWSTA: TWI START Condition Bit
+ * TWSTO: TWI STOP Condition Bit
+ * TWEN:  TWI Enable Bit
+ * TWIE:  TWI Interrupt Enable
+ *
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|           (1<<TWEA)
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
+ *
+ * default:
+ *     (1<<TWEN)|          (1<<TWINT)|           (1<<TWSTO)
+ *
+ * Init:
+ *     (1<<TWEN)
+ *
+ * start read/write:
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ *     (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
+ *
+ * wait ready:
+ *      (1<<TWIE)|(1<<TWSTO)
+ *
+ *
+ *
+ *i2c_result
+ *
+ *     0b10000000      Busy (Transmission in progress)
+ *     0b01000000      Timeout
+ *     0b00001000      Start transmitted
+ *     0b00000100      Slave acknowledged address
+ *     0b00000010      Data byte(s) transmitted/received
+ *     0b00000001      Transmission completed
+ *
+ *
+ *----------------------------------------------------------------------
+ */
+
+#define TWI_C_DISABLE          0x00
+#define TWI_C_ENABLE           (1<<TWEN)
+
+
+
+ typedef struct i2c_msg_s {
+       uint8_t stat;
+ #define XMIT_DONE     (1<<0)
+ #define DATA_ACK      (1<<1)
+ #define ADDR_ACK      (1<<2)
+ #define START         (1<<3)
+ #define TIMEOUT       (1<<6)
+ #define BUSY          (1<<7)
+       uint8_t idx;
+       uint8_t len;
+       uint8_t buf[CONFIG_SYS_I2C_BUFSIZE];
+} i2c_msg_t;
+
+static volatile i2c_msg_t xmit;
+
+ISR(TWI_vect)
+{
+       uint8_t tmp_stat;
+       uint8_t tmp_idx;
+       uint8_t next_twcr;
+       uint8_t n;
+
+       tmp_idx = xmit.idx;
+       tmp_stat = xmit.stat;
+
+       uint8_t twsr = TWSR;
+
+       switch (twsr & 0xf8) {
+
+       case TWI_START:
+       case TWI_REP_START:
+               tmp_stat = BUSY | START;
+               tmp_idx = 0;                    /* reset xmit_buf index */
+
+               if (tmp_idx < xmit.len) {               /* all bytes transmited? */
+                       TWDR = xmit.buf[tmp_idx];
+                       ++tmp_idx;
+                       next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
+               } else {
+                       tmp_stat |= XMIT_DONE;
+                       tmp_stat &= ~BUSY;
+                       next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+               }
+               break;
+
+       case TWI_MTX_ADR_ACK:
+       case TWI_MTX_DATA_ACK:
+               if ((twsr&0xf8) == TWI_MTX_ADR_ACK)
+                       tmp_stat |= ADDR_ACK;
+               else
+                       tmp_stat |= DATA_ACK;
+
+               if (tmp_idx < xmit.len) {               /* all bytes transmited? */
+                       TWDR = xmit.buf[tmp_idx];
+                       ++tmp_idx;
+                       next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
+               } else {
+                       tmp_stat |= XMIT_DONE;
+                       tmp_stat &= ~BUSY;
+                       next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+               }
+               break;
+
+       case TWI_MTX_DATA_NACK:
+               tmp_stat |= XMIT_DONE;
+               tmp_stat &= ~BUSY;
+               next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+               break;
+
+       case TWI_MRX_DATA_ACK:
+               xmit.buf[tmp_idx] = TWDR;
+               ++tmp_idx;
+               /* fall thru */
+       case TWI_MRX_ADR_ACK:
+               if ((twsr&0xf8) == TWI_MRX_ADR_ACK)
+                       tmp_stat |= ADDR_ACK;
+               else
+                       tmp_stat |= DATA_ACK;
+
+               n = xmit.len-1;
+               if (tmp_idx < n) {
+                       next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);
+               } else {
+                       next_twcr = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);
+               }
+               break;
+
+       case TWI_MRX_DATA_NACK:
+               tmp_stat |= ADDR_ACK | DATA_ACK;
+
+               xmit.buf[tmp_idx] = TWDR;
+               ++tmp_idx;
+               /* fall thru */
+       default:
+               tmp_stat &= ~BUSY;
+               next_twcr = (1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO);
+               break;
+       }
+
+       xmit.stat = tmp_stat;
+       xmit.idx = tmp_idx;
+
+       debug_i2c("|%02x", twsr);
+       TWCR = next_twcr;
+}
+
+
+/*------------------------------------------------------------------*/
+
+static uint8_t twps;
+static uint8_t twbr;
+
+
+static void _init(void)
+{
+       xmit.stat = 0;
+
+       /* Disable TWI, disable TWI interrupt. */
+       /* (Reset TWI hardware state machine.) */
+       TWCR = TWI_C_DISABLE;
+       _delay_us(5);
+#if DEBUG_I2C
+       memset((void *) xmit.buf, 0xdf, sizeof(xmit.buf));
+#endif
+
+       TWDR = 0xff;
+       TWBR = twbr;
+       TWSR = twps & 0x03;
+       TWCR = TWI_C_ENABLE;
+}
+
+void i2c_init(uint32_t speed)
+{
+       twps = 0;
+       uint32_t tmp_twbr = F_CPU /2 / speed - 8;
+
+       while (tmp_twbr > 255) {
+               tmp_twbr >>= 4;
+               twps += 1;
+       }
+       debug_cond((twps > 3), "*** TWCLK too low: %lu Hz\n", speed);
+
+       twbr = (uint8_t) tmp_twbr;
+
+       PRR0 &= ~_BV(PRTWI);
+       _init();
+}
+
+
+int_fast8_t i2c_waitready(void)
+{
+       uint32_t timer = get_timer(0);
+       uint8_t timeout = 0;
+
+       do {
+               if (get_timer(timer) >= 30) {
+                       timeout = TIMEOUT;
+                       _init();
+               }
+       } while ((TWCR & ((1<<TWIE)|(1<<TWSTO))) != 0 && !timeout);
+
+       xmit.stat |= timeout;
+
+#if DEBUG_I2C
+       dump_ram((uint8_t *) &xmit, 4, "=== i2c_wait ready: (done)");
+       _delay_ms(30);
+#endif
+       return xmit.stat;
+}
+
+static
+int i2c_send(uint8_t chip, uint16_t addr, uint8_t alen, uint8_t *buffer, int8_t len)
+{
+       uint8_t i, n;
+       uint8_t rc;
+
+       rc = i2c_waitready();
+       if ((rc & (BUSY | TIMEOUT)) != 0)
+               return rc;
+
+       xmit.stat = BUSY;
+       xmit.buf[0] = chip<<1;
+       for (i = 1; i < alen+1; i++) {
+               xmit.buf[i] = (uint8_t) addr;
+               addr >>= 8;
+       }
+       for (n = len + i; i < n; i++)
+               xmit.buf[i] = *buffer++;
+       xmit.len = i;
+
+#if DEBUG_I2C
+       dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_send");
+       _delay_ms(30);
+#endif
+       /* Enable TWI, TWI int and initiate start condition */
+       TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA);
+
+       rc = xmit.stat;
+
+       return rc;
+}
+
+static
+int i2c_recv(uint8_t chip, uint8_t *buffer, int8_t len)
+{
+       uint8_t rc;
+
+       rc = i2c_waitready();
+       if ((rc & (BUSY | TIMEOUT)) != 0)
+               return rc;
+
+       xmit.stat = BUSY;
+       xmit.len = len + 1;
+       xmit.buf[0] = (chip<<1) | 1;
+
+#if DEBUG_I2C
+       dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_recv: before start");
+       _delay_ms(30);
+#endif
+       /* Enable TWI, TWI int and initiate start condition */
+       TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA);
+       rc = i2c_waitready();
+
+#if DEBUG_I2C
+       dump_ram((uint8_t *) &xmit, 0x20, "=== i2c_recv: after completion");
+       _delay_ms(30);
+#endif
+       if (rc & DATA_ACK) {
+               /* at least 1 byte received */
+               for (uint8_t i=1, n=xmit.idx; i < n; i++)
+                       *buffer++ = xmit.buf[i];
+       }
+
+       return rc;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+
+int i2c_write(uint8_t chip, unsigned int addr, uint_fast8_t alen,
+                               uint8_t *buffer, uint_fast8_t len)
+{
+       int rc;
+
+       if ((alen > 2) || (1 + alen + len > CONFIG_SYS_I2C_BUFSIZE)) {
+               debug("** i2c_write: buffer overflow, alen: %u, len: %u\n",
+                       alen, len);
+               return -1;
+       }
+
+       i2c_send(chip, addr, alen, buffer, len);
+       rc = i2c_waitready();
+
+       return (rc & XMIT_DONE) != 0;
+}
+
+int i2c_read(uint8_t chip, unsigned int addr, uint_fast8_t alen,
+                               uint8_t *buffer, uint_fast8_t len)
+{
+       int rc;
+
+       if ((alen > 2) || (1 + len > CONFIG_SYS_I2C_BUFSIZE)) {
+               debug("** i2c_read: parameter error: alen: %u, len: %u\n",
+                       alen, len);
+               return -1;
+       }
+
+       if (alen != 0) {
+               i2c_send(chip, addr, alen, NULL, 0);
+       }
+       rc = i2c_recv(chip, buffer, len);
+
+       return !((rc & (XMIT_DONE|DATA_ACK)) == (XMIT_DONE|DATA_ACK));
+}
diff --git a/avr/main.c b/avr/main.c
new file mode 100644 (file)
index 0000000..86dcc50
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+
+#include "common.h"
+#include <avr/interrupt.h>
+#include <avr/wdt.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "ff.h"
+#include "z80-if.h"
+#include "i2c.h"
+#include "con-utils.h"
+#include "serial.h"
+#include "timer.h"
+#include "cli.h"
+#include "env.h"
+#include "z180-serv.h"
+#include "gpio.h"
+#include "time.h"
+#include "rtc.h"
+#include "debug.h"
+
+uint8_t mcusr __attribute__ ((section (".noinit")));
+
+#if DEBUG
+__attribute__ ((naked)) __attribute__ ((section (".init3")))
+void preset_ram (void)
+{
+       for (uint8_t *p = (uint8_t *) RAMSTART; p <= (uint8_t *) RAMEND; p++)
+               *p = 0xdd;
+
+}
+#endif
+
+__attribute__ ((naked)) __attribute__ ((section (".init3")))
+void get_mcusr (void)
+{
+       /* save and clear reset reason(s) */
+       /* TODO: move to init section? */
+       mcusr = MCUSR;
+       MCUSR = 0;
+
+       wdt_disable();
+}
+
+/*--------------------------------------------------------------------------*/
+#if DEBUG
+
+static const FLASH char * const FLASH rreasons[] = {
+                       FSTR("Power on"),
+                       FSTR("External"),
+                       FSTR("Brown out"),
+                       FSTR("Watchdog"),
+                       FSTR("JTAG"),
+               };
+
+static
+void print_reset_reason(void)
+{
+       uint8_t r = mcusr & 0x1f;
+       const FLASH char * const FLASH *p = rreasons;
+
+       printf_P(PSTR("### Reset reason(s): %s"), r ? "" : "none");
+       for ( ; r; p++, r >>= 1) {
+               if (r & 1) {
+                       my_puts_P(*p);
+                       if (r & ~1)
+                               printf_P(PSTR(", "));
+               }
+       }
+       printf_P(PSTR(".\n"));
+}
+
+#endif
+
+ISR(INT5_vect)
+{
+       Stat |= S_MSG_PENDING;
+}
+
+ISR(INT6_vect)
+{
+       Stat |= S_CON_PENDING;
+}
+
+static
+void setup_avr(void)
+{
+       /* CPU */
+
+       /* Disable JTAG Interface regardless of the JTAGEN fuse setting. */
+       MCUCR = _BV(JTD);
+       MCUCR = _BV(JTD);
+
+       /* Disable peripherals. Enable individually in respective init function. */
+       PRR0 = _BV(PRTWI) |
+               _BV(PRTIM2) | _BV(PRTIM0) | _BV(PRTIM1) |
+               _BV(PRSPI) | _BV(PRUSART0) | _BV(PRADC);
+
+       PRR1 = _BV(PRTIM5) | _BV(PRTIM4) | _BV(PRTIM3) |
+               _BV(PRUSART3) | _BV(PRUSART2) | _BV(PRUSART1);
+
+
+       /* disable analog comparator */
+       ACSR = _BV(ACD);
+       /* Ports */
+
+       /* Clock */
+       CLKPR = _BV(CLKPCE);
+       CLKPR = 0;
+
+       /* Timer */
+       PRR1 &= ~_BV(PRTIM4);
+       OCR4A = F_CPU / 1000 - 1;       /* Timer4: 1000Hz interval */
+       TCCR4B = (0b00<<WGM42)|(0b001<<CS40); /* Normal Mode, Prescaler 1 */
+       TIMSK4 = _BV(OCIE4A);           /* Enable Output Compare A interrupt */
+
+       /* INT5, INT6: falling edge */
+       EICRB = (EICRB & ~((0b11 << ISC50) | (0b11 << ISC60))) |
+               (0b10 << ISC50) | (0b10 << ISC60);
+       /* Reset pending ints */
+       EIFR |= _BV(INTF5) | _BV(INTF6);
+       /* Enable INT5, and INT6 */
+       EIMSK |= _BV(INT5) | _BV(INT6);
+}
+
+static
+int reset_reason_is_power_on(void)
+{
+       return (mcusr & _BV(PORF)) != 0;
+}
+
+static
+void setup_system_time(void)
+{
+       struct tm rtc_time;
+
+       rtc_get(&rtc_time);
+       rtc_time.tm_isdst = 0;
+       set_system_time(mk_gmtime(&rtc_time) );
+}
+
+
+
+static void setup_fatfs(void)
+{
+       static FATFS FatFs0;
+       static FATFS FatFs1;
+
+       f_mount(&FatFs0, "0:", 0);
+       f_mount(&FatFs1, "1:", 0);
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Stored value of bootdelay, used by autoboot_command() */
+static int  stored_bootdelay;
+
+
+/***************************************************************************
+ * Watch for 'delay' seconds for autoboot stop.
+ * returns: 0 - no key, allow autoboot
+ *          1 - got key, abort
+ */
+
+static int abortboot(int  bootdelay)
+{
+       int abort = 0;
+       uint32_t ts;
+
+       if (bootdelay >= 0)
+               printf_P(PSTR("Hit any key to stop autoboot: %2d "), bootdelay);
+
+#if defined CONFIG_ZERO_BOOTDELAY_CHECK
+       /*
+        * Check if key already pressed
+        * Don't check if bootdelay < 0
+        */
+       if (bootdelay >= 0) {
+               if (tstc()) {   /* we got a key press   */
+                       (void) my_getchar(1);  /* consume input */
+                       my_puts_P(PSTR("\b\b\b 0"));
+                       abort = 1;      /* don't auto boot      */
+               }
+       }
+#endif
+
+       while ((bootdelay > 0) && (!abort)) {
+               --bootdelay;
+               /* delay 1000 ms */
+               ts = get_timer(0);
+               do {
+                       if (tstc()) {   /* we got a key press   */
+                               abort  = 1;     /* don't auto boot      */
+                               bootdelay = 0;  /* no more delay        */
+                               break;
+                       }
+                       udelay(10000);
+               } while (!abort && get_timer(ts) < 1000);
+
+               printf_P(PSTR("\b\b\b%2d "), bootdelay);
+       }
+
+       putchar('\n');
+
+       return abort;
+}
+
+static
+const char *bootdelay_process(void)
+{
+       char *s;
+       int bootdelay;
+
+       bootdelay = (int) getenv_ulong(PSTR(ENV_BOOTDELAY), 10, CONFIG_BOOTDELAY);
+
+
+       debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
+       _delay_ms(20);
+
+       s = getenv_str(PSTR(ENV_BOOTCMD));
+       stored_bootdelay = bootdelay;
+       return s;
+}
+
+static
+void autoboot_command(const char *s)
+{
+       debug("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
+       _delay_ms(20);
+
+       if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
+               run_command_list(s, -1);
+       }
+}
+
+
+static
+void main_loop(void)
+{
+       const char *s;
+
+       s = bootdelay_process();
+       autoboot_command(s);
+       cli_loop();
+}
+
+int main(void)
+{
+       extern void setup_mmc(void);
+
+       setup_avr();
+       for (int i = 0; i < GPIO_MAX; i++)
+               gpio_config(i, INPUT_PULLUP);
+       setup_mmc();
+       env_init();
+       z80_setup_bus();
+
+       if (reset_reason_is_power_on())
+               _delay_ms(CONFIG_PWRON_DELAY);
+
+       serial_setup(getenv_ulong(PSTR(ENV_BAUDRATE), 10, CONFIG_BAUDRATE));
+       sei();
+
+#if DEBUG
+       debug("\n=========================<  (RE)START DEBUG  >=========================\n");
+       print_reset_reason();
+#endif
+
+       i2c_init(CONFIG_SYS_I2C_CLOCK);
+       setup_system_time();
+       setup_fatfs();
+
+       printf_P(PSTR("\n" MCU_STRING "+Z8S180 Stamp Monitor - Version: " VERSION  " \n\n"));
+
+       setup_z180_serv();
+
+       main_loop();
+}
diff --git a/avr/mmc.c b/avr/mmc.c
new file mode 100644 (file)
index 0000000..d45cdf5
--- /dev/null
+++ b/avr/mmc.c
@@ -0,0 +1,808 @@
+/*-----------------------------------------------------------------------*/
+/* MMCv3/SDv1/SDv2 (in SPI mode) control module  (C)ChaN, 2007             */
+/*-----------------------------------------------------------------------*/
+/* Only spi_rcvr(), spi_xmit(), disk_timerproc() and some macros         */
+/* are platform dependent.                                               */
+/*-----------------------------------------------------------------------*/
+
+#include "common.h"
+#include <stdbool.h>
+#include <util/atomic.h>
+#include "timer.h"
+#include "spi.h"
+#include "diskio.h"
+#include "debug.h"
+
+#define MAX_DRV                2
+
+/* Port Controls  (Platform dependent) */
+/* SD card socket connections */
+
+/* TODO: config.h cofig macros */
+
+//#define SD_CD_0              SBIT(PORT,)                             /* Card detect switch */
+//#define SD_CD_0_IN   SBIT(PIN,)
+//#define SD_CD_0_DDR  SBIT(DDR,)
+
+//#define SD_WP_0              SBIT(PORT,)                             /* Write protect switch */
+//#define SD_WP_0_IN   SBIT(PIN,)
+//#define SD_WP_0_DDR  SBIT(DDR,)
+
+#define SD_CS_0                SBIT(PORTB,0)                           /* Chip select/Card sense pin */
+//#define SD_CS_0_IN   SBIT(PINB,0)
+#define SD_CS_0_DDR    SBIT(DDRB,0)
+
+
+#define SD_CD_1                SBIT(PORTG,3)                           /* Card detect switch */
+#define SD_CD_1_IN     SBIT(PING,3)
+#define SD_CD_1_DDR    SBIT(DDRG,3)
+
+//#define SD_WP_1              SBIT(PORTG,5)                   /* Write protect switch */
+//#define SD_WP_1_IN   SBIT(PING,5)
+//#define SD_WP_1_DDR  SBIT(DDRG,5)
+
+#define SD_CS_1                SBIT(PORTG,4)                           /* Chip select/Card sense pin */
+//#define SD_CS_1_IN   SBIT(PING,4)
+#define SD_CS_1_DDR    SBIT(DDRG,4)
+
+
+#define        SPI_CLK_SLOW()  SPISetMMCInitClock()    /* Set slow clock (100k-400k) */
+#define        SPI_CLK_FAST()  SPISetFastClock()               /* Set fast clock (depends on the CSD) */
+
+/*--------------------------------------------------------------------------
+ Definitions for MMC/SDC command
+ ---------------------------------------------------------------------------*/
+
+#define CMD0   (0)                     /* GO_IDLE_STATE */
+#define CMD1   (1)                     /* SEND_OP_COND (MMC) */
+#define        ACMD41  (0x80+41)       /* SEND_OP_COND (SDC) */
+#define CMD8   (8)                     /* SEND_IF_COND */
+#define CMD9   (9)                     /* SEND_CSD */
+#define CMD10  (10)            /* SEND_CID */
+#define CMD12  (12)            /* STOP_TRANSMISSION */
+#define ACMD13 (0x80+13)       /* SD_STATUS (SDC) */
+#define CMD16  (16)            /* SET_BLOCKLEN */
+#define CMD17  (17)            /* READ_SINGLE_BLOCK */
+#define CMD18  (18)            /* READ_MULTIPLE_BLOCK */
+#define CMD23  (23)            /* SET_BLOCK_COUNT (MMC) */
+#define        ACMD23  (0x80+23)       /* SET_WR_BLK_ERASE_COUNT (SDC) */
+#define CMD24  (24)            /* WRITE_BLOCK */
+#define CMD25  (25)            /* WRITE_MULTIPLE_BLOCK */
+#define CMD55  (55)            /* APP_CMD */
+#define CMD58  (58)            /* READ_OCR */
+
+
+/*--------------------------------------------------------------------------
+
+ Module Private Functions
+
+ ---------------------------------------------------------------------------*/
+
+struct sdsock_stat_s {
+       volatile DSTATUS stat;  /* Disk/socket status */
+       BYTE CardType;          /* Card type flags */
+};
+
+static
+struct sdsock_stat_s
+       socket[MAX_DRV] = {
+               {.stat=STA_NOINIT},
+               {.stat=STA_NOINIT}
+       };
+
+/*-----------------------------------------------------------------------*/
+/* Wait for card ready                                                   */
+/*-----------------------------------------------------------------------*/
+
+static
+int wait_ready (void)  /* 1:OK, 0:Timeout */
+{
+       uint32_t to = get_timer(0);
+
+       /* Wait for ready in timeout of 500ms */
+       do {
+               if (spi_rcvr() == 0xFF) {
+                       return 1;
+               }
+       } while (get_timer(to) < 500);
+
+       return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Deselect the card and release SPI bus                                 */
+/*-----------------------------------------------------------------------*/
+
+static
+void deselect(BYTE drv)
+{
+       //debug("*** enter deselect(%.2x)\n", drv);
+       if (drv == 0)
+               SD_CS_0 = 1;
+       else {
+               SD_CS_1 = 1;
+       }
+
+       /* Dummy clock (TODO: force DO hi-z for multiple slave SPI) */
+       if (socket[drv].stat & STA_FAST)
+               SPI_CLK_FAST();
+       else
+               SPI_CLK_SLOW();
+       spi_rcvr();
+       SPI_OFF();
+
+       if (drv == 0) {
+#ifdef SD_CS_0_IN
+               SD_CS_0_DDR = 0;                /* Input */
+               SD_CS_0 = 0;                    /* No Pullup */
+#endif
+       } else {
+#ifdef SD_CS_1_IN
+               SD_CS_1_DDR = 0;
+               SD_CS_1 = 0;
+#endif
+       }
+       //debug("***  exit deselect(%.2x)\n", drv);
+}
+
+/*-----------------------------------------------------------------------*/
+/* Select the card and wait for ready                                    */
+/*-----------------------------------------------------------------------*/
+
+static
+int select(BYTE drv)   /* 1:Successful, 0:Timeout */
+{
+       //debug("*** enter select(%.2x)\n", drv);
+       if (drv == 0) {
+#ifdef SD_CS_0_IN
+               SD_CS_0 = 1;
+               SD_CS_0_DDR = 1;
+#endif
+               SD_CS_0 = 0;
+       } else {
+#ifdef SD_CS_1_IN
+               SD_CS_1 = 1;
+               SD_CS_1_DDR = 1;
+#endif
+               SD_CS_1 = 0;
+       }
+
+       if (socket[drv].stat & STA_FAST)
+               SPI_CLK_FAST();
+       else
+               SPI_CLK_SLOW();
+
+       /* Dummy clock (force DO enabled) */
+       spi_rcvr();
+
+       if (wait_ready()) {
+               //debug("***  exit select() == 1\n");
+               return 1;       /* OK */
+       }
+       deselect(drv);
+       //debug("***  exit select() == 0\n");
+
+       return 0;       /* Timeout */
+}
+
+/*-----------------------------------------------------------------------*/
+/* Power Control  (Platform dependent)                                   */
+/*-----------------------------------------------------------------------*/
+/* When the target system does not support socket power control, there   */
+/* is nothing to do in these functions and chk_power always returns 1.   */
+
+static
+void power_on(BYTE drv)
+{
+       //debug("*** enter power_on(%.2x)\n", drv);
+
+       if (drv == 0) {
+#ifdef SD_PWR_0
+               SD_PWR_0 = 0;           /* Drives PWR pin high */
+#endif
+
+       } else {
+#ifdef SD_PWR_1
+               SD_PWR_1 = 0;           /* Drives PWR pin high */
+#endif
+       }
+#if defined SD_PWR_0 || defined SD_PWR_1
+               for (uint32_t to = get_timer(0); get_timer(to) < 30;)
+                       ; /* Wait for 30ms */
+#endif
+       //debug("***  exit power_on(%.2x)\n", drv);
+}
+
+static
+void power_off(BYTE drv)
+{
+       //debug("*** enter power_off(%.2x)\n", drv);
+       select(drv);            /* Wait for card ready */
+       deselect(drv);
+
+       if (drv == 0) {
+#ifdef SD_PWR_0
+               SD_PWR_0 = 1;           /* Socket power OFF */
+#endif
+       } else {
+#ifdef SD_PWR_1
+               SD_PWR_1 = 1;           /* Socket power OFF */
+#endif
+       }
+       ATOMIC_BLOCK(ATOMIC_FORCEON) {
+               socket[drv].stat |= STA_NOINIT;
+       }
+       //debug("***  exit power_off(%.2x)\n", drv);
+}
+
+#if 0
+static
+int chk_power(BYTE drv) /* Socket power state: 0=off, 1=on */
+{
+       if (drv == 0) {
+#ifdef SD_PWR_0
+               return SD_PWR_0 == 0;
+#else
+               return 1;
+#endif /* SD_PWR_PIN */
+       } else {
+#ifdef SD_PWR_1
+               return SD_PWR_1 == 0;
+#else
+               return 1;
+#endif /* SD_PWR_PIN */
+       }
+}
+#endif
+
+/*-----------------------------------------------------------------------*/
+/* Receive a data packet from MMC                                        */
+/*-----------------------------------------------------------------------*/
+
+static
+int rcvr_datablock (
+       BYTE *buff,                     /* Data buffer to store received data */
+UINT btr /* Byte count (must be multiple of 4) */
+) {
+       BYTE token, tmp;
+       uint32_t to = get_timer(0);
+
+       /* Wait for data packet in timeout of 200ms */
+       do {
+               token = spi_rcvr();
+       } while ((token == 0xFF) && get_timer(to) < 200);
+       if(token != 0xFE) return 0;             /* If not valid data token, retutn with error */
+
+       tmp = spi_rcvr(); /* shift in first byte */
+       spi_write(0xff); /* start shift in next byte */
+       while (--btr) {
+               *buff++ = tmp;
+               asm volatile (""::"r"(buff), "r"(btr));
+               spi_wait();
+               tmp = SPDR;
+               spi_write(0xff);
+       }
+       *buff = tmp; /* store last byte in buffer while SPI module shifts in crc part1 */
+       spi_wait();
+       spi_rcvr(); /* second crc */
+
+       return 1; /* Return with success */
+}
+
+/*-----------------------------------------------------------------------*/
+/* Send a data packet to MMC                                             */
+/*-----------------------------------------------------------------------*/
+
+#if    _USE_WRITE
+static
+int xmit_datablock (
+               const BYTE *buff, /* 512 byte data block to be transmitted */
+               BYTE token /* Data/Stop token */
+)
+{
+       BYTE resp, tmp;
+       UINT btr;
+
+       if (!wait_ready()) return 0;
+
+       spi_write(token); /* Xmit data token */
+       if (token != 0xFD) { /* Is data token */
+               btr = 512;
+               do {
+                       tmp = *buff++;
+                       spi_wait();
+                       spi_write(tmp);
+               }while (--btr);
+               spi_wait();
+               spi_xmit(0xff); /* CRC (Dummy) */
+               spi_xmit(0xff);
+               resp = spi_rcvr(); /* Reveive data response */
+               return ((resp & 0x1F) != 0x05) ? 0 : 1; /* If not accepted, return with error */
+       }
+
+       spi_wait();
+       return 1;
+}
+#endif /* _USE_WRITE */
+
+/*-----------------------------------------------------------------------*/
+/* Send a command packet to MMC                                          */
+/*-----------------------------------------------------------------------*/
+
+static
+BYTE send_cmd (                /* Returns R1 resp (bit7==1:Send failed) */
+       BYTE drv,       /* Physical drive nmuber (0) */
+       BYTE cmd,       /* Command index */
+       DWORD arg       /* Argument */
+) {
+       union {
+               DWORD as32;
+               BYTE as8[4];
+       } argtmp;
+       BYTE n, res;
+
+       if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
+               cmd &= 0x7F;
+               res = send_cmd(drv, CMD55, 0);
+               if (res > 1)
+                       return res;
+       }
+
+       //debug("*** send_cmd( %.2x )", cmd);
+
+       /* Select the card and wait for ready except to stop multiple block read */
+       if (cmd != CMD12) {
+               deselect(drv);
+               if (!select(drv)) {
+                       //debug(" == %.2x\n", 0xff);
+                       return 0xFF;
+               }
+       }
+
+       /* Send command packet */
+       spi_xmit(0x40 | cmd); /* Start + Command index */
+       argtmp.as32 = arg;
+       spi_xmit(argtmp.as8[3]); /* Argument[31..24] */
+       spi_xmit(argtmp.as8[2]); /* Argument[23..16] */
+       spi_xmit(argtmp.as8[1]); /* Argument[15..8] */
+       spi_xmit(argtmp.as8[0]); /* Argument[7..0] */
+
+       n = 0x01; /* Dummy CRC + Stop */
+       if (cmd == CMD0)
+               n = 0x95; /* Valid CRC for CMD0(0) */
+       if (cmd == CMD8)
+               n = 0x87; /* Valid CRC for CMD8(0x1AA) */
+       spi_xmit(n);
+
+       /* Receive command response */
+       if (cmd == CMD12)
+               spi_rcvr(); /* Skip a stuff byte when stop reading */
+       n = 10; /* Wait for a valid response in timeout of 10 attempts */
+       do
+               res = spi_rcvr();
+       while ((res & 0x80) && --n);
+
+       //debug(" == %.2x\n", res);
+       return res; /* Return with the response value */
+}
+
+/*--------------------------------------------------------------------------
+
+ Public Functions
+
+ ---------------------------------------------------------------------------*/
+
+void setup_mmc(void)
+{
+#ifdef SD_PWR_0
+               SD_PWR_1 = 1;           /* Drives PWR pin low */
+               SD_PWR_0_DDR = 1;       /* Turns on PWR pin as output */
+#endif
+#ifdef SD_WP_0
+               SD_WP_0_DDR = 0;
+               SD_WP_0 = 1;            /* Pullup */
+#endif
+
+#ifdef SD_PWR_1
+               SD_PWR_1 = 1;           /* Drives PWR pin low */
+               SD_PWR_1_DDR = 1;       /* Turns on PWR pin as output */
+#endif
+#ifdef SD_WP_1
+               SD_WP_1_DDR = 0;
+               SD_WP_1 = 1;            /* Pullup */
+#endif
+
+       /* SPI as master */
+       PRR0 &= ~_BV(PRSPI);
+       SPI_DDR = (SPI_DDR & ~(_BV(SPI_MISO) | _BV(SPI_SS)))
+                       | _BV(SPI_MOSI) | _BV(SPI_SCK);
+       SPI_PORT = SPI_PORT & ~(_BV(SPI_MOSI) | _BV(SPI_SCK));
+
+#if defined SD_CD_0
+       SD_CD_0_DDR = 0;
+       SD_CD_0 = 1;                    /* Pullup */
+#elif defined SD_CS_0_IN
+       SD_CS_0_DDR = 0;
+       SD_CS_0 = 0;
+#endif
+#if defined SD_CD_0 || !defined SD_CS_0_IN
+       SD_CS_0 = 1;
+       SD_CS_0_DDR = 1;
+#endif
+
+#if defined SD_CD_1
+       SD_CD_1_DDR = 0;
+       SD_CD_1 = 1;                    /* Pullup */
+#elif defined SD_CS_1_IN
+       SD_CS_1_DDR = 0;
+       SD_CS_1 = 0;                    /* No Pullup */
+#endif
+#if defined SD_CD_1 || !defined SD_CS_1_IN
+       SD_CS_1 = 1;                    /* Set High */
+       SD_CS_1_DDR = 1;
+#endif
+}
+
+/*-----------------------------------------------------------------------*/
+/* Initialize Disk Drive                                                 */
+/*-----------------------------------------------------------------------*/
+
+#define MMC_INIT_TO 1000       /* 1s */
+
+DSTATUS disk_initialize (
+       BYTE drv                /* Physical drive nmuber (0) */
+)
+{
+       BYTE n, cmd, ty, ocr[4];
+       DSTATUS res;
+
+       if (drv >= MAX_DRV)
+               return STA_NOINIT;
+       res = socket[drv].stat;
+       if (res & STA_NODISK) {
+               return res & STAT_MASK; /* No card in the socket */
+       }
+       power_on(drv); /* Force socket power on */
+       ATOMIC_BLOCK(ATOMIC_FORCEON) {
+               socket[drv].stat &= ~STA_FAST;
+       }
+       SPI_CLK_SLOW();
+       for (n = 10; n; n--)
+               spi_rcvr(); /* 80 dummy clocks */
+
+       ty = 0;
+       if (send_cmd(drv, CMD0, 0) == 1) { /* Enter Idle state */
+               /* Init timeout timer */
+               uint32_t timer = get_timer(0);
+
+               if (send_cmd(drv, CMD8, 0x1AA) == 1) {  /* SDv2? */
+                       /* Get trailing return value of R7 resp */
+                       for (n = 0; n < 4; n++)
+                               ocr[n] = spi_rcvr();
+                       if (ocr[2] == 0x01 && ocr[3] == 0xAA) {
+                               /* The card can work at vdd range of 2.7-3.6V */
+                               while (get_timer(timer) < MMC_INIT_TO
+                                       && send_cmd(drv, ACMD41, 1UL << 30))
+                                       ; /* Wait for leaving idle state (ACMD41 with HCS bit) */
+                               if (get_timer(timer) < MMC_INIT_TO && send_cmd(drv, CMD58, 0) == 0) {
+                                       /* Check CCS bit in the OCR */
+                                       for (n = 0; n < 4; n++)
+                                               ocr[n] = spi_rcvr();
+                                       ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;      /* SDv2 */
+                               }
+                       }
+               } else {                                                        /* SDv1 or MMCv3 */
+                       if (send_cmd(drv, ACMD41, 0) <= 1) {
+                               ty = CT_SD1; cmd = ACMD41;      /* SDv1 */
+                       } else {
+                               ty = CT_MMC; cmd = CMD1;        /* MMCv3 */
+                       }
+
+                       /* Wait for leaving idle state */
+                       while (get_timer(timer) < MMC_INIT_TO && send_cmd(drv, cmd, 0))
+                               ;
+
+                       /* Set R/W block length to 512 */
+                       if (!(get_timer(timer) < MMC_INIT_TO) || send_cmd(drv, CMD16, 512) != 0)
+                               ty = 0;
+               }
+       }
+       socket[drv].CardType = ty;
+       deselect(drv);
+
+       if (ty) { /* Initialization succeded */
+               /* Clear STA_NOINIT */
+               ATOMIC_BLOCK(ATOMIC_FORCEON) {
+                       res = (socket[drv].stat & ~STA_NOINIT) | STA_FAST;
+                       socket[drv].stat = res;
+               }
+       } else { /* Initialization failed */
+               power_off(drv);
+       }
+
+       return socket[drv].stat & STAT_MASK;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Get Disk Status                                                       */
+/*-----------------------------------------------------------------------*/
+
+DSTATUS disk_status (
+       BYTE drv        /* Physical drive nmuber (0) */
+)
+{
+       DSTATUS res;
+
+       //debug("*****  disk_status(%.2x)", drv);
+       if (drv >= MAX_DRV)
+               res = STA_NOINIT;
+       else
+               res = socket[drv].stat & STAT_MASK;
+
+       //debug(" == %.2x\n", res);
+       return res;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Read Sector(s)                                                        */
+/*-----------------------------------------------------------------------*/
+
+DRESULT disk_read (
+       BYTE drv,       /* Physical drive nmuber (0) */
+       BYTE *buff,     /* Pointer to the data buffer to store read data */
+       DWORD sector,   /* Start sector number (LBA) */
+       UINT count      /* Sector count (1..255) */
+)
+{
+       BYTE cmd;
+
+       if (drv >= MAX_DRV || !count)
+               return RES_PARERR;
+       if (socket[drv].stat & STA_NOINIT)
+               return RES_NOTRDY;
+
+       /* Convert to byte address if needed */
+       if (!(socket[drv].CardType & CT_BLOCK))
+               sector *= 512;
+
+       /*  READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
+       cmd = count > 1 ? CMD18 : CMD17;
+       if (send_cmd(drv, cmd, sector) == 0) {
+               do {
+                       if (!rcvr_datablock(buff, 512))
+                               break;
+                       buff += 512;
+               } while (--count);
+               if (cmd == CMD18)
+                       send_cmd(drv, CMD12, 0);        /* STOP_TRANSMISSION */
+       }
+       deselect(drv);
+
+       return count ? RES_ERROR : RES_OK;
+}
+
+/*-----------------------------------------------------------------------*/
+/* Write Sector(s)                                                       */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_WRITE
+DRESULT disk_write (
+       BYTE drv,       /* Physical drive nmuber (0) */
+       const BYTE *buff, /* Pointer to the data to be written */
+       DWORD sector,   /* Start sector number (LBA) */
+       UINT count      /* Sector count (1..255) */
+)
+{
+       DSTATUS res;
+
+       if (drv >= MAX_DRV || !count)
+               return RES_PARERR;
+       res = socket[drv].stat;
+       if ( res & STA_NOINIT)
+               return RES_NOTRDY;
+       if (res & STA_PROTECT)
+               return RES_WRPRT;
+
+       /* Convert to byte address if needed */
+       if (!(socket[drv].CardType & CT_BLOCK))
+               sector *= 512;
+
+       if (count == 1) {
+               /* Single block write */
+               if ((send_cmd(drv, CMD24, sector) == 0) /* WRITE_BLOCK */
+                               && xmit_datablock(buff, 0xFE))
+               count = 0;
+       } else {
+               /* Multiple block write */
+               if (socket[drv].CardType & CT_SDC)
+                       send_cmd(drv, ACMD23, count);
+               if (send_cmd(drv, CMD25, sector) == 0) {
+                       /* WRITE_MULTIPLE_BLOCK */
+                       do {
+                               if (!xmit_datablock(buff, 0xFC))
+                                       break;
+                               buff += 512;
+                       } while (--count);
+                       if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
+                               count = 1;
+               }
+       }
+       deselect(drv);
+
+       return count ? RES_ERROR : RES_OK;
+}
+#endif /* _USE_WRITE */
+
+/*-----------------------------------------------------------------------*/
+/* Miscellaneous Functions                                               */
+/*-----------------------------------------------------------------------*/
+
+#if _USE_IOCTL
+DRESULT disk_ioctl (
+       BYTE drv,               /* Physical drive nmuber (0) */
+       BYTE cmd,               /* Control code */
+       void *buff              /* Buffer to send/receive control data */
+)
+{
+       DRESULT res;
+       BYTE n, csd[16], *ptr = buff;
+       DWORD csize;
+
+       if (drv >= MAX_DRV)
+               return RES_PARERR;
+
+       res = RES_ERROR;
+
+       if (socket[drv].stat & STA_NOINIT)
+               return RES_NOTRDY;
+
+       /* TODO: SPI clock? */
+
+       switch (cmd) {
+       case CTRL_SYNC :                /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
+               if (select(drv))
+                       res = RES_OK;
+               break;
+
+       case GET_SECTOR_COUNT: /* Get number of sectors on the disk (DWORD) */
+               if ((send_cmd(drv, CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
+                       if ((csd[0] >> 6) == 1) {       /* SDC ver 2.00 */
+                               csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
+                               *(DWORD*)buff = csize << 10;
+                       } else {                                        /* SDC ver 1.XX or MMC*/
+                               n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
+                               csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
+                               *(DWORD*)buff = csize << (n - 9);
+                       }
+                       res = RES_OK;
+               }
+               break;
+
+       case GET_BLOCK_SIZE:    /* Get erase block size in unit of sector (DWORD) */
+               if (socket[drv].CardType & CT_SD2) {    /* SDv2? */
+                       if (send_cmd(drv, ACMD13, 0) == 0) { /* Read SD status */
+                               spi_rcvr();
+                               if (rcvr_datablock(csd, 16)) { /* Read partial block */
+                                       for (n = 64 - 16; n; n--)
+                                               spi_rcvr(); /* Purge trailing data */
+                                       *(DWORD*) buff = 16UL << (csd[10] >> 4);
+                                       res = RES_OK;
+                               }
+                       }
+               } else {                                        /* SDv1 or MMCv3 */
+                       if ((send_cmd(drv, CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
+                               if (socket[drv].CardType & CT_SD1) {    /* SDv1 */
+                                       *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
+                               } else {                                        /* MMCv3 */
+                                       *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
+                               }
+                               res = RES_OK;
+                       }
+               }
+               break;
+
+       /* Following commands are never used by FatFs module */
+
+       case MMC_GET_TYPE:              /* Get card type flags (1 byte) */
+               *ptr = socket[drv].CardType;
+               res = RES_OK;
+               break;
+
+       case MMC_GET_CSD: /* Receive CSD as a data block (16 bytes) */
+               if (send_cmd(drv, CMD9, 0) == 0 /* READ_CSD */
+               && rcvr_datablock(ptr, 16))
+                       res = RES_OK;
+               break;
+
+       case MMC_GET_CID: /* Receive CID as a data block (16 bytes) */
+               if (send_cmd(drv, CMD10, 0) == 0 /* READ_CID */
+               && rcvr_datablock(ptr, 16))
+                       res = RES_OK;
+               break;
+
+       case MMC_GET_OCR: /* Receive OCR as an R3 resp (4 bytes) */
+               if (send_cmd(drv, CMD58, 0) == 0) { /* READ_OCR */
+                       for (n = 4; n; n--)
+                               *ptr++ = spi_rcvr();
+                       res = RES_OK;
+               }
+               break;
+
+       case MMC_GET_SDSTAT: /* Receive SD status as a data block (64 bytes) */
+               if (send_cmd(drv, ACMD13, 0) == 0) { /* SD_STATUS */
+                       spi_rcvr();
+                       if (rcvr_datablock(ptr, 64))
+                               res = RES_OK;
+               }
+               break;
+
+       case CTRL_POWER_OFF :   /* Power off */
+               power_off(drv);
+               res = RES_OK;
+               break;
+
+       default:
+               res = RES_PARERR;
+       }
+
+       deselect(drv);
+
+       return res;
+}
+#endif /* _USE_IOCTL */
+
+/*-----------------------------------------------------------------------*/
+/* Device Timer Interrupt Procedure  (Platform dependent)                */
+/*-----------------------------------------------------------------------*/
+/* This function must be called in period of 10ms                        */
+
+void disk_timerproc (void)
+{
+       BYTE s;
+
+       s = socket[0].stat;
+#ifdef SD_WP_0
+       if (SD_WP_0_IN == 0)                    /* Write protected */
+               s |= STA_PROTECT;
+       else                                                    /* Write enabled */
+               s &= ~STA_PROTECT;
+#endif
+
+#if defined SD_CD_0
+       if (SD_CD_0_IN == 0)                    /* Card inserted */
+               s &= ~STA_NODISK;
+       else                                                    /* Socket empty */
+               s |= (STA_NODISK | STA_NOINIT);
+#elif defined SD_CS_0_IN
+       if (SD_CS_0_DDR == 0) {
+               if (SD_CS_0_IN == 1)            /* Card inserted */
+                       s &= ~STA_NODISK;
+               else                                            /* Socket empty */
+                       s |= (STA_NODISK | STA_NOINIT);
+       }
+#endif
+       socket[0].stat = s;                             /* Update MMC status */
+
+       s = socket[1].stat;
+#ifdef SD_WP_1
+       if (SD_WP_1_IN == 0)                    /* Write protected */
+               s |= STA_PROTECT;
+       else                                                    /* Write enabled */
+               s &= ~STA_PROTECT;
+#endif
+
+#if defined SD_CD_1
+       if (SD_CD_1_IN == 0)                    /* Card inserted */
+               s &= ~STA_NODISK;
+       else                                                    /* Socket empty */
+               s |= (STA_NODISK | STA_NOINIT);
+#elif defined SD_CS_1_IN
+       if (SD_CS_1_DDR == 0) {
+               if (SD_CS_1_IN == 1)            /* Card inserted */
+                       s &= ~STA_NODISK;
+               else                                            /* Socket empty */
+                       s |= (STA_NODISK | STA_NOINIT);
+       }
+#endif
+       socket[1].stat = s;                     /* Update MMC status */
+}
diff --git a/avr/pcf8583.c b/avr/pcf8583.c
new file mode 100644 (file)
index 0000000..bdb779f
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * Date & Time support for Philips PCF8583 RTC
+ */
+
+#include "common.h"
+#include <stdlib.h>
+#include "time.h"
+#include "rtc.h"
+#include "i2c.h"
+#include "command.h"
+#include "debug.h"
+
+#define  DEBUG_RTC 0
+
+#define debug_rtc(fmt, args...)                        \
+       debug_cond(DEBUG_RTC, fmt, ##args)
+
+#define REG_CS         0x00    /* control/status */
+#define REG_CSEC       0x01    /* hundredth of a second */
+#define REG_SEC                0x02    /* seconds */
+#define REG_MIN                0x03    /* minutes */
+#define REG_HOUR       0x04    /* hours */
+#define REG_YRDATE     0x05    /* year/date */
+#define REG_WDMON      0x06    /* weekdays/months */
+#define NR_OF_REGS     7
+
+
+/* ------------------------------------------------------------------------- */
+
+static uint_fast8_t bcd2bin(uint8_t val)
+{
+       return (val >> 4) * 10 + (val & 0x0f);
+}
+
+static uint8_t bin2bcd (uint_fast8_t val)
+{
+       div_t d = div(val, 10);
+
+       return (d.quot << 4) | d.rem;
+}
+
+
+int rtc_get (struct tm *tmp)
+{
+       uint8_t rtcbuf[NR_OF_REGS];
+       int16_t year;
+
+       i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, rtcbuf, NR_OF_REGS);
+       i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0x10, 1, (uint8_t *) &year, 2);
+
+       debug_rtc("Get RTC year: %u, wdays/month: %02x, year/date: %02x, "
+               "hour: %02x, min: %02x, sec: %02x, (stat: %02x)\n", year,
+               rtcbuf[6], rtcbuf[5], rtcbuf[4], rtcbuf[3], rtcbuf[2], rtcbuf[0]);
+
+       tmp->tm_sec  = bcd2bin (rtcbuf[REG_SEC]    & 0x7F);
+       tmp->tm_min  = bcd2bin (rtcbuf[REG_MIN]    & 0x7F);
+       tmp->tm_hour = bcd2bin (rtcbuf[REG_HOUR]   & 0x3F);
+       tmp->tm_mday = bcd2bin (rtcbuf[REG_YRDATE] & 0x3F);
+       tmp->tm_mon  = bcd2bin (rtcbuf[REG_WDMON]  & 0x1F) - 1;
+       while (year%4 != (rtcbuf[REG_YRDATE]>>6)) {
+               year++;
+               i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0x10, 1, (uint8_t *) &year, 2);
+       }
+       tmp->tm_year  = year - 1900;
+       tmp->tm_wday = rtcbuf[REG_WDMON] >> 5;
+       tmp->tm_yday = 0;
+       tmp->tm_isdst= 0;
+
+       debug_rtc( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+       return rtcbuf[REG_CS] == 0x04 ? 0 : 1;
+}
+
+int rtc_set (struct tm *tmp)
+{
+       uint8_t rtcbuf[NR_OF_REGS];
+       int16_t year = tmp->tm_year + 1900;
+
+       debug_rtc("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+               tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+               tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+
+       rtcbuf[REG_CS] = 0x84;
+       rtcbuf[REG_CSEC] = 0x00;
+       rtcbuf[REG_WDMON ] = (bin2bcd(tmp->tm_mon) + 1) | ((tmp->tm_wday) << 5);
+       rtcbuf[REG_YRDATE] = ((year % 4) << 6) | bin2bcd(tmp->tm_mday);
+       rtcbuf[REG_HOUR  ] = bin2bcd(tmp->tm_hour);
+       rtcbuf[REG_MIN   ] = bin2bcd(tmp->tm_min);
+       rtcbuf[REG_SEC   ] = bin2bcd(tmp->tm_sec);
+
+       i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0,    1, rtcbuf, NR_OF_REGS);
+       i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0x10, 1, (uint8_t *) &year, 2);
+       rtcbuf[REG_CS] = 0x04;
+       i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 1, rtcbuf, 1);
+
+       return 0;
+}
diff --git a/avr/print-utils.c b/avr/print-utils.c
new file mode 100644 (file)
index 0000000..83f86a9
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "common.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "con-utils.h"
+#include "print-utils.h"
+
+void print_blanks(uint_fast8_t count)
+{
+       while(count--)
+               putchar(' ');
+}
+
+
+int eeprom_read_buf(uint8_t *buf, uint32_t addr, uint8_t count)
+{
+       eeprom_read_block((void *) buf, (const void *) (size_t) addr, count);
+       return 0;
+}
+
+int ram_read_buf(uint8_t *buf, uint32_t addr, uint8_t count)
+{
+       while (count--)
+               *buf++ = *(uint8_t *) (size_t) addr++;
+       return 0;
+}
+
+int flash_read_buf(uint8_t *buf, uint32_t addr, uint8_t count)
+{
+       while (count--)
+               *buf++ = *(const __memx uint8_t *) (__uint24) addr++;
+       return 0;
+}
+
+int dump_mem(uint32_t address, uint32_t offset, uint32_t len,
+               int (*readfkt)(uint8_t *, uint32_t, uint8_t), char *title)
+{
+       uint8_t buf[16];
+       char *indent = NULL;
+       uint8_t llen = 16;
+       uint8_t pre = offset % 16;
+       offset = offset & ~0x0f;
+       len += pre;
+       uint8_t i;
+
+       if (title && *title) {
+               printf_P(PSTR("%s\n"),title);
+               indent = "    ";
+       }
+
+       while (len) {
+               if (len < 16)
+                       llen = len;
+               if (readfkt(buf, address, llen - pre) != 0)
+                       return -2; /* TODO: Error codes */
+
+               printf_P(PSTR("%s%.5lx:"),indent, offset);
+               for (i = 0; i < llen; i++) {
+                       if ((i % 8) == 0)
+                               putchar(' ');
+                       if (i < pre)
+                               printf_P(PSTR(".. "));
+                       else
+                               printf_P(PSTR("%.2x "), buf[i-pre]);
+               }
+               /* fill line with whitespace for nice ASCII print */
+               print_blanks(3 * (16u - i) + (16u-i)/8 + 1 + pre);
+               /* Print data in ASCII characters */
+               for (i = pre; i < llen; i++)
+                       printf_P(PSTR("%c"), isprint(buf[i-pre]) ? buf[i-pre] : '.');
+               putchar('\n');
+
+               address += llen - pre;
+               offset += 16;
+               pre = 0;
+               len -= llen;
+
+               if (ctrlc())
+                       return -1;
+       }
+       return 0;
+}
+
+void dump_eep(uint32_t addr, unsigned int len, char *title)
+{
+       dump_mem(addr, addr, len, eeprom_read_buf, title);
+}
+
+void dump_ram(uint8_t *addr, size_t offset, unsigned int len, char *title)
+{
+       dump_mem((uint32_t) (size_t) addr, offset, len, ram_read_buf, title);
+}
diff --git a/avr/serial.c b/avr/serial.c
new file mode 100644 (file)
index 0000000..adbc3c4
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <util/atomic.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "ring.h"
+#include "serial.h"
+
+
+static int _write(char c, FILE *stream);
+static FILE mystdout = FDEV_SETUP_STREAM(_write,
+               NULL, _FDEV_SETUP_WRITE);
+
+
+
+#define BUFFER_SIZE 128
+
+#if ((BUFFER_SIZE-1) & BUFFER_SIZE)
+# error: BUFFER_SIZE not power of 2
+#endif
+
+#if ((BUFFER_SIZE) > 256)
+# error: BUFFER_SIZE
+#endif
+
+struct ring rx_ring;
+struct ring tx_ring;
+uint8_t rx_ring_buffer[BUFFER_SIZE];
+uint8_t tx_ring_buffer[BUFFER_SIZE];
+
+
+
+/* Initialize UART */
+
+void usart0_setup(unsigned long baud) {
+
+       ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+
+               PRR0 &= ~_BV(PRUSART0);
+               UCSR0B = 0;
+
+               /* Initialize ring buffers. */
+               ring_init(&rx_ring, rx_ring_buffer, BUFFER_SIZE);
+               ring_init(&tx_ring, tx_ring_buffer, BUFFER_SIZE);
+
+               UCSR0A = 0;
+               UBRR0  = F_CPU / baud / 16 - 1;
+               UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
+               UCSR0C = 3 << UCSZ00;
+       };
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* UART RXC interrupt */
+
+ISR(USART0_RX_vect)
+{
+       uint8_t d;
+
+       d = UDR0;
+       ring_write_ch(&rx_ring, d);
+}
+
+/* UART UDRE interrupt */
+
+ISR(USART0_UDRE_vect)
+{
+       int d = ring_read_ch(&tx_ring);
+
+       if (d < 0) {
+               /* Disable TX empty interrupt. */
+               UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0);
+       } else {
+               UDR0 = d;
+       }
+}
+
+/*--------------------------------------------------------------------------*/
+
+void serial_setup(unsigned long baud)
+{
+       stdout = &mystdout;
+       usart0_setup(baud);
+}
+
+/*--------------------------------------------------------------------------*/
+
+int _write(char c, FILE *stream)
+{
+       (void) stream;
+
+       if (c == '\n')
+               serial_putc('\r');
+       serial_putc(c);
+
+       return 0;
+}
+
+int serial_getc(void)
+{
+       return ring_read_ch(&rx_ring);
+}
+
+void serial_putc(char data)
+{
+       while (ring_write_ch(&tx_ring, data) < 0)
+               ;
+
+       /* Enable the TXE interrupt. */
+       UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0) | _BV(UDRIE0);
+}
+
+uint_fast8_t serial_tstc(void)
+{
+       return !ring_is_empty(&rx_ring);
+}
diff --git a/avr/timer.c b/avr/timer.c
new file mode 100644 (file)
index 0000000..1b15985
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include "timer.h"
+#include <avr/interrupt.h>
+#include <util/atomic.h>
+#include "time.h"
+
+/* timer interrupt/overflow counter */
+/* counts up every ms. */
+static volatile
+uint32_t timestamp;
+
+/*
+ * 1000Hz timer interrupt generated by OC4A
+ */
+ISR(TIMER4_COMPA_vect)
+{
+       static int_fast8_t tick_10ms;
+       static int_fast8_t tick_1s;
+       int_fast8_t i, j;
+
+       extern void disk_timerproc(void);
+
+       OCR4A += F_CPU / 1000;  /* 1000Hz interval */
+
+       timestamp++;
+
+       i = tick_10ms + 1;
+       if (i == 10) {
+               Stat |= S_10MS_TO;
+
+               /* Drive timer procedure of low level disk I/O module */
+               disk_timerproc();
+
+               j = tick_1s - 1;
+               if (j == 0) {
+                       system_tick();
+                       j = 100;
+               }
+               tick_1s = j;
+               i = 0;
+       }
+       tick_10ms = i;
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+uint32_t get_timer(uint32_t base)
+{
+       uint32_t ret;
+       ATOMIC_BLOCK(ATOMIC_FORCEON)
+       {
+               ret = timestamp;
+       }
+       return ret - base;
+}
diff --git a/avr/xmalloc.c b/avr/xmalloc.c
new file mode 100644 (file)
index 0000000..d42d5c9
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <stdlib.h>
+#include "debug.h"
+#include "xmalloc.h"
+
+void* xmalloc(size_t size)
+{
+       void *p;
+
+       p = malloc(size);
+
+       if (p == NULL)
+               debug("*** Out of memory!\n");
+
+       return p;
+}
+
+
+void* xrealloc(void *p, size_t size)
+{
+       p = realloc(p, size);
+
+       if (p == NULL)
+               debug("*** Out of memory!\n");
+
+       return p;
+}
diff --git a/avr/z180-serv.c b/avr/z180-serv.c
new file mode 100644 (file)
index 0000000..d1f52dd
--- /dev/null
@@ -0,0 +1,828 @@
+/*
+ * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include "z180-serv.h"
+#include "common.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <util/atomic.h>
+
+#include "config.h"
+#include "background.h"
+#include "env.h"
+#include "ff.h"
+#include "serial.h"
+#include "z80-if.h"
+#include "debug.h"
+#include "print-utils.h"
+#include "timer.h"
+#include "time.h"
+#include "bcd.h"
+#include "rtc.h"
+
+#define DEBUG_CPM_SDIO 0       /* set to 1 to debug */
+
+#define debug_cpmsd(fmt, args...)                                                          \
+       debug_cond(DEBUG_CPM_SDIO, fmt, ##args)
+
+
+/*--------------------------------------------------------------------------*/
+
+struct msg_item {
+       uint8_t fct;
+       uint8_t sub_min, sub_max;
+       void (*func)(uint8_t, int, uint8_t *);
+};
+
+uint32_t msg_to_addr(uint8_t *msg)
+{
+       union {
+               uint32_t as32;
+               uint8_t as8[4];
+       } addr;
+
+       addr.as8[0] = msg[0];
+       addr.as8[1] = msg[1];
+       addr.as8[2] = msg[2];
+       addr.as8[3] = 0;
+
+       return addr.as32;
+}
+
+
+static int msg_xmit_header(uint8_t func, uint8_t subf, int len)
+{
+       z80_memfifo_putc(fifo_msgout, 0xAE);
+       z80_memfifo_putc(fifo_msgout, len+2);
+       z80_memfifo_putc(fifo_msgout, func);
+       z80_memfifo_putc(fifo_msgout, subf);
+
+       return 0;
+}
+
+int msg_xmit(uint8_t func, uint8_t subf, int len, uint8_t *msg)
+{
+       msg_xmit_header(func, subf, len);
+       while (len--)
+               z80_memfifo_putc(fifo_msgout, *msg++);
+
+       return 0;
+}
+
+void do_msg_ini_memfifo(uint8_t subf, int len, uint8_t * msg)
+{
+       (void)len;
+
+       z80_memfifo_init(subf, msg_to_addr(msg));
+}
+
+
+void do_msg_char_out(uint8_t subf, int len, uint8_t * msg)
+{
+       (void)subf;
+
+       while (len--)
+               putchar(*msg++);
+}
+
+/* echo message */
+void do_msg_echo(uint8_t subf, int len, uint8_t * msg)
+{
+       (void)subf;
+
+       /* send re-echo */
+       msg_xmit(1, 3, len, msg);
+}
+
+/* get timer */
+void do_msg_get_timer(uint8_t subf, int len, uint8_t * msg)
+{
+       uint32_t time_ms = (len >= 4) ? *(uint32_t *) msg : 0;
+
+       time_ms = get_timer(time_ms);
+       msg_xmit(3, subf, sizeof(time_ms), (uint8_t *) &time_ms);
+}
+
+/* ---------------------------------------------------------------------------*/
+
+#define CPM_DAY_OFFSET ((1978-1900) * 365 + 19)                /* 19 leap years */
+
+/*
+ * Convert CP/M time stamp to a broken-down time structure
+ *
+ */
+int mk_date_time (int len, uint8_t *msg, struct tm *tmp)
+{
+       time_t stamp;
+
+       if (len != 5)
+               return -1;
+
+       /* days since 2000-01-01 */
+       long days = msg[3] + (msg[4] << 8) - 8036;
+
+       if (days < 0)
+               return -1;
+
+       stamp = days * ONE_DAY;
+       stamp += bcd2bin(msg[0]);
+       stamp += bcd2bin(msg[1]) * 60 ;
+       stamp += bcd2bin(msg[2]) * 3600L;
+       gmtime_r(&stamp, tmp);
+       return 0;
+}
+
+void mk_cpm_time(struct tm *tmp, uint8_t cpm_time[5])
+{
+       uint16_t days = 1;
+       uint_fast8_t leap=2;
+
+       for (int year=78; year < tmp->tm_year; year++) {
+               days = days + 365 + (leap == 0);
+               leap = (leap+1)%4;
+       }
+       days += tmp->tm_yday;
+
+       cpm_time[0] = bin2bcd(tmp->tm_sec);
+       cpm_time[1] = bin2bcd(tmp->tm_min);
+       cpm_time[2] = bin2bcd(tmp->tm_hour);
+       cpm_time[3] = days;
+       cpm_time[4] = days >> 8;
+}
+
+/* get/set cp/m time */
+void do_msg_get_set_time(uint8_t subf, int len, uint8_t * msg)
+{
+       struct tm t;
+       uint8_t cpm_time[5];
+       int rc;
+
+       memset(cpm_time, 0, ARRAY_SIZE(cpm_time));
+
+       switch (subf) {
+       case 3:                 /* set date & time */
+               /* initialize t with current time */
+               rc = rtc_get (&t);
+
+               if (rc >= 0) {
+                       /* insert new date & time */
+                       if (mk_date_time (len, msg, &t) != 0) {
+                               my_puts_P(PSTR("## set_time: Bad date format\n"));
+                               break;
+                       }
+
+                       time_t time;
+                       time = mk_gmtime(&t);
+                       gmtime_r(&time, &t);
+
+                       /* and write to RTC */
+                       rc = rtc_set (&t);
+                       if(rc)
+                               my_puts_P(PSTR("## set_time: Set date failed\n"));
+               } else {
+                       my_puts_P(PSTR("## set_time: Get date failed\n"));
+               }
+               /* FALL TROUGH */
+       case 2:                 /* get date & time */
+               rc = rtc_get (&t);
+               if (rc >= 0) {
+                       time_t time;
+                       time = mk_gmtime(&t);
+                       //mktime(&t);
+                       gmtime_r(&time, &t);
+
+                       mk_cpm_time(&t, cpm_time);
+               } else {
+                       my_puts_P(PSTR("## get_time: Get date failed\n"));
+               }
+               break;
+       }
+
+       msg_xmit(3, subf, sizeof(cpm_time), cpm_time);
+}
+
+/* ---------------------------------------------------------------------------*/
+
+static uint8_t drv;
+static uint8_t disk_buffer[CONFIG_CPM_BLOCK_SIZE];
+static struct cpm_drive_s drv_table[CONFIG_CPM_MAX_DRIVE];
+static int handle_cpm_drv_to;
+
+typedef enum {SINGLE, START, MIDDLE, END} dbgmsg_t;
+
+void drv_debug(dbgmsg_t phase, const FLASH char *const fmt, ...)                                                           \
+{
+       struct cpm_drive_s *dp = &drv_table[drv];
+
+       if (dp->opt & DRV_OPT_DEBUG) {
+
+               va_list ap;
+               va_start (ap, fmt);
+
+               if (phase == SINGLE || phase == START)
+                       printf_P(PSTR("# %7lu dsk%d: "), get_timer(0), drv);
+
+               vfprintf_P (stdout, fmt, ap);
+
+               if (phase == SINGLE || phase == END)
+                       putc('\n', stdout);
+
+               va_end (ap);
+       }
+}
+
+int drv_list(void)
+{
+       for (uint8_t i = 0; i < CONFIG_CPM_MAX_DRIVE; i++) {
+               struct cpm_drive_s * p = &drv_table[i];
+               if (p->img_name) {
+                       printf_P(PSTR("  dsk%d: %2s %3s attached to %s\n"), i,
+                                       p->opt&DRV_OPT_RO ? "RO":"RW", p->opt&DRV_OPT_DEBUG ? "DBG":"",
+                                       p->img_name);
+               }
+       }
+       return 0;
+}
+
+int drv_detach(uint8_t unit)
+{
+       drv = unit;
+       if (drv < CONFIG_CPM_MAX_DRIVE) {
+               struct cpm_drive_s *p = &drv_table[drv];
+
+               drv_debug(SINGLE, PSTR("detach from '%s'"), p->img_name ? p->img_name : "-");
+
+               if (p->img_name) {
+                       f_close(&p->fd);
+                       free(p->img_name);
+                       p->opt = 0;
+                       p->flags &= ~DRV_FLG_DIRTY;
+                       p->img_name = NULL;
+
+                       uint32_t scb = getenv_ulong(PSTR(ENV_CPM3_SCB), 16, 0);
+                       if (scb && (z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                               z80_write(scb + 0xf0, 0xff);
+                               z80_write(p->dph + 11, 0xff);
+                               z80_bus_cmd(Release);
+                       }
+               }
+       }
+       return 0;
+}
+
+static int drv_find_file_attached(const char *fn)
+{
+       for (uint8_t i = 0; i < CONFIG_CPM_MAX_DRIVE; i++) {
+               struct cpm_drive_s *p = &drv_table[i];
+               if (p->img_name && !strcmp(fn, p->img_name)) {
+                       return i;
+               }
+       }
+       return -1;
+}
+
+int drv_attach(uint8_t unit, const char *filename, drv_opt_t options)
+{
+       int res;
+
+       drv = unit;
+       if (drv >= CONFIG_CPM_MAX_DRIVE)
+               return AT_RANGE;
+
+       struct cpm_drive_s *p = &drv_table[drv];
+
+       if (options & DRV_OPT_REATTATCH) {
+               if (filename) {
+                       return AT_ERROR;
+               }
+
+               if (!p->img_name) {
+                       return AT_NOT;
+               }
+
+               /* change options */
+               if ((p->opt ^ options) & DRV_OPT_RO) {
+                       f_close(&p->fd);
+                       res = f_open(&p->fd, p->img_name,
+                                       FA_READ | (options&DRV_OPT_RO ? 0 : FA_WRITE));
+               }
+
+               p->opt = options & ~DRV_OPT_REATTATCH;
+
+       } else {
+
+               if (p->img_name)
+                       return AT_ALREADY;
+               if (drv_find_file_attached(filename) >= 0)
+                       return AT_OTHER;
+
+               p->opt = options;
+
+               /* new attachment */
+
+               if ((p->img_name = strdup(filename)) == NULL)
+                       return AT_NOMEM;
+
+               res = f_open(&p->fd, p->img_name,
+                               FA_READ | (options&DRV_OPT_RO ? 0 : FA_WRITE));
+
+               if (!res && f_size(&p->fd) < CONFIG_CPM_DISKSIZE) {
+#if 0
+                       unsigned int bw;
+                       debug_cpmsd("            expanding image file from %ld to %ld\n",
+                                       f_size(&p->fd), CONFIG_CPM_DISKSIZE);
+
+                       res = f_lseek(&p->fd, CONFIG_CPM_DISKSIZE-CONFIG_CPM_BLOCK_SIZE);
+                       if (!res) {
+                               memset(disk_buffer, 0xe5, CONFIG_CPM_BLOCK_SIZE);
+                               res = f_write(&p->fd, disk_buffer, CONFIG_CPM_BLOCK_SIZE, &bw);
+                               if (res || bw < CONFIG_CPM_BLOCK_SIZE) {
+                                       debug_cpmsd("               failed! res: %d, bytes written: %u\n",      res, bw);
+                               }
+                               p->flags |= DRV_FLG_DIRTY;
+                               bg_setstat(handle_cpm_drv_to, 1);
+                       }
+#else
+                       drv_debug(SINGLE, PSTR("wrong image file size: %ld, should be %ld"),
+                                       f_size(&p->fd), CONFIG_CPM_DISKSIZE);
+                       res = 64;
+#endif
+               }
+               if (res) {
+                       drv_detach(drv);
+                       return AT_OPEN;
+               }
+       }
+
+       return AT_OK;
+}
+
+
+int cpm_drv_to(int state)
+{
+       static uint32_t ts;
+
+       switch(state) {
+       case 0:
+               break;
+
+       case 1:
+               ts = get_timer(0);
+               state = 2;
+               break;
+
+       case 2:
+               if (get_timer(ts) > 1000) {
+                       for (uint_fast8_t i=0; i < CONFIG_CPM_MAX_DRIVE; i++) {
+                               if (drv_table[i].flags & DRV_FLG_DIRTY) {
+                                       drv_table[i].flags &= ~DRV_FLG_DIRTY;
+                                       f_sync(&drv_table[i].fd);
+                                       drv = i;
+                                       drv_debug(SINGLE, PSTR("f_sync"));
+                               }
+                       }
+                       state = 0;
+               }
+       }
+       return state;
+}
+
+static const FLASH char * const FLASH rc_messages[] = {
+                       FSTR("OK"),
+                       FSTR("Internal error: wrong message len"),      /* 01 */
+                       FSTR("Invalid relative drive #"),                       /* 02 */
+                       FSTR("Bus timeout"),                                            /* 03 */
+                       FSTR("Access byond disk size"),                         /* 04 */
+                       FSTR("Write protect"),                                          /* 05 */
+                       FSTR("No media"),                                                       /* 06 */
+                       FSTR("R/W address == 0 !!!!"),                          /* 07 */
+               };
+
+void msg_cpm_result(uint8_t subf, uint8_t rc, int res)
+{
+       uint8_t result_msg[3];
+
+       if (res)
+               rc |= 0x80;
+
+       result_msg[0] = rc;
+       result_msg[1] = res;
+       result_msg[2] = res >> 8;
+
+       msg_xmit(2, subf, sizeof(result_msg), result_msg);
+
+       if (rc) {
+#if GCC_BUG_61443
+               char msg[40];
+               strncpy_P(msg, rc_messages[rc & 0x7f], sizeof msg -1);
+               drv_debug(END, PSTR(" rc: %.02x/%d, '%s'"),
+                                       rc, res, msg);
+#else
+               drv_debug(END, PSTR(" rc: %.02x/%d, '%S'"),
+                                       rc, res, rc_messages[rc & 0x7f]);
+#endif
+       } else
+               drv_debug(END, PSTR(""));
+
+}
+
+/*
+       db      2       ; disk command
+       ds      1       ; subcommand (login/read/write)
+       ds      1       ; @adrv (8 bits)        +0
+       ds      1       ; @rdrv (8 bits)        +1
+       ds      3       ; @xdph (24 bits)       +2
+*/
+
+void do_msg_cpm_login(uint8_t subf, int len, uint8_t * msg)
+{
+       struct cpm_drive_s *dp;
+       FRESULT res = 0;
+
+       (void)subf;
+
+       /* Get relative drive number */
+       drv = msg[1];
+       drv_debug(START, PSTR("login"));
+
+       if (len != 5) {
+               return msg_cpm_result(subf, 0x01, res);
+       }
+
+       if ( drv >= CONFIG_CPM_MAX_DRIVE) {
+               /* invalid relative drive number */
+               return msg_cpm_result(subf, 0x02, res);
+       }
+
+       dp = &drv_table[drv];
+       dp->flags &= ~DRV_FLG_OPEN;
+       dp->dph = ((uint32_t)msg[4] << 16) + ((uint16_t)msg[3] << 8) + msg[2];
+
+       if (dp->img_name == NULL) {
+               /* no file attached */
+               return msg_cpm_result(subf, 0x06, res);
+       }
+
+       f_close(&dp->fd);
+       res = f_open(&dp->fd, dp->img_name,
+                       FA_READ | (dp->opt&DRV_OPT_RO ? 0 : FA_WRITE));
+
+       dp->flags |= DRV_FLG_OPEN;
+
+       /* send  result*/
+       msg_cpm_result(subf, 0x00, res);
+}
+
+
+/*
+       db      2       ; disk command
+       ds      1       ; subcommand (login/read/write)
+       ds      1       ; @adrv (8 bits)                +0
+       ds      1       ; @rdrv (8 bits)                +1
+       ds      2       ; @trk (16 bits)                +2
+       ds      2       ; @sect(16 bits)                +4
+       ds      1       ; @cnt  (8 bits)                +6
+       ds      3       ; phys. transfer addr   +7
+*/
+
+#define ADRV   0
+#define RDRV   1
+#define TRK            2
+#define SEC            4
+#define CNT            6
+#define ADDR   7
+
+void do_msg_cpm_rw(uint8_t subf, int len, uint8_t * msg)
+{
+       struct cpm_drive_s *dp;
+       uint32_t addr;
+       uint32_t pos;
+       uint16_t track;
+       uint16_t sec;
+       uint8_t secs;
+       bool dowrite;
+       FRESULT res = 0;
+       uint8_t rc = 0;
+       bool buserr = 0;
+
+       drv = msg[RDRV];
+       dowrite = (subf == 2);
+
+       drv_debug(START, PSTR("%2S"), dowrite ? PSTR("W ") : PSTR(" R"));
+
+       if (len != 10) {
+               return msg_cpm_result(subf, 0x01, res);
+       }
+       if ( drv>= CONFIG_CPM_MAX_DRIVE) {
+               return msg_cpm_result(subf, 0x02, res);
+       }
+
+       dp = &drv_table[drv];
+       track = (uint16_t)(msg[TRK+1] << 8) + msg[TRK];
+       sec  = (uint16_t)(msg[SEC+1] << 8) + msg[SEC];
+       secs = msg[CNT];
+       addr = ((uint32_t)msg[ADDR+2] << 16) + ((uint16_t)msg[ADDR+1] << 8) + msg[ADDR];
+
+       if (dp->img_name == NULL) {
+               /* no media */
+               return msg_cpm_result(subf, 0x06, res);
+       }
+
+       /* TODO: tracks per sector from dpb */
+       pos = (track * 8UL + sec) * CONFIG_CPM_BLOCK_SIZE;
+
+       drv_debug(MIDDLE, PSTR(" T:%4d, S:%2d, cnt:%2d, lba: %.8lx, addr: %.5lx"),
+                               track, sec, secs, pos, addr);
+
+       if (addr == 0) {
+               return msg_cpm_result(subf, 0x07, res);
+       }
+
+       if (dowrite && dp->opt & DRV_OPT_RO) {
+               return msg_cpm_result(subf, 0x05, res);
+       }
+
+
+       if (pos + secs * CONFIG_CPM_BLOCK_SIZE > CONFIG_CPM_DISKSIZE) {
+               drv_debug(MIDDLE, PSTR(" access > DISKSIZE:%.8lx!"),
+                                               CONFIG_CPM_DISKSIZE);
+               return msg_cpm_result(subf, 0x04, res);
+       }
+
+       res = f_lseek(&dp->fd, pos);
+
+       while (!res && secs--) {
+               unsigned int brw;
+               if (dowrite) {
+                       if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                               buserr = 1;
+                               break;
+                       } else {
+                               z80_read_block(disk_buffer, addr, CONFIG_CPM_BLOCK_SIZE);
+                               z80_bus_cmd(Release);
+                       }
+                       res = f_write(&dp->fd, disk_buffer, CONFIG_CPM_BLOCK_SIZE, &brw);
+               } else {
+                       res = f_read(&dp->fd, disk_buffer, CONFIG_CPM_BLOCK_SIZE, &brw);
+                       if (res == FR_OK) {
+                               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
+                                       buserr = 1;
+                                       break;
+                               } else {
+                                       z80_write_block(disk_buffer, addr, CONFIG_CPM_BLOCK_SIZE);
+                                       z80_bus_cmd(Release);
+                               }
+                       }
+               }
+               if (brw != CONFIG_CPM_BLOCK_SIZE) {
+                       drv_debug(MIDDLE, PSTR(" short rd/wr: res: %d, brw: %u"),
+                                               res, brw);
+                       res = 64;
+               }
+               addr += CONFIG_CPM_BLOCK_SIZE;
+       }
+
+       if (dowrite && !res) {
+               dp->flags |= DRV_FLG_DIRTY;
+               bg_setstat(handle_cpm_drv_to, 1);
+       }
+
+       if (buserr) {
+               /* Bus timeout. how can this happen? */
+               rc = 0x03;
+       }
+
+       /* send  result*/
+       msg_cpm_result(subf, rc, res);
+}
+
+
+const FLASH struct msg_item z80_messages[] =
+{
+       { 0,                    /* fct nr. */
+         1, 3,                 /* sub fct nr. from, to */
+         do_msg_ini_memfifo},
+       { 1,
+         1, 1,
+         do_msg_char_out},
+       { 1,
+         2, 2,
+         do_msg_echo},
+       { 2,
+         0, 0,
+         do_msg_cpm_login},
+       { 2,
+         1, 2,
+         do_msg_cpm_rw},
+       { 3,
+         1, 1,
+         do_msg_get_timer},
+       { 3,
+         2, 3,                         /* 2: get, 3: set time and date */
+         do_msg_get_set_time},
+       { 0xff,                         /* end mark */
+         0, 0,
+         0},
+
+};
+
+
+
+
+void do_message(int len, uint8_t *msg)
+{
+       uint8_t fct, sub_fct;
+       int_fast8_t i = 0;
+
+       if (len >= 2) {
+               fct = *msg++;
+               sub_fct = *msg++;
+               len -= 2;
+
+               while (fct != z80_messages[i].fct) {
+                       if (z80_messages[i].fct == 0xff) {
+                               DBG_P(1, "do_message: Unknown function: %i, %i\n",
+                                               fct, sub_fct);
+                               return; /* TODO: unknown message # */
+                       }
+
+                       ++i;
+               }
+
+               while (fct == z80_messages[i].fct) {
+                       if (sub_fct >= z80_messages[i].sub_min &&
+                                       sub_fct <= z80_messages[i].sub_max )
+                               break;
+                       ++i;
+               }
+
+               if (z80_messages[i].fct != fct) {
+                       DBG_P(1, "do_message: Unknown sub function: %i, %i\n",
+                                       fct, sub_fct);
+                       return; /* TODO: unknown message sub# */
+               }
+
+               (z80_messages[i].func)(sub_fct, len, msg);
+
+
+       } else {
+               /* TODO: error */
+               DBG_P(1, "do_message: to few arguments (%i); this shouldn't happen!\n", len);
+       }
+}
+
+
+
+#define CTRBUF_LEN 256
+
+void check_msg_fifo(void)
+{
+       int ch;
+       static int_fast8_t state;
+       static int msglen,idx;
+       static uint8_t buffer[CTRBUF_LEN];
+
+       while ((ch = z80_memfifo_getc(fifo_msgin)) >= 0) {
+               switch (state) {
+               case 0:         /* wait for start of message */
+                       if (ch == 0xAE) { /* TODO: magic number */
+                               msglen = 0;
+                               idx = 0;
+                               state = 1;
+                       }
+                       break;
+               case 1:         /* get msg len */
+                       if (ch > 0 && ch <= CTRBUF_LEN) {
+                               msglen = ch;
+                               state = 2;
+                       } else
+                               state = 0;
+                       break;
+               case 2:         /* get message */
+                       buffer[idx++] = ch;
+                       if (idx == msglen) {
+                               do_message(msglen, buffer);
+                               state = 0;
+                       }
+                       break;
+               }
+       }
+}
+
+
+int msg_handling(int state)
+{
+       bool pending;
+
+       ATOMIC_BLOCK(ATOMIC_FORCEON) {
+               pending = (Stat & S_MSG_PENDING) != 0;
+               Stat &= ~S_MSG_PENDING;
+       }
+
+       if (pending) {
+               uint8_t init_request;
+               z80_bus_cmd(Request);
+               init_request = z80_read(0x43);
+               z80_bus_cmd(Release);
+               if ( init_request != 0) {
+                       /* Get address of fifo 0 */
+                       z80_bus_cmd(Request);
+                       uint32_t fifo_addr = z80_read(0x40) +
+                                               ((uint16_t) z80_read(0x40+1) << 8) +
+                                               ((uint32_t) z80_read(0x40+2) << 16);
+                       z80_write(0x43, 0);
+                       z80_bus_cmd(Release);
+
+                       if (fifo_addr != 0) {
+                               z80_memfifo_init(fifo_msgin, fifo_addr);
+                               state = 1;
+                       } else
+                               state = 0;
+
+               } else {
+                       check_msg_fifo();
+               }
+       }
+
+       return state;
+}
+
+
+static int handle_msg_handling;
+
+void setup_z180_serv(void)
+{
+
+       handle_msg_handling = bg_register(msg_handling, 0);
+       handle_cpm_drv_to = bg_register(cpm_drv_to, 0);
+}
+
+void restart_z180_serv(void)
+{
+       z80_bus_cmd(Request);
+       z80_memset(0x40, 0, 4);
+       z80_bus_cmd(Release);
+
+       for (int i = 0; i < NUM_FIFOS; i++)
+               z80_memfifo_init(i, 0);
+       bg_setstat(handle_msg_handling, 0);
+
+}
+
+#if 0
+/*--------------------------------------------------------------------------*/
+
+const FLASH uint8_t iniprog[] = {
+       0xAF,                   // xor     a
+       0xED, 0x39, 0x36,       // out0    (rcr),a         ;disable  DRAM refresh
+       0x3E, 0x30,             // ld      a,030h
+       0xED, 0x39, 0x32        //out0    (dcntl),a       ;0 mem, max i/0 wait states
+};
+
+const FLASH uint8_t sertest[] = {
+       0xAF,              //   xor     a
+       0xED, 0x39, 0x36,  //   out0    (rcr),a         ;disable  DRAM refresh
+       0x3E, 0x30,        //   ld      a,030h
+       0xED, 0x39, 0x32,  //   out0    (dcntl),a       ;0 mem, max i/0 wait states
+       0x3E, 0x80,        //   ld      a,M_MPBT                ;no MP, PS=10, DR=16, SS=0
+       0xED, 0x39, 0x03,  //   out0    (cntlb1),a
+       0x3E, 0x64,        //   ld      a,M_RE + M_TE + M_MOD2  ;
+       0xED, 0x39, 0x01,  //   out0    (cntla1),a
+       0x3E, 0x00,        //   ld      a,0
+       0xED, 0x39, 0x05,  //   out0    (stat1),a       ;Enable rx interrupts
+       0xED, 0x38, 0x05,  //l0:in0     a,(stat1)
+       0xE6, 0x80,        //   and     80h
+       0x28, 0xF9,        //   jr      z,l0
+       0xED, 0x00, 0x09,  //   in0     b,(rdr1)
+       0xED, 0x38, 0x05,  //l1:in0     a,(stat1)
+       0xE6, 0x02,        //   and     02h
+       0x28, 0xF9,        //   jr      z,l1
+       0xED, 0x01, 0x07,  //   out0    (tdr1),b
+       0x18, 0xEA,        //   jr      l0
+};
+
+const FLASH uint8_t test1[] = {
+       0xAF,              //   xor     a
+       0xED, 0x39, 0x36,  //   out0    (rcr),a         ;disable  DRAM refresh
+       0x3E, 0x30,        //   ld      a,030h
+       0xED, 0x39, 0x32,  //   out0    (dcntl),a       ;0 mem, max i/0 wait states
+       0x21, 0x1E, 0x00,  //   ld      hl,dmclrt       ;load DMA registers
+       0x06, 0x08,        //   ld      b,dmct_e-dmclrt
+       0x0E, 0x20,        //   ld      c,sar0l
+       0xED, 0x93,        //   otimr
+       0x3E, 0xC3,        //   ld      a,0c3h          ;dst +1, src +1, burst
+       0xED, 0x39, 0x31,  //   out0    (dmode),a       ;
+       0x3E, 0x62,        //   ld      a,062h          ;enable dma0,
+       0xED, 0x39, 0x30,  //cl_1:      out0    (dstat),a       ;copy 64k
+       0x18, 0xFB,        //   jr      cl_1            ;
+       0x00, 0x00,        //dmclrt:    dw      0               ;src (inc)
+       0x00,              //   db      0               ;src
+       0x00, 0x00,        //   dw      0               ;dst (inc),
+       0x00,              //   db      0               ;dst
+       0x00, 0x00,        //   dw      0               ;count (64k)
+};
+#endif
diff --git a/avr/z80-if.c b/avr/z80-if.c
new file mode 100644 (file)
index 0000000..e36b369
--- /dev/null
@@ -0,0 +1,699 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+/**
+ *
+ * Pin assignments
+ *
+ * | Z180-Sig   |   AVR-Port    | Dir   |
+ * +------------+---------------+-------+
+ * |    A0      | PA    0       |  O    |
+ * |    A1      | PA    1       |  O    |
+ * |    A2      | PA    2       |  O    |
+ * |    A3      | PA    3       |  O    |
+ * |    A4      | PA    4       |  O    |
+ * |    A5      | PA    5       |  O    |
+ * |    A6      | PA    6       |  O    |
+ * |    A7      | PA    7       |  O    |
+ * |    A8      | PC    0       |  O    |
+ * |    A9      | PC    1       |  O    |
+ * |    A10     | PC    2       |  O    |
+ * |    A11     | PC    3       |  O    |
+ * |    A12     | PC    4       |  O    |
+ * |    A13     | PC    5       |  O    |
+ * |    A14     | PC    6       |  O    |
+ * |    A15     | PC    7       |  O    |
+ * |    A16     | PE    2       |  O    |
+ * |    A17     | PE    3       |  O    |
+ * |    A18     | PE    4       |  O    |
+ * |    D0      | PF    0       |  I/O  |
+ * |    D1      | PF    1       |  I/O  |
+ * |    D2      | PF    2       |  I/O  |
+ * |    D3      | PF    3       |  I/O  |
+ * |    D4      | PF    4       |  I/O  |
+ * |    D5      | PF    5       |  I/O  |
+ * |    D6      | PF    6       |  I/O  |
+ * |    D7      | PF    7       |  I/O  |
+ * |    RD      | PD    3       |  O    |
+ * |    WR      | PD    2       |  O    |
+ * |    MREQ    | PD    4       |  O    |
+ * |    RST     | PD    5       |  O    |
+ * |    BUSREQ  | PD    7       |  O    |
+ * |    BUSACK  | PD    6       |  I    |
+ * |
+ * | Optional
+ * +------------------------------------+
+ * |    STEP    | PG    0       |  O    |
+ * |    RUN     | PG    1       |  O    |
+ * |    WAIT    | PG    2       |  I    |
+
+ */
+
+
+#include "z80-if.h"
+#include <util/atomic.h>
+#include "debug.h"
+#include "config.h"
+#include "env.h"
+
+
+//#define P_ZCLK               PORTB
+//#define ZCLK         5
+//#define DDR_ZCLK     DDRB
+#define P_MREQ         PORTD
+#define MREQ           4
+#define DDR_MREQ       DDRD
+#define P_RD           PORTD
+#define RD             3
+#define P_WR           PORTD
+#define WR             2
+#define P_BUSREQ       PORTD
+#define BUSREQ         7
+#define DDR_BUSREQ     DDRD
+#define P_BUSACK       PORTD
+#define PIN_BUSACK     PIND
+#define BUSACK         6
+#define DDR_BUSACK     DDRD
+#define P_RST          PORTD
+#define PIN_RST                PIND
+#define DDR_RST                DDRD
+#define RST            5
+
+
+#define P_DB           PORTF
+#define PIN_DB         PINF
+#define DDR_DB         DDRF
+
+#define P_ADL          PORTA
+#define P_ADH          PORTC
+#define P_ADB          PORTE
+#define PIN_ADB                PINE
+#define DDR_ADL                DDRA
+#define DDR_ADH                DDRC
+#define DDR_ADB                DDRE
+
+#define ADB_WIDTH      3
+#define ADB_SHIFT      2
+//#define ADB_PORT     PORTE
+
+
+//#define Z80_O_ZCLK   SBIT(P_ZCLK, 5)
+#define        Z80_O_MREQ      SBIT(P_MREQ, 4)
+#define Z80_O_RD       SBIT(P_RD, 3)
+#define Z80_O_WR       SBIT(P_WR, 2)
+#define Z80_O_BUSREQ   SBIT(P_BUSREQ, 7)
+//#define Z80_O_NMI    SBIT(P_NMI, )
+#define Z80_O_RST      SBIT(P_RST, 5)
+#define Z80_I_RST      SBIT(PIN_RST, 5)
+#define Z80_I_BUSACK   SBIT(PIN_BUSACK, 6)
+//#define Z80_I_HALT   SBIT(P_HALT, )
+
+/* Optional */
+#define P_RUN          PORTG
+#define RUN                    1
+#define DDR_RUN                DDRG
+#define P_STEP         PORTG
+#define STEP           0
+#define DDR_STEP       DDRG
+#define P_WAIT         PORTG
+#define WAIT           2
+#define DDR_WAIT       DDRG
+/* All three signals are on the same Port (PortG) */
+#define PORT_SS                PORTG
+#define DDR_SS         DDRG
+#define PIN_SS         PING
+#define        Z80_O_RUN       SBIT(PORT_SS, RUN)
+#define        Z80_O_STEP      SBIT(PORT_SS, STEP)
+#define        Z80_I_WAIT      SBIT(PORT_SS, WAIT)
+
+
+#define BUS_TO 20
+
+
+#define MASK(n)        ((1<<(n))-1)
+#define SMASK(w,s) (MASK(w) << (s))
+
+
+static zstate_t zstate;
+static volatile uint8_t timer;         /* used for bus timeout */
+static bool reset_polarity;
+
+/*---------------------------------------------------------*/
+/* 10Hz timer interrupt generated by OC4A                  */
+/*---------------------------------------------------------*/
+
+ISR(TIMER5_COMPA_vect)
+{
+
+       uint8_t i = timer;
+
+       if (i)
+               timer = i - 1;
+}
+
+/*--------------------------------------------------------------------------*/
+
+
+static void z80_addrbus_set_in(void)
+{
+       /* /MREQ, /RD, /WR: Input, no pullup */
+       DDR_MREQ &= ~(_BV(MREQ) | _BV(RD) | _BV(WR));
+       Z80_O_MREQ = 0;
+       Z80_O_RD = 0;
+       Z80_O_WR = 0;
+
+       P_ADL = 0;
+       DDR_ADL = 0;
+       P_ADH = 0;
+       DDR_ADH = 0;
+       PIN_ADB = P_ADB & (MASK(ADB_WIDTH) << ADB_SHIFT);
+       DDR_ADB = DDR_ADB & ~(MASK(ADB_WIDTH) << ADB_SHIFT);
+}
+
+
+static void z80_addrbus_set_out(void)
+{
+       /* /MREQ, /RD, /WR: Output and high */
+       Z80_O_MREQ = 1;
+       Z80_O_RD = 1;
+       Z80_O_WR = 1;
+       DDR_MREQ |= _BV(MREQ) | _BV(RD) | _BV(WR);
+
+       DDR_ADL = 0xff;
+       DDR_ADH = 0xff;
+       DDR_ADB = DDR_ADB | (MASK(ADB_WIDTH) << ADB_SHIFT);
+}
+
+
+static void z80_dbus_set_in(void)
+{
+       DDR_DB = 0;
+       P_DB = 0;
+}
+
+
+static void z80_dbus_set_out(void)
+{
+       DDR_DB = 0xff;
+}
+
+static void z80_reset_active(void)
+{
+       if (reset_polarity)
+               Z80_O_RST = 1;
+       else
+               Z80_O_RST = 0;
+}
+
+static void z80_reset_inactive(void)
+{
+       if (reset_polarity)
+               Z80_O_RST = 0;
+       else
+               Z80_O_RST = 1;
+}
+
+static void z80_reset_pulse(void)
+{
+       z80_reset_active();
+       _delay_us(10);
+       z80_reset_inactive();
+}
+
+
+void z80_setup_bus(void)
+{
+       ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+
+               /* /ZRESET: Input, no pullup */
+               DDR_RST &= ~_BV(RST);
+               Z80_O_RST = 0;
+
+               /* /BUSREQ: Output and high */
+               Z80_O_BUSREQ = 1;
+               DDR_BUSREQ |= _BV(BUSREQ);
+
+               /* /BUSACK: Input, no pullup */
+               DDR_BUSACK &= ~_BV(BUSACK);
+               P_BUSACK &= ~_BV(BUSACK);
+
+               z80_addrbus_set_in();
+               z80_dbus_set_in();
+
+               if (getenv_yesno(PSTR(ENV_SINGLESTEP))) {
+                       /* /RUN & /STEP: output, /WAIT: input */
+
+                       PORT_SS = (PORT_SS & ~_BV(RUN)) | _BV(STEP);
+                       DDR_SS = (DDR_SS & ~_BV(WAIT)) | _BV(RUN) | _BV(STEP);
+               }
+
+               reset_polarity = Z80_I_RST;
+               z80_reset_active();
+               DDR_RST |= _BV(RST);
+
+               zstate = RESET;
+       }
+
+       /* Timer 5 */
+       PRR1 &= ~_BV(PRTIM5);
+       OCR5A = F_CPU / 1024 / 10 - 1;            /* Timer: 10Hz interval (OC4A) */
+       TCCR5B = (0b01<<WGM52)|(0b101<<CS40); /* CTC Mode, Prescaler 1024 */
+       TIMSK5 = _BV(OCIE5A);                             /* Enable oca interrupt */
+
+}
+
+
+zstate_t z80_bus_state(void)
+{
+       return zstate;
+}
+
+
+static void z80_busreq_hpulse(void)
+{
+       z80_dbus_set_in();
+       z80_addrbus_set_in();
+
+#if 0
+       ATOMIC_BLOCK(ATOMIC_FORCEON) {
+               Z80_O_BUSREQ = 1;
+               Z80_O_BUSREQ = 1;       /* 2 AVR clock cycles */
+               Z80_O_BUSREQ = 0;       /* 2 AVR clock cycles */
+       }
+#endif
+
+#if 1
+       ATOMIC_BLOCK(ATOMIC_FORCEON) {
+               Z80_O_BUSREQ = 1;
+
+               do {
+                       if (Z80_I_BUSACK == 1)  {
+                               Z80_O_BUSREQ = 0;
+                               break;
+                       }
+               } while (1);
+       }
+#endif
+
+       if (zstate & ZST_ACQUIRED) {
+               timer = BUS_TO;
+               while (Z80_I_BUSACK == 1 && timer)
+                       ;
+               if (Z80_I_BUSACK == 0)
+                       z80_addrbus_set_out();
+       }
+}
+
+
+/*
+
+ +              |               |               |               |               |
+    +   State   |     RESET     |  RESET_AQRD   |    RUNNING    | RUNNING_AQRD  |
+       +        |               |               |               |               |
+          +     |       0       |       1       |       2       |       3       |
+Event        +  |               |               |               |               |
+----------------+---------------+---------------+---------------+---------------+
+                |               |               |               |               |
+Reset           |       0       |       0       |       0       |       0       |
+                |               |               |               |               |
+                |               |               |               |               |
+Request         |       1       |               |       3       |               |
+                |               |               |               |               |
+                |               |               |               |               |
+Release         |               |       0       |               |       2       |
+                |               |               |               |               |
+                |               |               |               |               |
+Run             |       2       |       3       |               |               |
+                |               |               |               |               |
+                |               |               |               |               |
+Restart         |               |               |       2       |       3       |
+                |               |               |               |               |
+                |               |               |               |               |
+M_Cycle         |               |               |               |       3       |
+                |               |               |               |               |
+                |               |               |               |               |
+*/
+
+zstate_t z80_bus_cmd(bus_cmd_t cmd)
+{
+       switch (cmd) {
+
+       case Reset:
+               z80_dbus_set_in();
+               z80_addrbus_set_in();
+               z80_reset_active();
+               Z80_O_BUSREQ = 1;
+               zstate = RESET;
+               break;
+
+       case Request:
+               switch (zstate) {
+               case RESET:
+                       Z80_O_BUSREQ = 0;
+                       z80_reset_inactive();
+                       timer = BUS_TO;
+                       while (Z80_I_BUSACK == 1 && timer)
+                               ;
+                       if (Z80_I_BUSACK == 0) {
+                               z80_addrbus_set_out();
+                               zstate = RESET_AQRD;
+                       } else {
+                               z80_reset_active();
+                               Z80_O_BUSREQ = 1;
+                       }
+                       break;
+
+               case RUNNING:
+                       Z80_O_BUSREQ = 0;
+                       timer = BUS_TO;
+                       while (Z80_I_BUSACK == 1 && timer)
+                               ;
+                       if (Z80_I_BUSACK == 0) {
+                               z80_addrbus_set_out();
+                               zstate = RUNNING_AQRD;
+                       } else {
+                               Z80_O_BUSREQ = 1;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+
+       case Release:
+               switch (zstate) {
+               case RESET_AQRD:
+                       z80_dbus_set_in();
+                       z80_addrbus_set_in();
+                       z80_reset_active();
+                       Z80_O_BUSREQ = 1;
+                       zstate = RESET;
+                       break;
+               case RUNNING_AQRD:
+                       z80_dbus_set_in();
+                       z80_addrbus_set_in();
+                       Z80_O_BUSREQ = 1;
+                       zstate = RUNNING;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case Run:
+               switch (zstate) {
+               case RESET:
+                       z80_reset_inactive();
+                       zstate = RUNNING;
+                       break;
+
+               case RESET_AQRD:
+                       z80_dbus_set_in();
+                       z80_addrbus_set_in();
+                       z80_reset_pulse();
+                       z80_addrbus_set_out();
+                       zstate = RUNNING_AQRD;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case Restart:
+               switch (zstate) {
+               case RUNNING:
+               case RUNNING_AQRD:
+                       z80_reset_pulse();
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case M_Cycle:
+               switch (zstate) {
+               case RUNNING_AQRD:
+                       z80_busreq_hpulse();    /* TODO: */
+                       break;
+               default:
+                       break;
+               }
+       }
+       return zstate;
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+static
+//inline __attribute__ ((always_inline))
+void z80_setaddress(uint32_t addr)
+{
+       P_ADL = addr;
+       P_ADH = (addr & 0xff00) >> 8;
+       PIN_ADB = (((addr >> 16) << ADB_SHIFT) ^ P_ADB) & MASK(ADB_WIDTH) << ADB_SHIFT;
+}
+
+void z80_write(uint32_t addr, uint8_t data)
+{
+       z80_setaddress(addr);
+       Z80_O_MREQ = 0;
+       z80_dbus_set_out();
+       P_DB = data;
+       P_DB = data;
+       Z80_O_WR = 0;
+       Z80_O_WR = 0;
+       Z80_O_WR = 1;
+       Z80_O_MREQ = 1;
+}
+
+uint8_t z80_read(uint32_t addr)
+{
+       uint8_t data;
+
+       z80_setaddress(addr);
+       Z80_O_MREQ = 0;
+       z80_dbus_set_in();
+       Z80_O_RD = 0;
+       Z80_O_RD = 0;
+       Z80_O_RD = 0;
+       data = PIN_DB;
+       Z80_O_RD = 1;
+       Z80_O_MREQ = 1;
+
+       return data;
+}
+
+
+void z80_memset(uint32_t addr, uint8_t data, uint32_t length)
+{
+       z80_dbus_set_out();
+       Z80_O_MREQ = 0;
+       P_DB = data;
+       while(length--) {
+               z80_setaddress(addr++);
+               Z80_O_WR = 0;
+               Z80_O_WR = 0;
+               Z80_O_WR = 1;
+       }
+       Z80_O_MREQ = 1;
+}
+
+void z80_write_block_P(const FLASH uint8_t *src, uint32_t dest, uint32_t length)
+{
+       uint8_t data;
+
+       z80_dbus_set_out();
+       Z80_O_MREQ = 0;
+       while(length--) {
+               z80_setaddress(dest++);
+               data = *src++;
+               P_DB = data;
+               P_DB = data;
+               Z80_O_WR = 0;
+               Z80_O_WR = 0;
+               Z80_O_WR = 1;
+       }
+       Z80_O_MREQ = 1;
+}
+
+void z80_write_block(const uint8_t *src, uint32_t dest, uint32_t length)
+{
+       uint8_t data;
+
+       z80_dbus_set_out();
+       Z80_O_MREQ = 0;
+       while(length--) {
+               z80_setaddress(dest++);
+               data = *src++;
+               P_DB = data;
+               P_DB = data;
+               Z80_O_WR = 0;
+               Z80_O_WR = 0;
+               Z80_O_WR = 1;
+       }
+       Z80_O_MREQ = 1;
+}
+
+void z80_read_block (uint8_t *dest, uint32_t src, size_t length)
+{
+       uint8_t data;
+
+       Z80_O_MREQ = 0;
+       z80_dbus_set_in();
+       while(length--) {
+               z80_setaddress(src++);
+               Z80_O_RD = 0;
+               Z80_O_RD = 0;
+               Z80_O_RD = 0;
+               data = PIN_DB;
+               Z80_O_RD = 1;
+               *dest++ = data;
+       }
+       Z80_O_MREQ = 1;
+}
+
+
+/*
+  0179'                         rx.bs_mask:    ds      1               ; (buf_len - 1)
+  017A'                         rx.in_idx:     ds      1               ;
+  017B'                         rx.out_idx:    ds      1               ;
+  017C'                         rx.buf:                ds      rx.buf_len      ;
+  018B'                         rx.buf_end     equ     $-1             ; last byte (start+len-1)
+
+  018C'                         tx.bs_mask:    ds      1               ; (buf_len - 1)
+  018D'                         tx.in_idx:     ds      1               ;
+  018E'                         tx.out_idx:    ds      1               ;
+  018F'                         tx.buf:                ds      tx.buf_len      ;
+  019E'                         tx.buf_end     equ     $-1             ; last byte
+*/
+
+
+typedef struct __attribute__((packed)) {
+       uint8_t mask;
+       uint8_t in_idx;
+       uint8_t out_idx;
+       uint8_t buf[];
+} zfifo_t;
+
+
+
+#define FIFO_BUFSIZE_MASK      -3
+#define FIFO_INDEX_IN          -2
+#define FIFO_INDEX_OUT         -1
+
+
+static struct {
+       uint32_t base;
+       uint8_t idx_out,
+               idx_in,
+               mask;
+       } fifo_dsc[NUM_FIFOS];
+
+
+void z80_memfifo_init(const fifo_t f, uint32_t addr)
+{
+       fifo_dsc[f].base = addr;
+
+
+       if (addr != 0) {
+               z80_bus_cmd(Request);
+               fifo_dsc[f].mask = z80_read(addr + FIFO_BUFSIZE_MASK);
+               fifo_dsc[f].idx_in = z80_read(addr + FIFO_INDEX_IN);
+               fifo_dsc[f].idx_out = z80_read(addr + FIFO_INDEX_OUT);
+               z80_bus_cmd(Release);
+
+               if (fifo_dsc[f].idx_in != 0 || fifo_dsc[f].idx_out != 0) {
+                       DBG_P(1, "## z80_memfifo_init: %i, %lx, in: %.2x, out: %.2x, mask: %.2x\n",
+                                       f, addr, fifo_dsc[f].idx_in, fifo_dsc[f].idx_out, fifo_dsc[f].mask);
+               }
+       }
+}
+
+
+int z80_memfifo_is_empty(const fifo_t f)
+{
+       int rc = 1;
+
+       if (fifo_dsc[f].base != 0) {
+
+               uint32_t adr = fifo_dsc[f].base + FIFO_INDEX_IN;
+               uint8_t idx;
+
+               z80_bus_cmd(Request);
+               idx = z80_read(adr);
+               z80_bus_cmd(Release);
+               rc = idx == fifo_dsc[f].idx_out;
+       }
+
+       return rc;
+}
+
+int z80_memfifo_is_full(const fifo_t f)
+{
+       int rc = 0;
+
+       if (fifo_dsc[f].base != 0) {
+               z80_bus_cmd(Request);
+               rc = ((fifo_dsc[f].idx_in + 1) & fifo_dsc[f].mask)
+                       == z80_read(fifo_dsc[f].base+FIFO_INDEX_OUT);
+               z80_bus_cmd(Release);
+       }
+       return rc;
+}
+
+
+uint8_t z80_memfifo_getc_wait(const fifo_t f)
+{
+       uint8_t rc, idx;
+
+       while (z80_memfifo_is_empty(f))
+               ;
+
+       z80_bus_cmd(Request);
+       idx = fifo_dsc[f].idx_out;
+       rc = z80_read(fifo_dsc[f].base+idx);
+       fifo_dsc[f].idx_out = ++idx & fifo_dsc[f].mask;
+       z80_write(fifo_dsc[f].base+FIFO_INDEX_OUT, fifo_dsc[f].idx_out);
+       z80_bus_cmd(Release);
+
+       return rc;
+}
+
+int z80_memfifo_getc(const fifo_t f)
+{
+       int rc = -1;
+
+       if (fifo_dsc[f].base != 0) {
+               uint8_t idx = fifo_dsc[f].idx_out;
+               z80_bus_cmd(Request);
+               if (idx != z80_read(fifo_dsc[f].base + FIFO_INDEX_IN)) {
+                       rc = z80_read(fifo_dsc[f].base+idx);
+                       fifo_dsc[f].idx_out = ++idx & fifo_dsc[f].mask;
+                       z80_write(fifo_dsc[f].base+FIFO_INDEX_OUT, fifo_dsc[f].idx_out);
+               }
+               z80_bus_cmd(Release);
+       }
+
+       return rc;
+}
+
+
+void z80_memfifo_putc(fifo_t f, uint8_t val)
+{
+       int idx;
+
+       while (z80_memfifo_is_full(f))
+               ;
+
+       z80_bus_cmd(Request);
+       idx = fifo_dsc[f].idx_in;
+       z80_write(fifo_dsc[f].base+idx, val);
+       fifo_dsc[f].idx_in = ++idx & fifo_dsc[f].mask;
+       z80_write(fifo_dsc[f].base+FIFO_INDEX_IN, fifo_dsc[f].idx_in);
+       z80_bus_cmd(Release);
+}
diff --git a/configs/default.config b/configs/default.config
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/configs/gcc.tup b/configs/gcc.tup
new file mode 100644 (file)
index 0000000..ad2d788
--- /dev/null
@@ -0,0 +1,40 @@
+CC     = $(TOOLCHAIN)-gcc
+LD     = $(TOOLCHAIN)-gcc
+AR     = $(TOOLCHAIN)-ar
+AS     = $(TOOLCHAIN)-as
+OBJCOPY        = $(TOOLCHAIN)-objcopy
+OBJDUMP        = $(TOOLCHAIN)-objdump
+SIZE   = $(TOOLCHAIN)-size
+GDB    = $(TOOLCHAIN)-gdb
+
+
+CFLAGS += -g -Os
+CFLAGS += -std=gnu99
+CFLAGS += -Wall -Wextra
+CFLAGS += -Wredundant-decls 
+#CFLAGS        += -fno-common -ffunction-sections -fdata-sections
+
+
+LDFLAGS        += -Wl,--gc-sections
+LDFLAGS        += -Wl,--cref
+
+ifneq ($(LDSCRIPT),)
+LDFLAGS        += -T$(LDSCRIPT)
+endif
+
+
+!cc = |> ^ CC %f^ $(CC) $(CFLAGS) $(CPPFLAGS) -c %f -o %o |> %B.o
+!LINK = |> ^ LINK %o^ $(LD) $(CFLAGS) $(LDFLAGS) -Wl,-Map=%O.map %f $(LDLIBS) -o %o |> | %O.map
+!OBJCOPY= |> ^ OBJCOPY %o^ $(OBJCOPY) -Oihex %f %o |> 
+!OBJDUMP= |> ^ OBJDUMP %o^ $(OBJDUMP) -h -S %f > %o |> %O.lss
+!SIZE = |> ^ SIZE %f^ $(SIZE) %f |> 
+
+
+: foreach $(SRC) | $(PREDEP) |> !cc |>  {objs}
+: $(SRC_Z) |> !cc $(CPPFLAGS_Z) |> {objs}
+
+: {objs} |> !LINK |> $(PROG).elf {elf}
+: {elf}  |> !OBJCOPY |> %B.hex {aux}
+: {elf}  |> !OBJDUMP |> %B.lss {aux}
+: {elf}  | {aux} |> !SIZE |>
+
diff --git a/configs/m1281-debug.config b/configs/m1281-debug.config
new file mode 100644 (file)
index 0000000..db4eb98
--- /dev/null
@@ -0,0 +1,2 @@
+CONFIG_DEBUG=0
+CONFIG_MCU=atmega1281
diff --git a/configs/m2561-debug.config b/configs/m2561-debug.config
new file mode 100644 (file)
index 0000000..2366681
--- /dev/null
@@ -0,0 +1,2 @@
+CONFIG_DEBUG=0
+CONFIG_MCU=atmega2561
diff --git a/include/avr/ffconf.h b/include/avr/ffconf.h
new file mode 100644 (file)
index 0000000..51a3c23
--- /dev/null
@@ -0,0 +1,289 @@
+/*---------------------------------------------------------------------------/
+/  FatFs - Configuration file
+/---------------------------------------------------------------------------*/
+
+#define FFCONF_DEF 63463       /* Revision ID */
+
+/*---------------------------------------------------------------------------/
+/ Function Configurations
+/---------------------------------------------------------------------------*/
+
+#define FF_FS_READONLY 0
+/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
+/  Read-only configuration removes writing API functions, f_write(), f_sync(),
+/  f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
+/  and optional writing functions as well. */
+
+
+#define FF_FS_MINIMIZE 0
+/* This option defines minimization level to remove some basic API functions.
+/
+/   0: Basic functions are fully enabled.
+/   1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
+/      are removed.
+/   2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
+/   3: f_lseek() function is removed in addition to 2. */
+
+
+#define FF_USE_STRFUNC 2
+/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
+/
+/  0: Disable string functions.
+/  1: Enable without LF-CRLF conversion.
+/  2: Enable with LF-CRLF conversion. */
+
+
+#define FF_USE_FIND            0
+/* This option switches filtered directory read functions, f_findfirst() and
+/  f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
+
+
+#define FF_USE_MKFS            0
+/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
+
+
+#define FF_USE_FASTSEEK        0
+/* This option switches fast seek function. (0:Disable or 1:Enable) */
+
+
+#define FF_USE_EXPAND  0
+/* This option switches f_expand function. (0:Disable or 1:Enable) */
+
+
+#define FF_USE_CHMOD   0
+/* This option switches attribute manipulation functions, f_chmod() and f_utime().
+/  (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
+
+
+#define FF_USE_LABEL   0
+/* This option switches volume label functions, f_getlabel() and f_setlabel().
+/  (0:Disable or 1:Enable) */
+
+
+#define FF_USE_FORWARD 0
+/* This option switches f_forward() function. (0:Disable or 1:Enable) */
+
+
+/*---------------------------------------------------------------------------/
+/ Locale and Namespace Configurations
+/---------------------------------------------------------------------------*/
+
+#define FF_CODE_PAGE   850
+/* This option specifies the OEM code page to be used on the target system.
+/  Incorrect code page setting can cause a file open failure.
+/
+/   437 - U.S.
+/   720 - Arabic
+/   737 - Greek
+/   771 - KBL
+/   775 - Baltic
+/   850 - Latin 1
+/   852 - Latin 2
+/   855 - Cyrillic
+/   857 - Turkish
+/   860 - Portuguese
+/   861 - Icelandic
+/   862 - Hebrew
+/   863 - Canadian French
+/   864 - Arabic
+/   865 - Nordic
+/   866 - Russian
+/   869 - Greek 2
+/   932 - Japanese (DBCS)
+/   936 - Simplified Chinese (DBCS)
+/   949 - Korean (DBCS)
+/   950 - Traditional Chinese (DBCS)
+/     0 - Include all code pages above and configured by f_setcp()
+*/
+
+
+#define FF_USE_LFN             1
+#define FF_MAX_LFN             128
+/* The FF_USE_LFN switches the support for LFN (long file name).
+/
+/   0: Disable LFN. FF_MAX_LFN has no effect.
+/   1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
+/   2: Enable LFN with dynamic working buffer on the STACK.
+/   3: Enable LFN with dynamic working buffer on the HEAP.
+/
+/  To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
+/  requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
+/  additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
+/  The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
+/  be in range of 12 to 255. It is recommended to be set 255 to fully support LFN
+/  specification.
+/  When use stack for the working buffer, take care on stack overflow. When use heap
+/  memory for the working buffer, memory management functions, ff_memalloc() and
+/  ff_memfree() in ffsystem.c, need to be added to the project. */
+
+
+#define FF_LFN_UNICODE 0
+/* This option switches the character encoding on the API when LFN is enabled.
+/
+/   0: ANSI/OEM in current CP (TCHAR = char)
+/   1: Unicode in UTF-16 (TCHAR = WCHAR)
+/   2: Unicode in UTF-8 (TCHAR = char)
+/   3: Unicode in UTF-32 (TCHAR = DWORD)
+/
+/  Also behavior of string I/O functions will be affected by this option.
+/  When LFN is not enabled, this option has no effect. */
+
+
+#define FF_LFN_BUF             128
+#define FF_SFN_BUF             12
+/* This set of options defines size of file name members in the FILINFO structure
+/  which is used to read out directory items. These values should be suffcient for
+/  the file names to read. The maximum possible length of the read file name depends
+/  on character encoding. When LFN is not enabled, these options have no effect. */
+
+
+#define FF_STRF_ENCODE 3
+/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
+/  f_putc(), f_puts and f_printf() convert the character encoding in it.
+/  This option selects assumption of character encoding ON THE FILE to be
+/  read/written via those functions.
+/
+/   0: ANSI/OEM in current CP
+/   1: Unicode in UTF-16LE
+/   2: Unicode in UTF-16BE
+/   3: Unicode in UTF-8
+*/
+
+
+#define FF_FS_RPATH            2
+/* This option configures support for relative path.
+/
+/   0: Disable relative path and remove related functions.
+/   1: Enable relative path. f_chdir() and f_chdrive() are available.
+/   2: f_getcwd() function is available in addition to 1.
+*/
+
+
+/*---------------------------------------------------------------------------/
+/ Drive/Volume Configurations
+/---------------------------------------------------------------------------*/
+
+#define FF_VOLUMES             2
+/* Number of volumes (logical drives) to be used. (1-10) */
+
+
+#define FF_STR_VOLUME_ID       0
+#define FF_VOLUME_STRS         "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
+/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
+/  When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
+/  number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
+/  logical drives. Number of items must not be less than FF_VOLUMES. Valid
+/  characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
+/  compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
+/  not defined, a user defined volume string table needs to be defined as:
+/
+/  const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
+*/
+
+
+#define FF_MULTI_PARTITION     0
+/* This option switches support for multiple volumes on the physical drive.
+/  By default (0), each logical drive number is bound to the same physical drive
+/  number and only an FAT volume found on the physical drive will be mounted.
+/  When this function is enabled (1), each logical drive number can be bound to
+/  arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
+/  funciton will be available. */
+
+
+#define FF_MIN_SS              512
+#define FF_MAX_SS              512
+/* This set of options configures the range of sector size to be supported. (512,
+/  1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
+/  harddisk. But a larger value may be required for on-board flash memory and some
+/  type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
+/  for variable sector size mode and disk_ioctl() function needs to implement
+/  GET_SECTOR_SIZE command. */
+
+
+#define FF_USE_TRIM            0
+/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
+/  To enable Trim function, also CTRL_TRIM command should be implemented to the
+/  disk_ioctl() function. */
+
+
+#define FF_FS_NOFSINFO 0
+/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
+/  option, and f_getfree() function at first time after volume mount will force
+/  a full FAT scan. Bit 1 controls the use of last allocated cluster number.
+/
+/  bit0=0: Use free cluster count in the FSINFO if available.
+/  bit0=1: Do not trust free cluster count in the FSINFO.
+/  bit1=0: Use last allocated cluster number in the FSINFO if available.
+/  bit1=1: Do not trust last allocated cluster number in the FSINFO.
+*/
+
+
+
+/*---------------------------------------------------------------------------/
+/ System Configurations
+/---------------------------------------------------------------------------*/
+
+#define FF_FS_TINY             1
+/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
+/  At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
+/  Instead of private sector buffer eliminated from the file object, common sector
+/  buffer in the filesystem object (FATFS) is used for the file data transfer. */
+
+
+#define FF_FS_EXFAT            0
+/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
+/  To enable exFAT, also LFN needs to be enabled.
+/  Note that enabling exFAT discards ANSI C (C89) compatibility. */
+
+
+#define FF_FS_NORTC            0
+#define FF_NORTC_MON   1
+#define FF_NORTC_MDAY  1
+#define FF_NORTC_YEAR  2018
+/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
+/  any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
+/  the timestamp function. Every object modified by FatFs will have a fixed timestamp
+/  defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
+/  To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
+/  added to the project to read current time form real-time clock. FF_NORTC_MON,
+/  FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
+/  These options have no effect at read-only configuration (FF_FS_READONLY = 1). */
+
+
+#define FF_FS_LOCK             0
+/* The option FF_FS_LOCK switches file lock function to control duplicated file open
+/  and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
+/  is 1.
+/
+/  0:  Disable file lock function. To avoid volume corruption, application program
+/      should avoid illegal open, remove and rename to the open objects.
+/  >0: Enable file lock function. The value defines how many files/sub-directories
+/      can be opened simultaneously under file lock control. Note that the file
+/      lock control is independent of re-entrancy. */
+
+
+#define FF_FS_REENTRANT        0
+#define FF_FS_TIMEOUT  1000
+#define FF_SYNC_t              HANDLE
+/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
+/  module itself. Note that regardless of this option, file access to different
+/  volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
+/  and f_fdisk() function, are always not re-entrant. Only file/directory access
+/  to the same volume is under control of this function.
+/
+/   0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
+/   1: Enable re-entrancy. Also user provided synchronization handlers,
+/      ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
+/      function, must be added to the project. Samples are available in
+/      option/syscall.c.
+/
+/  The FF_FS_TIMEOUT defines timeout period in unit of time tick.
+/  The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
+/  SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
+/  included somewhere in the scope of ff.h. */
+
+/* #include <windows.h>        // O/S definitions  */
+
+
+
+/*--- End of configuration options ---*/
diff --git a/include/background.h b/include/background.h
new file mode 100644 (file)
index 0000000..87e95e5
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef BACKGROUND_H
+#define BACKGROUND_H
+
+typedef int (*bg_func)(int);
+
+int bg_register(bg_func f, int initval);
+int bg_setstat(int handle, int val);
+int bg_getstat(int handle);
+void bg_shed(void);
+
+#endif /* BACKGROUND_H */
diff --git a/include/bcd.h b/include/bcd.h
new file mode 100644 (file)
index 0000000..efbebcc
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef BCD_H
+#define BCD_H
+
+uint_fast8_t bcd2bin(uint8_t val);
+uint8_t bin2bcd (uint_fast8_t val);
+
+#endif /* BCD_H */
diff --git a/include/cli.h b/include/cli.h
new file mode 100644 (file)
index 0000000..28e92be
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2014 Google, Inc
+ * Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#ifndef CLI_H
+#define CLI_H
+
+/**
+ * Go into the command loop
+ *
+ * This will return if we get a timeout waiting for a command, but only for
+ * the simple parser (not hush). See CONFIG_BOOT_RETRY_TIME.
+ */
+void cli_loop(void);
+
+/**
+ * cli_simple_run_command() - Execute a command with the simple CLI
+ *
+ * @cmd:       String containing the command to execute
+ * @flag       Flag value - see CMD_FLAG_...
+ * @return 1  - command executed, repeatable
+ *     0  - command executed but not repeatable, interrupted commands are
+ *          always considered not repeatable
+ *     -1 - not executed (unrecognized, bootd recursion or too many args)
+ *           (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is
+ *           considered unrecognized)
+ */
+//int cli_simple_run_command(const char *cmd, int flag);
+
+/**
+ * cli_simple_run_command_list() - Execute a list of command
+ *
+ * The commands should be separated by ; or \n and will be executed
+ * by the built-in parser.
+ *
+ * This function cannot take a const char * for the command, since if it
+ * finds newlines in the string, it replaces them with \0.
+ *
+ * @param cmd  String containing list of commands
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+//int cli_simple_run_command_list(char *cmd, int flag);
+
+/**
+ * parse_line() - split a command line down into separate arguments
+ *
+ * The argv[] array is filled with pointers into @line, and each argument
+ * is terminated by \0 (i.e. @line is changed in the process unless there
+ * is only one argument).
+ *
+ * #argv is terminated by a NULL after the last argument pointer.
+ *
+ * At most CONFIG_SYS_MAXARGS arguments are permited - if there are more
+ * than that then an error is printed, and this function returns
+ * CONFIG_SYS_MAXARGS, with argv[] set up to that point.
+ *
+ * @line:      Command line to parse
+ * @args:      Array to hold arguments
+ * @return number of arguments
+ */
+//int cli_simple_parse_line(char *line, char *argv[]);
+
+/*
+ * Run a command.
+ *
+ * @param cmd  Command to run
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+int run_command(const char *cmd, int flag);
+
+int run_command_list(const char *cmd, int len);
+
+
+#endif /* CLI_H */
diff --git a/include/cli_readline.h b/include/cli_readline.h
new file mode 100644 (file)
index 0000000..f326106
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2014 Google, Inc
+ * Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#ifndef CLI_READLINE_H
+#define CLI_READLINE_H
+
+#include "common.h"
+#include <stdbool.h>
+
+extern char console_buffer[];  /* console I/O buffer   */
+
+/**
+ * cli_readline() - read a line into the console_buffer
+ *
+ * Display the prompt, then read a command line into console_buffer. The
+ * maximum line length is CONFIG_SYS_CBSIZE including a \0 terminator, which
+ * will always be added.
+ *
+ * The command is echoed as it is typed. Command editing is supported.
+ * Tab auto-complete is supported if CONFIG_AUTO_COMPLETE is defined.
+ *
+ * @prompt: Prompt to display
+ * @enable_history: Use history buffer if true
+ * @return command line length excluding terminator, or -ve on error
+ */
+int cli_readline(const FLASH char *const prompt, bool enable_history);
+
+#endif /* CLI_READLINE_H */
diff --git a/include/cmd_mem.h b/include/cmd_mem.h
new file mode 100644 (file)
index 0000000..782c10a
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef CMD_MEM_H
+#define CMD_MEM_H
+
+#include "command.h"
+#include "cmd_mem.h"
+
+
+extern command_ret_t do_mem_md(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_mem_mm(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_mem_nm(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_mem_mw(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_mem_cp(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_mem_cmp(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_mem_base(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_mem_loop(cmd_tbl_t *, int, int, char * const []);
+extern command_ret_t do_mem_loopw(cmd_tbl_t *, int, int, char * const []);
+#ifdef CONFIG_CMD_MEMTEST
+extern command_ret_t do_mem_mtest(cmd_tbl_t *, int, int, char * const []);
+#endif
+#ifdef CONFIG_MX_CYCLIC
+extern command_ret_t do_mem_mdc(cmd_tbl_t *, int, int, char * const []);
+#endif /* CONFIG_MX_CYCLIC */
+
+#endif /* CMD_MEM_H */
diff --git a/include/command.h b/include/command.h
new file mode 100644 (file)
index 0000000..9ca460d
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+/*
+ *  Definitions for Command Processor
+ */
+#ifndef __COMMAND_H
+#define __COMMAND_H
+
+#include "common.h"
+#include "config.h"
+#include <setjmp.h>
+
+#ifndef NULL
+#define NULL   0
+#endif
+
+/* Default to a width of 8 characters for help message command width */
+#ifndef CONFIG_SYS_HELP_CMD_WIDTH
+#define CONFIG_SYS_HELP_CMD_WIDTH      8
+#endif
+
+/*
+ * Error codes that commands return to cmd_process(). We use the standard 0
+ * and 1 for success and failure, but add one more case - failure with a
+ * request to call cmd_usage(). But the cmd_process() function handles
+ * CMD_RET_USAGE itself and after calling cmd_usage() it will return 1.
+ * This is just a convenience for commands to avoid them having to call
+ * cmd_usage() all over the place.
+ */
+typedef enum {
+       CMD_RET_SUCCESS = 0,    /* Success */
+       CMD_RET_FAILURE = 1,    /* Failure */
+       CMD_RET_USAGE = -1,     /* Failure, please report 'usage' error */
+} command_ret_t;
+
+/*
+ * Monitor Command Table
+ */
+
+struct cmd_tbl_s {
+       const FLASH char *name;         /* Command Name                 */
+       int             maxargs;                        /* maximum number of arguments  */
+       int             repeatable;                     /* autorepeat allowed?          */
+                                                               /* Implementation function      */
+       command_ret_t   (*cmd)(const FLASH struct cmd_tbl_s *, int, int, char * const []);
+       const FLASH char *usage;        /* Usage message        (short) */
+#ifdef CONFIG_SYS_LONGHELP
+       const FLASH char *help;         /* Help  message        (long)  */
+#endif
+#ifdef CONFIG_AUTO_COMPLETE
+       /* do auto completion on the arguments */
+       int             (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
+#endif
+};
+
+typedef const FLASH struct cmd_tbl_s cmd_tbl_t;
+
+/**
+ * Process a command with arguments. We look up the command and execute it
+ * if valid. Otherwise we print a usage message.
+ *
+ * @param flag         Some flags normally 0 (see CMD_FLAG_.. above)
+ * @param argc         Number of arguments (arg 0 must be the command text)
+ * @param argv         Arguments
+ * @param repeatable   This function sets this to 0 if the command is not
+ *                     repeatable. If the command is repeatable, the value
+ *                     is left unchanged.
+ * @return 0 if the command succeeded, 1 if it failed
+ */
+command_ret_t
+cmd_process(int flag, int argc, char * const argv[], uint_fast8_t *repeatable);
+
+
+/* command.c */
+command_ret_t _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int
+             flag, int argc, char * const argv[]);
+cmd_tbl_t *find_cmd(const char *cmd);
+cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len);
+
+int cmd_tbl_item_count(void);
+command_ret_t cmd_usage(cmd_tbl_t *cmdtp);
+
+#ifdef CONFIG_AUTO_COMPLETE
+extern int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
+extern int cmd_auto_complete(const FLASH char *const prompt, char *buf, int *np, int *colp);
+#endif
+
+/**
+ * cmd_process_error() - report and process a possible error
+ *
+ * @cmdtp: Command which caused the error
+ * @err: Error code (0 if none, -ve for error, like -EIO)
+ * @return 0 if there is not error, 1 (CMD_RET_FAILURE) if an error is found
+ */
+int cmd_process_error(cmd_tbl_t *cmdtp, int err);
+
+/*
+ * Monitor Command
+ *
+ * All commands use a common argument format:
+ *
+ * void function (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+ */
+
+
+#ifdef CONFIG_CMD_BOOTD
+extern command_ret_t do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+#endif
+#ifdef CONFIG_CMD_BOOTM
+extern command_ret_t do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+extern int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd);
+#else
+static inline int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd)
+{
+       (void) cmdtp; (void) cmd;
+
+       return 0;
+}
+#endif
+
+extern int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc,
+                          char *const argv[]);
+
+extern command_ret_t do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+/*
+ * Command Flags:
+ */
+#define CMD_FLAG_REPEAT                0x0001  /* repeat last command          */
+#define CMD_FLAG_BOOTD         0x0002  /* command is from bootd        */
+
+#ifdef CONFIG_AUTO_COMPLETE
+# define _CMD_COMPLETE(x) x,
+#else
+# define _CMD_COMPLETE(x)
+#endif
+#ifdef CONFIG_SYS_LONGHELP
+# define _CMD_HELP(x) x,
+#else
+# define _CMD_HELP(x)
+#endif
+
+
+#define CMD_TBL_ITEM_COMPLETE(_name, _maxargs, _rep, _cmd,             \
+                               _usage, _help, _comp)                   \
+               { FSTR(#_name), _maxargs, _rep, _cmd, FSTR(_usage),     \
+                       _CMD_HELP(FSTR(_help)) _CMD_COMPLETE(_comp) }
+
+#define CMD_TBL_ITEM(_name, _maxargs, _rep, _cmd, _usage, _help)       \
+       CMD_TBL_ITEM_COMPLETE(_name, _maxargs, _rep, _cmd,              \
+                                       _usage, _help, NULL)
+
+typedef command_ret_t (*do_cmd_t)(cmd_tbl_t *, int, int, char * const []);
+
+extern  cmd_tbl_t cmd_tbl[];
+
+extern jmp_buf cmd_jbuf;
+
+
+#endif /* __COMMAND_H */
diff --git a/include/common.h b/include/common.h
new file mode 100644 (file)
index 0000000..e22b7a1
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <stdio.h>
+#include <stdint.h>
+
+#define GCC_VERSION (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
+
+#ifdef __AVR__
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include <util/delay.h>
+
+#define udelay(n)  _delay_us(n)
+
+struct bits {
+  uint8_t b0:1;
+  uint8_t b1:1;
+  uint8_t b2:1;
+  uint8_t b3:1;
+  uint8_t b4:1;
+  uint8_t b5:1;
+  uint8_t b6:1;
+  uint8_t b7:1;
+} __attribute__((__packed__));
+
+#define SBIT(port,pin) ((*(volatile struct bits*)&port).b##pin)
+
+//GCC bug PR61443
+//  Known to work: 4.8.4, 4.9.1
+//  Known to fail: 4.8.3, 4.9.0
+
+#if (GCC_VERSION < 40804) || (GCC_VERSION == 40900)
+#define GCC_BUG_61443 1
+#endif /* PR61443 */
+
+#else
+// TODO: stm32
+#endif /* __AVR__ */
+
+#ifdef __FLASH
+#define FLASH __flash
+#define MEMX __memx
+#else
+#define FLASH
+#define MEMX
+#endif
+
+#define stringify(s)   tostring(s)
+#define tostring(s)    #s
+
+#define FSTR(X) ((const FLASH char[]) { X } )
+#define ARRAY_SIZE(x)  (sizeof(x) / sizeof((x)[0]))
+
+#define MIN(a,b)    ({ typeof (a) _a = (a);                                    \
+                                               typeof (b) _b = (b);                                   \
+                                               _a < _b ? _a : _b; })
+#define MAX(a,b)    ({ typeof (a) _a = (a);                                    \
+                                               typeof (b) _b = (b);                                   \
+                                               _a > _b ? _a : _b; })
+
+#ifdef __AVR__
+#define Stat GPIOR0
+#else
+extern volatile uint_least8_t Stat;
+#endif /* __AVR__ */
+
+#define S_10MS_TO              (1<<0)
+#define S_MSG_PENDING  (1<<1)
+#define S_CON_PENDING  (1<<2)
+
+static inline
+void my_puts(const char *s)
+{
+       fputs(s, stdout);
+}
+
+static inline
+void my_puts_P(const char *s)
+{
+#ifdef __AVR__
+       fputs_P(s, stdout);
+#else
+       fputs(s, stdout);
+#endif /* __AVR__ */
+}
+
+#endif /* COMMON_H */
diff --git a/include/con-utils.h b/include/con-utils.h
new file mode 100644 (file)
index 0000000..86c0df0
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * Console utilities
+ */
+
+#ifndef CON_UTILS_H
+#define CON_UTILS_H
+
+uint_fast8_t tstc(void);
+
+int my_getchar(uint_fast8_t waitforchar);
+
+/* test if ctrl-c was pressed */
+uint_fast8_t ctrlc(void);
+
+
+/* pass 1 to disable ctrlc() checking, 0 to enable.
+ * returns previous state
+ */
+uint_fast8_t disable_ctrlc(uint_fast8_t disable);
+
+uint_fast8_t had_ctrlc (void);
+void clear_ctrlc(void);
+
+#endif /* CON_UTILS_H */
diff --git a/include/config.h b/include/config.h
new file mode 100644 (file)
index 0000000..8d7f348
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* Version */
+#define VERSION                 "0.6.8.2"
+
+/* Environment variables */
+
+#define ENV_BAUDRATE                   "baudrate"
+#define ENV_BOOTDELAY                  "bootdelay"
+#define ENV_BOOTCMD                            "bootcmd"
+
+#define ENV_CPM3_SYSFILE               "cpm3_file"
+#define ENV_CPM3_COMMON_BASE   "cpm3_commonbase"
+#define ENV_CPM3_BANKED_BASE   "cpm3_bankedbase"
+#define ENV_CPM3_SCB                   "cpm3_scb"
+
+#define ENV_PINALIAS                   "pin_alias"
+#define ENV_STARTADDRESS               "startaddress"
+#define ENV_ESC_CHAR                   "esc_char"
+
+#define ENV_SINGLESTEP                 "singlestep"
+
+#define CONFIG_ENV_SIZE                        1600
+#define CONFIG_ENV_OFFSET              0
+#define CONFIG_ENVVAR_MAX              30
+
+#define CONFIG_BAUDRATE                        115200L
+#define CONFIG_PWRON_DELAY             2000    /* ms to wait after power on */
+#define CONFIG_BOOTDELAY               4
+//#define CONFIG_ZERO_BOOTDELAY_CHECK  1
+
+#define CONFIG_CPM3_SYSFILE                    "0:/cpm3.sys"
+#define CONFIG_CPM3_COMMON_BASE                0xF000
+#define CONFIG_CPM3_BANKED_BASE                0x0
+//#define CONFIG_CPM3_COMMON_BASE_STR  "F000"
+#define CONFIG_CPM3_BANKED_BASE_STR    "0"
+
+#define CONFIG_CPM_MAX_DRIVE   8
+#define CONFIG_CPM_BASE_DRIVE  'A'
+#define CONFIG_CPM_BLOCK_SIZE  512
+
+#define CONFIG_CMD_MEMTEST
+#define CONFIG_MX_CYCLIC
+#define CONFIG_SYS_RAMSIZE_MAX (1l<<19)        /* max. addressable memory */
+
+#define CONFIG_CMD_DATE 1
+
+
+//#define CONFIG_CMD_LOADB
+
+
+#define CONFIG_SYS_I2C_RTC_ADDR        0x50
+#define CONFIG_SYS_I2C_BUFSIZE 64
+#define CONFIG_SYS_I2C_CLOCK   100000L /* SCL clock frequency in Hz */
+
+#define CONFIG_SYS_CBSIZE      250
+#define CONFIG_SYS_HIST_MAX    20
+#define CONFIG_SYS_MAXARGS     20
+#define CONFIG_SYS_ENV_NAMELEN 16
+
+#define CONFIG_SYS_PROMPT                      "-> "
+#define CONFIG_SYS_PROMPT_REPEAT       "=> "
+#define CONFIG_ESC_CHAR                ('^'-0x40)
+
+#define CONFIG_SYS_FBOOTSIG "Peda"
+
+/* TODO: */
+//#define CONFIG_AUTO_COMPLETE 1
+
+#define CONFIG_SYS_LONGHELP    1
+
+#endif /* CONFIG_H */
diff --git a/include/crc.h b/include/crc.h
new file mode 100644 (file)
index 0000000..89cde1f
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef CRC_H
+#define CRC_H
+
+#ifdef __AVR__
+#include <util/crc16.h>
+static inline
+uint16_t crc16(uint16_t crc, uint8_t data)
+{
+       return _crc_ccitt_update(crc, data);
+}
+#else /* !__AVR__ */
+       /* TODO */
+#endif /* __AVR__ */
+
+#endif /* CRC_H */
diff --git a/include/debug.h b/include/debug.h
new file mode 100644 (file)
index 0000000..0ee0129
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * (C) Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+
+#ifndef DEBUG_H_
+#define DEBUG_H_
+
+#include "common.h"
+
+#ifdef DEBUG
+#define _DEBUG 1
+#else
+#define _DEBUG 0
+#endif
+
+/*
+ * Output a debug text when condition "cond" is met. The "cond" should be
+ * computed by a preprocessor in the best case, allowing for the best
+ * optimization.
+ */
+#define debug_cond(cond, fmt, args...)         \
+       do {                                    \
+               if (cond)                       \
+                       printf_P(PSTR(fmt), ##args);    \
+       } while (0)
+
+#define debug(fmt, args...)                    \
+       debug_cond(_DEBUG, fmt, ##args)
+
+
+#if 1
+#ifdef DEBUG
+#define DBG_P(lvl, format, ...) if (DEBUG>=lvl) \
+                               fprintf_P( stdout, PSTR(format), ##__VA_ARGS__ )
+#else
+#define DBG_P(lvl, ...)
+#endif
+#endif /* 0 */
+
+
+void printfreelist(const char * title);
+
+
+#endif /* DEBUG_H_ */
diff --git a/include/diskio.h b/include/diskio.h
new file mode 100644 (file)
index 0000000..fee87a5
--- /dev/null
@@ -0,0 +1,88 @@
+/*-----------------------------------------------------------------------
+/  Low level disk interface modlue include file  R0.07   (C)ChaN, 2009
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO_H
+#define _DISKIO_H
+
+#define _USE_WRITE     1       /* 1: Enable disk_write function */
+#define _USE_IOCTL     1       /* 1: Enable disk_ioctl fucntion */
+
+#include "integer.h"
+
+
+/* Status of Disk Functions */
+typedef BYTE   DSTATUS;
+
+/* Results of Disk Functions */
+typedef enum {
+       RES_OK = 0,             /* 0: Successful */
+       RES_ERROR,              /* 1: R/W Error */
+       RES_WRPRT,              /* 2: Write Protected */
+       RES_NOTRDY,             /* 3: Not Ready */
+       RES_PARERR              /* 4: Invalid Parameter */
+} DRESULT;
+
+
+/*---------------------------------------*/
+/* Prototypes for disk control functions */
+
+DSTATUS disk_initialize (BYTE drv);
+DSTATUS disk_status (BYTE drv);
+DRESULT disk_read (BYTE drv, BYTE* buff, DWORD sector, UINT count);
+#if    _USE_WRITE
+DRESULT disk_write (BYTE drv, const BYTE* buff, DWORD sector, UINT count);
+#endif
+#if    _USE_IOCTL
+DRESULT disk_ioctl (BYTE drv, BYTE cmd, void* buff);
+#endif
+void disk_timerproc (void);
+
+
+
+/* Disk Status Bits (DSTATUS) */
+
+#define STA_NOINIT             0x01    /* Drive not initialized */
+#define STA_NODISK             0x02    /* No medium in the drive */
+#define STA_PROTECT            0x04    /* Write protected */
+#define STA_FAST               0x08    /* Fast SPI clock */
+#define STAT_MASK              (STA_NOINIT | STA_NODISK | STA_PROTECT)
+
+
+/* Command code for disk_ioctrl() */
+
+/* Generic command (Used by FatFs) */
+#define CTRL_SYNC                      0       /* Complete pending write process (needed at _FS_READONLY == 0) */
+#define GET_SECTOR_COUNT       1       /* Get media size (needed at _USE_MKFS == 1) */
+#define GET_SECTOR_SIZE                2       /* Get sector size (needed at _MAX_SS != _MIN_SS) */
+#define GET_BLOCK_SIZE         3       /* Get erase block size (needed at _USE_MKFS == 1) */
+#define CTRL_TRIM                      4       /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
+
+/* Generic command (Not used by FatFs) */
+#define CTRL_FORMAT                    5       /* Create physical format on the media */
+#define CTRL_POWER_IDLE                6       /* Put the device idle state */
+#define CTRL_POWER_OFF         7       /* Put the device off state */
+#define CTRL_LOCK                      8       /* Lock media removal */
+#define CTRL_UNLOCK                    9       /* Unlock media removal */
+#define CTRL_EJECT                     10      /* Eject media */
+
+/* MMC/SDC specific command (Not used by FatFs) */
+#define MMC_GET_TYPE           50      /* Get card type */
+#define MMC_GET_CSD                    51      /* Get CSD */
+#define MMC_GET_CID                    52      /* Get CID */
+#define MMC_GET_OCR                    53      /* Get OCR */
+#define MMC_GET_SDSTAT         54      /* Get SD status */
+
+/* ATA/CF specific command (Not used by FatFs) */
+#define ATA_GET_REV                    60      /* Get F/W revision */
+#define ATA_GET_MODEL          61      /* Get model name */
+#define ATA_GET_SN                     62      /* Get serial number */
+
+/* MMC card type flags (MMC_GET_TYPE) */
+#define CT_MMC         0x01            /* MMC ver 3 */
+#define CT_SD1         0x02            /* SD ver 1 */
+#define CT_SD2         0x04            /* SD ver 2 */
+#define CT_SDC         (CT_SD1|CT_SD2) /* SD */
+#define CT_BLOCK       0x08            /* Block addressing */
+
+#endif /* _DISKIO_H */
diff --git a/include/env.h b/include/env.h
new file mode 100644 (file)
index 0000000..bc44413
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#ifndef ENV_H
+#define ENV_H
+
+#include <stdbool.h>
+
+int env_init(void);
+
+char *getenv_str(const MEMX char *name);
+unsigned long getenv_ulong(const MEMX char *name, int base, unsigned long default_val);
+bool getenv_yesno(const MEMX char *name);
+int setenv_ulong(const MEMX char *varname, unsigned long value);
+int setenv_hex(const MEMX char *varname, unsigned long value);
+
+#if defined(CONFIG_AUTO_COMPLETE)
+int env_complete(char *var, int maxv, char *cmdv[], int maxsz, char *buf);
+#endif
+
+#endif /* ENV_H */
diff --git a/include/eval_arg.h b/include/eval_arg.h
new file mode 100644 (file)
index 0000000..a86b0d5
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * (C) Copyright 2016 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#ifndef EVAL_ARG_H
+#define EVAL_ARG_H
+
+/**
+ * eval_arg() - evaluate a command argument expression
+ *
+ * @arg: pointer to argument (usually argv[i])
+ * @end_ptr: pointer to position, where evaluation stopped. Points to '\0' if no error.
+ * @return evaluated argument
+ */
+long eval_arg(char *arg, char **end_ptr);
+
+#endif /* EVAL_ARG_H */
diff --git a/include/ff.h b/include/ff.h
new file mode 120000 (symlink)
index 0000000..7fb6cb1
--- /dev/null
@@ -0,0 +1 @@
+../fatfs/src/ff.h
\ No newline at end of file
diff --git a/include/ffconf.h b/include/ffconf.h
new file mode 100644 (file)
index 0000000..9841d5b
--- /dev/null
@@ -0,0 +1,5 @@
+#ifdef __AVR__
+#include "avr/ffconf.h"
+#else
+       /* TODO */
+#endif
diff --git a/include/getopt-min.h b/include/getopt-min.h
new file mode 100644 (file)
index 0000000..e42aa78
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef GETOPT_MIN_H
+#define GETOPT_MIN_H
+
+int getopt(                                            /* returns letter, '?', EOF */
+       int             argc,                                   /* argument count from main */
+       char    *const argv[],                  /* argument vector from main */
+       const FLASH char * optstring ); /* allowed args, e.g. "ab:c" */
+
+extern int optind;
+extern char *optarg;
+
+#endif /* GETOPT_MIN_H */
diff --git a/include/gpio.h b/include/gpio.h
new file mode 100644 (file)
index 0000000..1e0346d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef GPIO_H
+#define GPIO_H
+
+/* Number of user configurable I/O pins */
+#define GPIO_MAX 11
+
+typedef enum {NONE, INPUT, INPUT_PULLUP, OUTPUT, OUTPUT_TIMER} gpiomode_t;
+
+int gpio_config(int pin, gpiomode_t mode);
+gpiomode_t gpio_config_get(int pin);
+int gpio_read(int pin);
+void gpio_write(int pin, uint8_t val);
+int gpio_clockdiv_set(int pin, unsigned long divider);
+long gpio_clockdiv_get(int pin);
+
+#endif /* GPIO_H */
diff --git a/include/i2c.h b/include/i2c.h
new file mode 100644 (file)
index 0000000..f39fa1d
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * Copyright (C) 2009 Sergey Kubushyn <ksi@koi8.net>
+ * Copyright (C) 2009 - 2013 Heiko Schocher <hs@denx.de>
+ * Changes for multibus/multiadapter I2C support.
+ *
+ * (C) Copyright 2001
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ *
+ * The original I2C interface was
+ *   (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
+ *   AIRVENT SAM s.p.a - RIMINI(ITALY)
+ * but has been changed substantially.
+ */
+
+#ifndef _I2C_H_
+#define _I2C_H_
+
+/*
+ * Configuration items.
+ */
+/* TODO: config.h? */
+#define I2C_RXTX_LEN   128     /* maximum tx/rx buffer length */
+
+
+/*
+ * Initialization, must be called once on start up, may be called
+ * repeatedly to change the speed.
+ */
+void i2c_init(uint32_t speed);
+
+/*
+ * Probe the given I2C chip address.  Returns 0 if a chip responded,
+ * not 0 on failure.
+ */
+int i2c_probe(uint8_t chip);
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uint8_t chip, unsigned int addr, uint_fast8_t alen,
+                               uint8_t *buffer, uint_fast8_t len);
+int i2c_write(uint8_t chip, unsigned int addr, uint_fast8_t alen,
+                               uint8_t *buffer, uint_fast8_t len);
+
+/*
+ * Utility routines to read/write registers.
+ */
+uint8_t i2c_reg_read(uint8_t addr, uint8_t reg);
+
+void i2c_reg_write(uint8_t addr, uint8_t reg, uint8_t val);
+
+#endif /* _I2C_H_*/
diff --git a/include/integer.h b/include/integer.h
new file mode 100644 (file)
index 0000000..4660ed6
--- /dev/null
@@ -0,0 +1,38 @@
+/*-------------------------------------------*/\r
+/* Integer type definitions for FatFs module */\r
+/*-------------------------------------------*/\r
+\r
+#ifndef _FF_INTEGER\r
+#define _FF_INTEGER\r
+\r
+#ifdef _WIN32  /* FatFs development platform */\r
+\r
+#include <windows.h>\r
+#include <tchar.h>\r
+typedef unsigned __int64 QWORD;\r
+\r
+\r
+#else                  /* Embedded platform */\r
+\r
+/* These types MUST be 16-bit or 32-bit */\r
+typedef int                            INT;\r
+typedef unsigned int   UINT;\r
+\r
+/* This type MUST be 8-bit */\r
+typedef unsigned char  BYTE;\r
+\r
+/* These types MUST be 16-bit */\r
+typedef short                  SHORT;\r
+typedef unsigned short WORD;\r
+typedef unsigned short WCHAR;\r
+\r
+/* These types MUST be 32-bit */\r
+typedef long                   LONG;\r
+typedef unsigned long  DWORD;\r
+\r
+/* This type MUST be 64-bit (Remove this for C89 compatibility) */\r
+typedef unsigned long long QWORD;\r
+\r
+#endif\r
+\r
+#endif\r
diff --git a/include/print-utils.h b/include/print-utils.h
new file mode 100644 (file)
index 0000000..ffff039
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef PRINT_UTILS_H
+#define PRINT_UTILS_H
+
+#include "common.h"
+#include <avr/eeprom.h>
+
+void print_blanks(uint_fast8_t count);
+int dump_mem(uint32_t address, uint32_t offset, uint32_t len,
+               int (*readfkt)(uint8_t *, uint32_t, uint8_t), char *title);
+
+void dump_eep(uint32_t addr, unsigned int len, char *title);
+void dump_ram(uint8_t *addr, size_t offset, unsigned int len, char *title);
+
+int eeprom_read_buf(uint8_t *buf, uint32_t addr, uint8_t count);
+int ram_read_buf(uint8_t *buf, uint32_t addr, uint8_t count);
+int flash_read_buf(uint8_t *buf, uint32_t addr, uint8_t count);
+
+#endif /* PRINT_UTILS_H */
diff --git a/include/ring.h b/include/ring.h
new file mode 100644 (file)
index 0000000..b64f462
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef RING_H
+#define RING_H
+
+struct ring {
+       uint8_t *data;
+       uint_fast8_t mask;
+       volatile uint_fast8_t begin;
+       volatile uint_fast8_t end;
+};
+
+
+static inline
+void ring_init(struct ring *ring, uint8_t *buf, int size)
+{
+       ring->data = buf;
+       ring->mask = (size-1) & 0xff;
+       ring->begin = 0;
+       ring->end = 0;
+}
+
+static inline
+int ring_write_ch(struct ring *ring, uint8_t ch)
+{
+       uint_fast8_t ep = ring->end;
+
+       ring->data[ep] = ch;
+       ep = (ep + 1) & ring->mask;
+
+       if ((ep) != ring->begin) {
+               ring->end = ep;
+               return 1;
+       }
+
+       return -1;
+}
+
+#if 0
+static inline
+int ring_write(struct ring *ring, uint8_t *data, int size)
+{
+       int i;
+
+       for (i = 0; i < size; i++) {
+               if (ring_write_ch(ring, data[i]) < 0)
+                       return -i;
+       }
+
+       return i;
+}
+#endif
+
+static inline
+int ring_read_ch(struct ring *ring)
+{
+       int ret = -1;
+       uint_fast8_t bp = ring->begin;
+
+       if (bp != ring->end) {
+               ret = ring->data[bp];
+               ring->begin = (bp + 1) & ring->mask;
+       }
+
+       return ret;
+}
+
+
+static inline
+int_fast8_t ring_is_empty(struct ring *ring)
+{
+       return ring->begin == ring->end;
+}
+
+#endif /* RING_H */
diff --git a/include/rtc.h b/include/rtc.h
new file mode 100644 (file)
index 0000000..ca4c068
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _RTC_H_
+#define _RTC_H_
+
+int rtc_get (struct tm *);
+int rtc_set (struct tm *);
+
+#endif /* _RTC_H_ */
diff --git a/include/serial.h b/include/serial.h
new file mode 100644 (file)
index 0000000..54c7211
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef SERIAL_H
+#define SERIAL_H
+
+void serial_setup(unsigned long baud);
+void serial_putc(char);
+int serial_getc(void);
+uint_fast8_t serial_tstc(void);
+
+#endif /* SERIAL_H */
diff --git a/include/spi.h b/include/spi.h
new file mode 100644 (file)
index 0000000..4638476
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * (C) Copyright 2009,2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef SPI_H_
+#define SPI_H_
+
+#define SPI_PORT       PORTB           /* SPI Connection port */
+#define SPI_DDR        DDRB            /* SPI Direction port */
+#define SPI_SS         0
+#define SPI_SCK                1
+#define SPI_MOSI       2
+#define SPI_MISO       3
+
+
+/* SPI macros */
+
+#define SPI_SET_SPEED_F_2              do {SPCR = (1<<SPE) | (1<<MSTR) | (0<<SPR1) | (0<<SPR0); SPSR = (1<<SPI2X); } while(0)
+#define SPI_SET_SPEED_F_4              do {SPCR = (1<<SPE) | (1<<MSTR) | (0<<SPR1) | (0<<SPR0); SPSR = (0<<SPI2X); } while(0)
+#define SPI_SET_SPEED_F_8              do {SPCR = (1<<SPE) | (1<<MSTR) | (0<<SPR1) | (1<<SPR0); SPSR = (1<<SPI2X); } while(0)
+#define SPI_SET_SPEED_F_16             do {SPCR = (1<<SPE) | (1<<MSTR) | (0<<SPR1) | (1<<SPR0); SPSR = (0<<SPI2X); } while(0)
+#define SPI_SET_SPEED_F_32             do {SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR1) | (0<<SPR0); SPSR = (1<<SPI2X); } while(0)
+#define SPI_SET_SPEED_F_64             do {SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR1) | (0<<SPR0); SPSR = (0<<SPI2X); } while(0)
+#define SPI_SET_SPEED_F_128            do {SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR1) | (1<<SPR0); SPSR = (0<<SPI2X); } while(0)
+
+/** switch to fast SPI Clock */
+#define SPISetFastClock()              SPI_SET_SPEED_F_2
+#define SPISetSlowClock()              SPI_SET_SPEED_F_8
+#define SPISetMMCInitClock()   SPI_SET_SPEED_F_64
+
+#define SPI_OFF()                              do { SPCR = 0; } while(0)
+
+static inline __attribute__((always_inline)) void spi_wait() {
+       loop_until_bit_is_set(SPSR,SPIF);
+}
+
+static inline __attribute__((always_inline)) void spi_write(uint8_t a) {
+       SPDR = a;
+}
+
+static inline void spi_xmit(uint8_t a){
+       spi_write(a);
+       spi_wait();
+}
+
+static inline uint8_t spi_rcvr(void) {
+       SPDR = 0xFF;
+       spi_wait();
+       return SPDR;
+}
+
+#endif /* SPI_H_ */
diff --git a/include/time.h b/include/time.h
new file mode 120000 (symlink)
index 0000000..b9ae22c
--- /dev/null
@@ -0,0 +1 @@
+../time/time.h
\ No newline at end of file
diff --git a/include/timer.h b/include/timer.h
new file mode 100644 (file)
index 0000000..83bc329
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef TIMER_H
+#define TIMER_H
+
+#include "common.h"
+
+uint32_t get_timer(uint32_t);
+
+#endif /* TIMER_H */
diff --git a/include/xmalloc.h b/include/xmalloc.h
new file mode 100644 (file)
index 0000000..cb0019f
--- /dev/null
@@ -0,0 +1,8 @@
+
+#ifndef XMALLOC_H
+#define XMALLOC_H
+
+void* xmalloc(size_t size);
+void* xrealloc(void *p, size_t size);
+
+#endif /* XMALLOC_H */
diff --git a/include/z180-serv.h b/include/z180-serv.h
new file mode 100644 (file)
index 0000000..3b4a462
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef Z180_SERV_H
+#define Z180_SERV_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ff.h"
+
+void setup_z180_serv(void);
+void restart_z180_serv(void);
+
+
+/* CP/M drive interface */
+
+/* TODO: Variable Disk Format */
+#define CONFIG_CPM_DISKSIZE            (8*1024*1024L)
+
+typedef uint8_t drv_opt_t;
+
+#define DRV_OPT_RO                     (1<<0)  /* Drive is write protected */
+#define DRV_OPT_DEBUG          (1<<1)  /* Debug this drive */
+#define DRV_OPT_REATTATCH      (1<<7)  /* Change existing attachment */
+
+typedef uint8_t drv_flag_t;
+#define DRV_FLG_OPEN           (1<<0)  /* Drive is logged in from CP/M */
+#define DRV_FLG_DIRTY          (2<<0)  /* Unwritten data */
+
+struct cpm_drive_s {
+       drv_opt_t       opt;
+       drv_flag_t      flags;
+       uint32_t        dph;
+       char            *img_name;
+       FIL                     fd;
+};
+
+/* Return codes */
+
+#define AT_OK          0
+#define AT_ERROR       1
+#define AT_RANGE       2
+#define AT_ALREADY     3
+#define AT_NOT         4
+#define AT_NOFILE      5
+#define AT_NOMEM       6
+#define AT_OPEN                7
+#define AT_OTHER       8
+
+
+int drv_list(void);
+int drv_detach(uint8_t drv);
+int drv_attach(uint8_t drv, const char *filename, drv_opt_t options);
+
+#endif /* Z180_SERV_H */
diff --git a/include/z80-if.h b/include/z80-if.h
new file mode 100644 (file)
index 0000000..ef87e5a
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+#include "common.h"
+
+#define ZST_ACQUIRED   0x01
+#define ZST_RUNNING    0x02
+
+typedef enum {
+       RESET           = 0x00,
+       RESET_AQRD      = ZST_ACQUIRED,
+       RUNNING         = ZST_RUNNING,
+       RUNNING_AQRD    = ZST_RUNNING | ZST_ACQUIRED,
+} zstate_t;
+
+typedef enum {
+       Reset,
+       Request,
+       Release,
+       Run,
+       Restart,
+       M_Cycle
+} bus_cmd_t;
+
+typedef enum {LOW, HIGH} level_t;
+
+zstate_t z80_bus_state(void);
+zstate_t z80_bus_cmd(bus_cmd_t cmd);
+void z80_setup_bus(void);
+int z80_stat_reset(void);
+//void z80_busreq(level_t level);
+int z80_stat_halt(void);
+
+
+void z80_write(uint32_t addr, uint8_t data);
+uint8_t z80_read(uint32_t addr);
+void z80_memset(uint32_t addr, uint8_t data, uint32_t length);
+void z80_write_block_P(const FLASH uint8_t *src, uint32_t dest, uint32_t length);
+void z80_write_block(const uint8_t *src, uint32_t dest, uint32_t length);
+void z80_read_block (uint8_t *dest, uint32_t src, size_t length);
+
+
+typedef enum fifo_t {
+               fifo_msgin, fifo_msgout,
+               fifo_conin, fifo_conout,
+               NUM_FIFOS
+       } fifo_t;
+
+void z80_memfifo_init(const fifo_t f, uint32_t adr);
+int z80_memfifo_is_empty(const fifo_t f);
+int z80_memfifo_is_full(const fifo_t f);
+int z80_memfifo_getc(const fifo_t f);
+uint8_t z80_memfifo_getc_wait(const fifo_t f);
+void z80_memfifo_putc(fifo_t f, uint8_t val);
diff --git a/time/Files.am b/time/Files.am
new file mode 100644 (file)
index 0000000..26bfc62
--- /dev/null
@@ -0,0 +1,77 @@
+ # (C)2012 Michael Duane Rice All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # Redistributions of source code must retain the above copyright notice, this
+ # list of conditions and the following disclaimer. Redistributions in binary
+ # form must reproduce the above copyright notice, this list of conditions
+ # and the following disclaimer in the documentation and/or other materials
+ # provided with the distribution. Neither the name of the copyright holders
+ # nor the names of contributors may be used to endorse or promote products
+ # derived from this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ # POSSIBILITY OF SUCH DAMAGE.
+
+ # $Id: Files.am 2391 2013-05-03 20:53:06Z swfltek $
+
+time_a_c_sources = \
+       asc_store.c \
+       asctime.c \
+       asctime_r.c \
+       ctime.c \
+       ctime_r.c \
+       daylight_seconds.c \
+       difftime.c \
+       dst_pointer.c \
+       equation_of_time.c \
+       fatfs_time.c \
+       geo_location.c \
+       gm_sidereal.c \
+       gmtime.c \
+       gmtime_r.c \
+       isLeap.c \
+       isotime.c \
+       iso_week_date.c \
+       iso_week_date_r.c \
+       isotime_r.c \
+       lm_sidereal.c \
+       localtime.c \
+       localtime_r.c \
+       mk_gmtime.c \
+       mktime.c \
+       month_length.c \
+       moon_phase.c \
+       print_lz.c \
+       set_dst.c \
+       set_position.c \
+       set_system_time.c \
+       set_zone.c \
+       solar_declination.c \
+       solar_noon.c \
+       strftime.c \
+       sun_rise.c \
+       sun_set.c \
+       system_time.c \
+       time.c \
+       tm_store.c \
+       utc_offset.c \
+       week_of_month.c \
+       week_of_year.c
+
+time_a_asm_sources = \
+       system_tick.S
+
+time_a_extra_dist = \
+       ephemera_common.h
diff --git a/time/Makefile b/time/Makefile
new file mode 100644 (file)
index 0000000..ea8d363
--- /dev/null
@@ -0,0 +1,529 @@
+# Makefile.in generated by automake 1.14 from Makefile.am.
+# libc/time/Makefile.  Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+# Â©2012 Michael Duane Rice All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer. Redistributions in binary
+# form must reproduce the above copyright notice, this list of conditions
+# and the following disclaimer in the documentation and/or other materials
+# provided with the distribution. Neither the name of the copyright holders
+# nor the names of contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+# $Id: Makefile.am 2379 2013-04-30 16:42:26Z joerg_wunsch $
+
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/avr-libc
+pkgincludedir = $(includedir)/avr-libc
+pkglibdir = $(libdir)/avr-libc
+pkglibexecdir = $(libexecdir)/avr-libc
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-unknown-linux-gnu
+host_triplet = avr-unknown-none
+DIST_COMMON = $(top_srcdir)/libc/time/Files.am $(srcdir)/Makefile.in \
+       $(srcdir)/Makefile.am
+subdir = libc/time
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/leo/src/avr/avr-libc-1.8.1/missing aclocal-1.14
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+AR = avr-ar
+AS = avr-as
+ASDEBUG = 
+AUTOCONF = ${SHELL} /home/leo/src/avr/avr-libc-1.8.1/missing autoconf
+AUTOHEADER = ${SHELL} /home/leo/src/avr/avr-libc-1.8.1/missing autoheader
+AUTOMAKE = ${SHELL} /home/leo/src/avr/avr-libc-1.8.1/missing automake-1.14
+AVR_LIBC_MAJOR = 1
+AVR_LIBC_MINOR = 8
+AVR_LIBC_RELDATE = 20140811
+AVR_LIBC_REVISION = 1
+AVR_LIBC_USER_MANUAL = avr-libc-user-manual-1.8.1
+AVR_LIBC_VERSION = 1.8.1
+AVR_LIBC_VERSION_NUMERIC = 10801
+AWK = gawk
+CC = avr-gcc
+CCAS = avr-gcc
+CCASDEPMODE = depmode=gcc3
+CCASFLAGS = 
+CCDEPMODE = depmode=gcc3
+CDEBUG = 
+CFLAGS = 
+CPPFLAGS = 
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+DOCSDIR = 
+DOC_INST_DIR = ${DESTDIR}${datadir}/doc/avr-libc-$(VERSION)
+ECHO_C = 
+ECHO_N = -n
+ECHO_T = 
+EXEEXT = 
+FNO_JUMP_TABLES = -fno-jump-tables
+HAS_DELAY_CYCLES = 1
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_DOX_HTML = install-dox-html
+INSTALL_DOX_MAN = install-dox-man
+INSTALL_DOX_PDF = install-dox-pdf
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LDFLAGS = 
+LIBOBJS = 
+LIBS = 
+LN_S = ln -s
+LTLIBOBJS = 
+MAKEINFO = ${SHELL} /home/leo/src/avr/avr-libc-1.8.1/missing makeinfo
+MKDIR_P = /bin/mkdir -p
+OBJEXT = o
+PACKAGE = avr-libc
+PACKAGE_BUGREPORT = avr-libc-dev@nongnu.org
+PACKAGE_NAME = avr-libc
+PACKAGE_STRING = avr-libc 1.8.1
+PACKAGE_TARNAME = avr-libc
+PACKAGE_URL = 
+PACKAGE_VERSION = 1.8.1
+PATH_SEPARATOR = :
+PNGTOPNM = pngtopnm
+PNMTOPNG = pnmtopng
+RANLIB = avr-ranlib
+SET_MAKE = 
+SHELL = /bin/bash
+STRIP = avr-strip
+TARGET_DOX_HTML = dox-html
+TARGET_DOX_PDF = dox-pdf
+VERSION = 1.8.1
+abs_builddir = /home/leo/src/avr/avr-libc-1.8.1/libc/time
+abs_srcdir = /home/leo/src/avr/avr-libc-1.8.1/libc/time
+abs_top_builddir = /home/leo/src/avr/avr-libc-1.8.1
+abs_top_srcdir = /home/leo/src/avr/avr-libc-1.8.1
+ac_ct_CC = 
+am__include = include
+am__leading_dot = .
+am__quote = 
+am__tar = $${TAR-tar} chof - "$$tardir"
+am__untar = $${TAR-tar} xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-unknown-linux-gnu
+build_alias = x86_64-unknown-linux-gnu
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = unknown
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = avr-unknown-none
+host_alias = avr
+host_cpu = avr
+host_os = none
+host_vendor = unknown
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/leo/src/avr/avr-libc-1.8.1/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target_alias = 
+top_build_prefix = ../../
+top_builddir = ../..
+top_srcdir = ../..
+time_a_c_sources = \
+       asc_store.c \
+       asctime.c \
+       asctime_r.c \
+       ctime.c \
+       ctime_r.c \
+       daylight_seconds.c \
+       difftime.c \
+       dst_pointer.c \
+       equation_of_time.c \
+       fatfs_time.c \
+       geo_location.c \
+       gm_sidereal.c \
+       gmtime.c \
+       gmtime_r.c \
+       isLeap.c \
+       isotime.c \
+       iso_week_date.c \
+       iso_week_date_r.c \
+       isotime_r.c \
+       lm_sidereal.c \
+       localtime.c \
+       localtime_r.c \
+       mk_gmtime.c \
+       mktime.c \
+       month_length.c \
+       moon_phase.c \
+       print_lz.c \
+       set_dst.c \
+       set_position.c \
+       set_system_time.c \
+       set_zone.c \
+       solar_declination.c \
+       solar_noon.c \
+       strftime.c \
+       sun_rise.c \
+       sun_set.c \
+       system_time.c \
+       time.c \
+       tm_store.c \
+       utc_offset.c \
+       week_of_month.c \
+       week_of_year.c
+
+time_a_asm_sources = \
+       system_tick.S
+
+time_a_extra_dist = \
+       ephemera_common.h
+
+EXTRA_DIST = \
+       $(time_a_c_sources) \
+       $(time_a_asm_sources) \
+       $(time_a_extra_dist)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/libc/time/Files.am $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libc/time/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign libc/time/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+$(top_srcdir)/libc/time/Files.am:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
+       ctags-am distclean distclean-generic distdir dvi dvi-am html \
+       html-am info info-am install install-am install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+       pdf-am ps ps-am tags-am uninstall uninstall-am
+
+ # (C)2012 Michael Duane Rice All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # Redistributions of source code must retain the above copyright notice, this
+ # list of conditions and the following disclaimer. Redistributions in binary
+ # form must reproduce the above copyright notice, this list of conditions
+ # and the following disclaimer in the documentation and/or other materials
+ # provided with the distribution. Neither the name of the copyright holders
+ # nor the names of contributors may be used to endorse or promote products
+ # derived from this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ # POSSIBILITY OF SUCH DAMAGE.
+
+ # $Id: Files.am 2391 2013-05-03 20:53:06Z swfltek $
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/time/Makefile.am b/time/Makefile.am
new file mode 100644 (file)
index 0000000..c8a121f
--- /dev/null
@@ -0,0 +1,35 @@
+# Â©2012 Michael Duane Rice All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer. Redistributions in binary
+# form must reproduce the above copyright notice, this list of conditions
+# and the following disclaimer in the documentation and/or other materials
+# provided with the distribution. Neither the name of the copyright holders
+# nor the names of contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+# $Id: Makefile.am 2379 2013-04-30 16:42:26Z joerg_wunsch $
+
+include $(top_srcdir)/libc/time/Files.am
+
+EXTRA_DIST = \
+       $(time_a_c_sources) \
+       $(time_a_asm_sources) \
+       $(time_a_extra_dist)
diff --git a/time/Makefile.in b/time/Makefile.in
new file mode 100644 (file)
index 0000000..868aa89
--- /dev/null
@@ -0,0 +1,529 @@
+# Makefile.in generated by automake 1.14 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Â©2012 Michael Duane Rice All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer. Redistributions in binary
+# form must reproduce the above copyright notice, this list of conditions
+# and the following disclaimer in the documentation and/or other materials
+# provided with the distribution. Neither the name of the copyright holders
+# nor the names of contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+# $Id: Makefile.am 2379 2013-04-30 16:42:26Z joerg_wunsch $
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs  ]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(top_srcdir)/libc/time/Files.am $(srcdir)/Makefile.in \
+       $(srcdir)/Makefile.am
+subdir = libc/time
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+ASDEBUG = @ASDEBUG@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AVR_LIBC_MAJOR = @AVR_LIBC_MAJOR@
+AVR_LIBC_MINOR = @AVR_LIBC_MINOR@
+AVR_LIBC_RELDATE = @AVR_LIBC_RELDATE@
+AVR_LIBC_REVISION = @AVR_LIBC_REVISION@
+AVR_LIBC_USER_MANUAL = @AVR_LIBC_USER_MANUAL@
+AVR_LIBC_VERSION = @AVR_LIBC_VERSION@
+AVR_LIBC_VERSION_NUMERIC = @AVR_LIBC_VERSION_NUMERIC@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CDEBUG = @CDEBUG@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DOCSDIR = @DOCSDIR@
+DOC_INST_DIR = @DOC_INST_DIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EXEEXT = @EXEEXT@
+FNO_JUMP_TABLES = @FNO_JUMP_TABLES@
+HAS_DELAY_CYCLES = @HAS_DELAY_CYCLES@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_DOX_HTML = @INSTALL_DOX_HTML@
+INSTALL_DOX_MAN = @INSTALL_DOX_MAN@
+INSTALL_DOX_PDF = @INSTALL_DOX_PDF@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PNGTOPNM = @PNGTOPNM@
+PNMTOPNG = @PNMTOPNG@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TARGET_DOX_HTML = @TARGET_DOX_HTML@
+TARGET_DOX_PDF = @TARGET_DOX_PDF@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+time_a_c_sources = \
+       asc_store.c \
+       asctime.c \
+       asctime_r.c \
+       ctime.c \
+       ctime_r.c \
+       daylight_seconds.c \
+       difftime.c \
+       dst_pointer.c \
+       equation_of_time.c \
+       fatfs_time.c \
+       geo_location.c \
+       gm_sidereal.c \
+       gmtime.c \
+       gmtime_r.c \
+       isLeap.c \
+       isotime.c \
+       iso_week_date.c \
+       iso_week_date_r.c \
+       isotime_r.c \
+       lm_sidereal.c \
+       localtime.c \
+       localtime_r.c \
+       mk_gmtime.c \
+       mktime.c \
+       month_length.c \
+       moon_phase.c \
+       print_lz.c \
+       set_dst.c \
+       set_position.c \
+       set_system_time.c \
+       set_zone.c \
+       solar_declination.c \
+       solar_noon.c \
+       strftime.c \
+       sun_rise.c \
+       sun_set.c \
+       system_time.c \
+       time.c \
+       tm_store.c \
+       utc_offset.c \
+       week_of_month.c \
+       week_of_year.c
+
+time_a_asm_sources = \
+       system_tick.S
+
+time_a_extra_dist = \
+       ephemera_common.h
+
+EXTRA_DIST = \
+       $(time_a_c_sources) \
+       $(time_a_asm_sources) \
+       $(time_a_extra_dist)
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(top_srcdir)/libc/time/Files.am $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libc/time/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign libc/time/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+$(top_srcdir)/libc/time/Files.am:
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic cscopelist-am \
+       ctags-am distclean distclean-generic distdir dvi dvi-am html \
+       html-am info info-am install install-am install-data \
+       install-data-am install-dvi install-dvi-am install-exec \
+       install-exec-am install-html install-html-am install-info \
+       install-info-am install-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
+       pdf-am ps ps-am tags-am uninstall uninstall-am
+
+ # (C)2012 Michael Duane Rice All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification, are permitted provided that the following conditions are
+ # met:
+ #
+ # Redistributions of source code must retain the above copyright notice, this
+ # list of conditions and the following disclaimer. Redistributions in binary
+ # form must reproduce the above copyright notice, this list of conditions
+ # and the following disclaimer in the documentation and/or other materials
+ # provided with the distribution. Neither the name of the copyright holders
+ # nor the names of contributors may be used to endorse or promote products
+ # derived from this software without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ # POSSIBILITY OF SUCH DAMAGE.
+
+ # $Id: Files.am 2391 2013-05-03 20:53:06Z swfltek $
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/time/Rules.am b/time/Rules.am
new file mode 100644 (file)
index 0000000..a2c0929
--- /dev/null
@@ -0,0 +1,30 @@
+# Â©2012 Michael Duane Rice All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer. Redistributions in binary
+# form must reproduce the above copyright notice, this list of conditions
+# and the following disclaimer in the documentation and/or other materials
+# provided with the distribution. Neither the name of the copyright holders
+# nor the names of contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+# $Id: Rules.am 2321 2013-04-02 00:12:48Z swfltek $
+
+include $(top_srcdir)/libc/time/Files.am
diff --git a/time/asc_store.c b/time/asc_store.c
new file mode 100644 (file)
index 0000000..1839ec6
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: asc_store.c 2379 2013-04-30 16:42:26Z joerg_wunsch $ */
+
+/*
+       Private allocation, shared between asctime() and isotime()
+*/
+
+#include <time.h>
+
+char            __store[26];
+
+char           *__asc_store = __store;
diff --git a/time/asctime.c b/time/asctime.c
new file mode 100644 (file)
index 0000000..38c6ea9
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: asctime.c 2318 2013-03-30 11:59:28Z swfltek $ */
+
+/*
+       Standard asctime(), we simply punt to the re-entrant version.
+*/
+
+#include <time.h>
+
+extern char    *__asc_store;
+
+char           *
+asctime(const struct tm * timeptr)
+{
+       asctime_r(timeptr, __asc_store);
+       return __asc_store;
+}
diff --git a/time/asctime_r.c b/time/asctime_r.c
new file mode 100644 (file)
index 0000000..f85336d
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: asctime_r.c 2357 2013-04-21 16:25:30Z swfltek $ */
+
+/*
+       Re-entrant version of asctime().
+
+*/
+#include <time.h>
+#include <stdlib.h>
+
+#ifdef __MEMX
+const __memx char ascmonths[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+const __memx char ascdays[] = "SunMonTueWedThuFriSat";
+#else
+const char      ascmonths[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
+const char      ascdays[] = "SunMonTueWedThuFriSat";
+#endif
+
+extern void __print_lz(int , char *, char );
+
+void
+asctime_r(const struct tm * timeptr, char *buffer)
+{
+       unsigned char   i, m, d;
+       div_t result;
+
+       d = timeptr->tm_wday * 3;
+       m = timeptr->tm_mon * 3;
+       for (i = 0; i < 3; i++) {
+           buffer[i] = ascdays[d++];
+           buffer[i+4] = ascmonths[m++];
+       }
+       buffer[3]=buffer[7]=' ';
+       buffer += 8;
+
+       __print_lz(timeptr->tm_mday,buffer,' ');
+       buffer += 3;
+
+       __print_lz(timeptr->tm_hour,buffer,':');
+       buffer += 3;
+
+       __print_lz(timeptr->tm_min,buffer,':');
+       buffer += 3;
+
+       __print_lz(timeptr->tm_sec,buffer,' ');
+       buffer += 3;
+
+       result = div(timeptr->tm_year + 1900 , 100);
+
+       __print_lz(result.quot,buffer,' ');
+       buffer += 2;
+
+       __print_lz(result.rem,buffer,0);
+
+}
diff --git a/time/ctime.c b/time/ctime.c
new file mode 100644 (file)
index 0000000..f17b873
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Â©2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: ctime.c 2318 2013-03-30 11:59:28Z swfltek $ */
+
+/*
+       Standard ctime(). We have to break down the time stamp, print it into our
+       private buffer, and return the buffer.
+*/
+#include <time.h>
+
+extern char    *__asc_store;
+
+char           *
+ctime(const time_t * timeptr)
+{
+       struct tm       calendar;
+
+       localtime_r(timeptr, &calendar);
+       asctime_r(&calendar, __asc_store);
+       return __asc_store;
+}
diff --git a/time/ctime_r.c b/time/ctime_r.c
new file mode 100644 (file)
index 0000000..4bb3633
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: ctime_r.c 2315 2013-03-29 21:24:31Z joerg_wunsch $ */
+
+/*
+       Re entrant version of ctime()
+*/
+#include <time.h>
+
+void
+ctime_r(const time_t * timeptr, char *buffer)
+{
+       struct tm       calendar;
+
+       localtime_r(timeptr, &calendar);
+       asctime_r(&calendar, buffer);
+}
diff --git a/time/daylight_seconds.c b/time/daylight_seconds.c
new file mode 100644 (file)
index 0000000..97df585
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: daylight_seconds.c 2369 2013-04-28 14:19:35Z swfltek $ */
+
+/*
+    Determine the amount of time the sun is above the horizon. At high latitudes, around the
+    solstices, this can be zero or greater than ONE_DAY.
+
+*/
+
+#include <time.h>
+#include <math.h>
+
+extern long     __latitude;
+
+long
+daylight_seconds(const time_t * timer)
+{
+    double          l, d;
+    long            n;
+
+    /* convert latitude to radians */
+    l = __latitude / 206264.806;
+
+    d = -solar_declination(timer);
+
+    /* partial 'Sunrise Equation' */
+    d = tan(l) * tan(d);
+
+    /* magnitude of d may exceed 1.0 at near solstices */
+    if (d > 1.0)
+        d = 1.0;
+
+    if (d < -1.0)
+        d = -1.0;
+
+    /* derive hour angle */
+    d = acos(d);
+
+    /* but for atmospheric refraction, this would be d /= M_PI */
+    d /= 3.112505;
+
+    n = ONE_DAY * d;
+
+    return n;
+}
diff --git a/time/difftime.c b/time/difftime.c
new file mode 100644 (file)
index 0000000..95b24e9
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: difftime.c 2318 2013-03-30 11:59:28Z swfltek $ */
+
+/*
+       The C90 standard specifies this returns a 'double. Since we do not have a true double,
+       we return a work alike type.
+*/
+#include <time.h>
+
+int32_t
+difftime(time_t t1, time_t t2)
+{
+       return t1 - t2;
+}
diff --git a/time/dst_pointer.c b/time/dst_pointer.c
new file mode 100644 (file)
index 0000000..5eda185
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: dst_pointer.c 2379 2013-04-30 16:42:26Z joerg_wunsch $ */
+
+#include <inttypes.h>
+#include <time.h>
+
+int             (*__dst_ptr) (const time_t *, int32_t *);
diff --git a/time/ephemera_common.h b/time/ephemera_common.h
new file mode 100644 (file)
index 0000000..9583f89
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: ephemera_common.h 2345 2013-04-11 23:58:48Z swfltek $ */
+
+#ifndef EPHEMERA_PRIVATE_H
+#define EPHEMERA_PRIVATE_H
+
+#define TROP_YEAR 31556925
+#define ANOM_YEAR 31558433
+#define INCLINATION 0.409105176667471    /* Earths axial tilt at the epoch */
+#define PERIHELION 31316400    /* perihelion of 1999, 03 jan 13:00 UTC */
+#define SOLSTICE 836160        /* winter solstice of 1999, 22 Dec 07:44 UTC */
+#define TWO_PI 6.283185307179586
+#define TROP_CYCLE 5022440.6025
+#define ANOM_CYCLE 5022680.6082
+#define DELTA_V 0.03342044    /* 2x orbital eccentricity */
+
+#endif
diff --git a/time/equation_of_time.c b/time/equation_of_time.c
new file mode 100644 (file)
index 0000000..a527c83
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: equation_of_time.c 2369 2013-04-28 14:19:35Z swfltek $ */
+
+/*
+    The so called Equation of Time.
+
+    The eccentricity of Earths orbit contributes about 7.7 minutes of variation to the result. It
+    has a period of 1 anomalous year, with zeroes at perihelion and aphelion.
+
+    The tilt of Earths rotational axis (obliquity) contributes about 9.9 minutes of variation. It
+    has a period of 1/2 tropical year, with zeroes at solstices and equinoxes. The time of Earths
+    arrival at these events is influenced by the eccentricity, which causes it to progress along its
+    orbital path faster as it approaches perihelion, imposing a 'modulation' on the tropical phase.
+
+    The algorithm employed computes the orbital position with respect to perihelion, deriving
+    from that a 'velocity correction factor'. The orbital position with respect to the winter solstice
+    is then computed, as modulated by that factor. The individual contributions of the obliquity and the
+    eccentricity components are then summed, and returned as an integer value in seconds.
+
+*/
+
+#include <time.h>
+#include <math.h>
+#include "ephemera_common.h"
+
+int
+equation_of_time(const time_t * timer)
+{
+    int32_t         s, p;
+    double          pf, sf, dV;
+
+    /* compute orbital position relative to perihelion */
+    p = *timer % ANOM_YEAR;
+    p += PERIHELION;
+    pf = p;
+    pf /= ANOM_CYCLE;
+    pf = sin(pf);
+
+    /* Derive a velocity correction factor from the perihelion angle */
+    dV = pf * DELTA_V;
+
+    /* compute approximate position relative to solstice */
+    s = *timer % TROP_YEAR;
+    s += SOLSTICE;
+    s *= 2;
+    sf = s;
+    sf /= TROP_CYCLE;
+
+    /* modulate to derive actual position */
+    sf += dV;
+    sf = sin(sf);
+
+    /* compute contributions */
+    sf *= 592.2;
+    pf *= 459.6;
+    s = pf + sf;
+    return -s;
+
+}
diff --git a/time/fatfs_time.c b/time/fatfs_time.c
new file mode 100644 (file)
index 0000000..e38decb
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: fatfs_time.c 2365 2013-04-27 15:32:59Z swfltek $ */
+
+/*
+       Return a value suitable for use as a file system time stamp.
+*/
+
+#include <time.h>
+
+uint32_t
+fatfs_time(const struct tm * timeptr)
+{
+       uint32_t        ret;
+       uint32_t        n;
+
+       n = timeptr->tm_year - 80;
+       n <<= 25;
+       ret = n;
+
+       n = timeptr->tm_mon + 1;
+       n <<= 21;
+       ret |= n;
+
+       n = timeptr->tm_mday;
+       n <<= 16;
+       ret |= n;
+
+       n = timeptr->tm_hour;
+       n <<= 11;
+       ret |= n;
+
+       n = timeptr->tm_min;
+       n <<= 5;
+       ret |= n;
+
+       ret |= (timeptr->tm_sec / 2);
+
+       return ret;
+}
diff --git a/time/geo_location.c b/time/geo_location.c
new file mode 100644 (file)
index 0000000..84bd7a8
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: geo_location.c 2379 2013-04-30 16:42:26Z joerg_wunsch $ */
+
+long            __latitude;
+long            __longitude;
diff --git a/time/gm_sidereal.c b/time/gm_sidereal.c
new file mode 100644 (file)
index 0000000..b0984aa
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: gm_sidereal.c 2369 2013-04-28 14:19:35Z swfltek $ */
+
+/*
+    Greenwich Mean Sidereal Time. A sidereal second is somewhat shorter than a standard second,
+    about 1.002737909350795 sidereal seconds per standard second.
+
+    We resort to fixed point math due to the insufficient resolution of a 'double', using...
+
+        timestamp * ( 1.002737909350795 << 31 )
+        --------------------------------------- + Te
+                        1 << 31
+
+    Where Te is the sidereal time at the epoch.
+
+*/
+
+#include <time.h>
+#include <stdint.h>
+
+unsigned long
+gm_sidereal(const time_t * timer)
+{
+    uint64_t        tmp;
+
+    tmp = *timer;
+    tmp *= 0x8059B740;
+    tmp /= 0x80000000;
+    tmp += (uint64_t) 23991;
+
+    tmp %= ONE_DAY;
+    return tmp;
+}
diff --git a/time/gmtime.c b/time/gmtime.c
new file mode 100644 (file)
index 0000000..f3d0b2e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: gmtime.c 2318 2013-03-30 11:59:28Z swfltek $ */
+
+/*
+       Standard gmtime(). We convert binary time into calendar time in our private struct tm object,
+       returning that object.
+*/
+
+#include <time.h>
+
+extern struct tm __tm_store;
+
+struct tm      *
+gmtime(const time_t * timeptr)
+{
+       gmtime_r(timeptr, &__tm_store);
+       return &__tm_store;
+}
diff --git a/time/gmtime_r.c b/time/gmtime_r.c
new file mode 100644 (file)
index 0000000..22658ea
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: gmtime_r.c 2369 2013-04-28 14:19:35Z swfltek $ */
+
+/* Re entrant version of gmtime(). */
+
+#include <time.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+void
+gmtime_r(const time_t * timer, struct tm * timeptr)
+{
+    int32_t         fract;
+    ldiv_t          lresult;
+    div_t           result;
+    uint16_t        days, n, leapyear, years;
+
+    /* break down timer into whole and fractional parts of 1 day */
+    days = *timer / 86400UL;
+    fract = *timer % 86400UL;
+
+    /*
+            Extract hour, minute, and second from the fractional day
+        */
+    lresult = ldiv(fract, 60L);
+    timeptr->tm_sec = lresult.rem;
+    result = div(lresult.quot, 60);
+    timeptr->tm_min = result.rem;
+    timeptr->tm_hour = result.quot;
+
+    /* Determine day of week ( the epoch was a Saturday ) */
+    n = days + SATURDAY;
+    n %= 7;
+    timeptr->tm_wday = n;
+
+    /*
+        * Our epoch year has the property of being at the conjunction of all three 'leap cycles',
+        * 4, 100, and 400 years ( though we can ignore the 400 year cycle in this library).
+        *
+        * Using this property, we can easily 'map' the time stamp into the leap cycles, quickly
+        * deriving the year and day of year, along with the fact of whether it is a leap year.
+        */
+
+    /* map into a 100 year cycle */
+    lresult = ldiv((long) days, 36525L);
+    years = 100 * lresult.quot;
+
+    /* map into a 4 year cycle */
+    lresult = ldiv(lresult.rem, 1461L);
+    years += 4 * lresult.quot;
+    days = lresult.rem;
+    if (years > 100)
+        days++;
+
+    /*
+         * 'years' is now at the first year of a 4 year leap cycle, which will always be a leap year,
+         * unless it is 100. 'days' is now an index into that cycle.
+         */
+    leapyear = 1;
+    if (years == 100)
+        leapyear = 0;
+
+    /* compute length, in days, of first year of this cycle */
+    n = 364 + leapyear;
+
+    /*
+     * if the number of days remaining is greater than the length of the
+     * first year, we make one more division.
+     */
+    if (days > n) {
+        days -= leapyear;
+        leapyear = 0;
+        result = div(days, 365);
+        years += result.quot;
+        days = result.rem;
+    }
+    timeptr->tm_year = 100 + years;
+    timeptr->tm_yday = days;
+
+    /*
+            Given the year, day of year, and leap year indicator, we can break down the
+            month and day of month. If the day of year is less than 59 (or 60 if a leap year), then
+            we handle the Jan/Feb month pair as an exception.
+        */
+    n = 59 + leapyear;
+    if (days < n) {
+        /* special case: Jan/Feb month pair */
+        result = div(days, 31);
+        timeptr->tm_mon = result.quot;
+        timeptr->tm_mday = result.rem;
+    } else {
+        /*
+            The remaining 10 months form a regular pattern of 31 day months alternating with 30 day
+            months, with a 'phase change' between July and August (153 days after March 1).
+            We proceed by mapping our position into either March-July or August-December.
+            */
+        days -= n;
+        result = div(days, 153);
+        timeptr->tm_mon = 2 + result.quot * 5;
+
+        /* map into a 61 day pair of months */
+        result = div(result.rem, 61);
+        timeptr->tm_mon += result.quot * 2;
+
+        /* map into a month */
+        result = div(result.rem, 31);
+        timeptr->tm_mon += result.quot;
+        timeptr->tm_mday = result.rem;
+    }
+
+    /*
+            Cleanup and return
+        */
+    timeptr->tm_isdst = 0;  /* gmt is never in DST */
+    timeptr->tm_mday++; /* tm_mday is 1 based */
+
+}
diff --git a/time/isLeap.c b/time/isLeap.c
new file mode 100644 (file)
index 0000000..3c846aa
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: isLeap.c 2325 2013-04-02 21:22:16Z swfltek $ */
+
+/*
+    Return 1 if 'year' is a leap year, else 0.
+*/
+
+#include <stdlib.h>
+
+unsigned char
+is_leap_year(int year)
+{
+    div_t           d;
+
+    /* year must be divisible by 4 to be a leap year */
+    if (year & 3)
+        return 0;
+
+    /* If theres a remainder after division by 100, year is not divisible by 100 or 400 */
+    d = div(year, 100);
+    if (d.rem)
+        return 1;
+
+    /* If the quotient is divisible by 4, then year is divisible by 400 */
+    if ((d.quot & 3) == 0)
+        return 1;
+
+    return 0;
+}
diff --git a/time/iso_week_date.c b/time/iso_week_date.c
new file mode 100644 (file)
index 0000000..efbf841
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: iso_week_date.c 2394 2013-05-04 10:26:24Z swfltek $ */
+
+/*
+    Compute the ISO 8601 week date corresponding to the given year and day of year.
+    See http://en.wikipedia.org/wiki/ISO_week_date for a full description.
+
+    See iso_week_date_r.c for implementation details.
+
+*/
+
+#include <time.h>
+
+extern char    *__asc_store;
+
+struct week_date *
+iso_week_date(int y, int yday)
+{
+    struct week_date *iso;
+
+    iso = (struct week_date *) __asc_store;
+    iso_week_date_r(y, yday, iso);
+    return iso;
+}
diff --git a/time/iso_week_date_r.c b/time/iso_week_date_r.c
new file mode 100644 (file)
index 0000000..ac1feb4
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: iso_week_date_r.c 2394 2013-05-04 10:26:24Z swfltek $ */
+
+/*
+    Compute the ISO 8601 week date corresponding to the given year and day of year.
+    See http://en.wikipedia.org/wiki/ISO_week_date for a full description. To summarize:
+
+        Weeks are numbered from 1 to 53.
+        Week days are numbered 1 to 7, beginning with Monday as day 1.
+
+        The first week of the year contains the first Thursday in that year.
+        Dates prior to week 1 belong to the final week of the previous year.
+
+        The final week of the year contains the last Thursday in that year.
+        Dates after the final week belong to week 1 of the following year.
+
+*/
+
+#include <time.h>
+
+void
+iso_week_date_r(int y, int yday, struct week_date * iso)
+{
+    uint16_t        years, n, wday;
+    int             weeknum;
+    int isLeap;
+
+    iso->year = y;
+
+    isLeap = is_leap_year(y);
+
+    /* compute days elapsed since epoch */
+    years = y - 2000;
+    n = 365 * years + yday;
+    if (years) {
+        n++;        /* epoch was a leap year */
+        n += years / 4;
+        n -= isLeap;
+        if (years > 100)
+            n--;
+    }
+
+    /* compute ISO8601 day of week (1 ... 7, Monday = 1) */
+    wday = n + 6; /* epoch was a Saturday */
+    wday %= 7;
+    if (wday == 0)
+        wday = 7;
+
+    iso->day = wday;
+
+    /* compute tentative week number */
+    weeknum = yday + 11 - wday;
+    weeknum /= 7;
+
+    /* if 53, it could be week 1 of the following year */
+    if (weeknum == 53) {
+        /*
+            The final week must include its Thursday in the year. We determine the yday of this
+            weeks Thursday, and test whether it exceeds this years length.
+        */
+
+        /* determine final yday of this year, 364 or 365 */
+        n = 364 + isLeap;
+
+        /* compute yday of this weeks Thursday */
+        wday--;       /* convert to zero based week, Monday = 0 */
+        yday -= wday; /* yday of this weeks Monday */
+        yday += 3;    /* yday of this weeks Thursday */
+
+        /* Is this weeks Thursday included in the year? */
+        if (yday > (int) n) {
+            iso->year++;
+            weeknum = 1;
+        }
+    }
+    iso->week = weeknum;
+
+    /*
+        If zero, it is the final week of the previous year.
+        We determine that by asking for the week number of Dec 31.
+    */
+    if (weeknum == 0) {
+        y = y - 1;
+        iso_week_date_r(y, 364 + is_leap_year(y), iso);
+        iso->day = wday;
+    }
+}
diff --git a/time/isotime.c b/time/isotime.c
new file mode 100644 (file)
index 0000000..a257815
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: isotime.c 2365 2013-04-27 15:32:59Z swfltek $ */
+
+/*
+       This function returns ISO8601 formatted time, in our private buffer.
+*/
+
+#include <time.h>
+
+extern char    *__asc_store;
+
+char           *
+isotime(const struct tm * tmptr)
+{
+       isotime_r(tmptr, __asc_store);
+       return __asc_store;
+}
diff --git a/time/isotime_r.c b/time/isotime_r.c
new file mode 100644 (file)
index 0000000..5636a7f
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: isotime_r.c 2365 2013-04-27 15:32:59Z swfltek $ */
+
+/*
+       Re entrant version of isotime(),  which prints the date and time in ISO 8601 format.
+*/
+
+#include <stdlib.h>
+#include <time.h>
+
+extern void __print_lz(int , char *, char );
+
+void
+isotime_r(const struct tm * tmptr, char *buffer)
+{
+       int             i;
+
+       i = tmptr->tm_year + 1900;
+       __print_lz(i/100, buffer, '-');
+       buffer+=2;
+       __print_lz(i%100, buffer,'-');
+       buffer+=3;
+
+       i = tmptr->tm_mon + 1;
+       __print_lz(i, buffer,'-');
+       buffer+=3;
+
+       i = tmptr->tm_mday;
+       __print_lz(i, buffer,' ');
+       buffer+=3;
+
+       i = tmptr->tm_hour;
+       __print_lz(i, buffer,':');
+       buffer+=3;
+
+       i = tmptr->tm_min;
+       __print_lz(i, buffer,':');
+       buffer+=3;
+
+       i = tmptr->tm_sec;
+       __print_lz(i, buffer,0);
+
+}
diff --git a/time/lm_sidereal.c b/time/lm_sidereal.c
new file mode 100644 (file)
index 0000000..ad34fac
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: lm_sidereal.c 2326 2013-04-02 21:23:41Z swfltek $ */
+
+/*
+    Local Mean Sidereal Time. See gm_sidereal() for info.
+*/
+#include <time.h>
+
+extern long     __longitude;
+
+unsigned long
+lm_sidereal(const time_t * timer)
+{
+    long            n;
+
+    n = gm_sidereal(timer) + __longitude / 15L;
+    n += ONE_DAY;
+    n %= ONE_DAY;
+    return n;
+}
diff --git a/time/localtime.c b/time/localtime.c
new file mode 100644 (file)
index 0000000..0e18967
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: localtime.c 2318 2013-03-30 11:59:28Z swfltek $ */
+
+/*
+       Standard localtime() function.
+*/
+
+#include <time.h>
+
+extern struct tm __tm_store;
+
+struct tm      *
+localtime(const time_t * timer)
+{
+       localtime_r(timer, &__tm_store);
+       return &__tm_store;
+}
diff --git a/time/localtime_r.c b/time/localtime_r.c
new file mode 100644 (file)
index 0000000..0bd1a02
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: localtime_r.c 2318 2013-03-30 11:59:28Z swfltek $ */
+
+/*
+       Re entrant version of localtime(). Given a binary UTC time stamp, add the time
+       zone and Daylight savings offset, then break it down into calendar time.
+*/
+
+#include <time.h>
+
+extern long     __utc_offset;
+
+extern int      (*__dst_ptr) (const time_t *, int32_t *);
+
+void
+localtime_r(const time_t * timer, struct tm * timeptr)
+{
+       time_t          lt;
+       int16_t         dst;
+
+       dst = -1;
+
+       if (__dst_ptr)
+               dst = __dst_ptr(timer, &__utc_offset);
+
+       lt = *timer + __utc_offset;
+
+       if (dst > 0)
+               lt += dst;
+
+       gmtime_r(&lt, timeptr);
+       timeptr->tm_isdst = dst;
+}
diff --git a/time/mk_gmtime.c b/time/mk_gmtime.c
new file mode 100644 (file)
index 0000000..7f2b9b9
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: mk_gmtime.c 2369 2013-04-28 14:19:35Z swfltek $ */
+
+/*
+    'Break down' a y2k time stamp into the elements of struct tm.
+    Unlike mktime(), this function does not 'normalize' the elements of timeptr.
+
+*/
+
+#include <time.h>
+
+time_t
+mk_gmtime(const struct tm * timeptr)
+{
+
+    time_t          ret;
+    uint32_t        tmp;
+    int             n, m, d, leaps;
+
+    /*
+        Determine elapsed whole days since the epoch to the beginning of this year. Since our epoch is
+        at a conjunction of the leap cycles, we can do this rather quickly.
+        */
+    n = timeptr->tm_year - 100;
+    leaps = 0;
+    if (n) {
+        m = n - 1;
+        leaps = m / 4;
+        leaps -= m / 100;
+        leaps++;
+    }
+    tmp = 365UL * n + leaps;
+
+    /*
+                Derive the day of year from month and day of month. We use the pattern of 31 day months
+                followed by 30 day months to our advantage, but we must 'special case' Jan/Feb, and
+                account for a 'phase change' between July and August (153 days after March 1).
+            */
+    d = timeptr->tm_mday - 1;   /* tm_mday is one based */
+
+    /* handle Jan/Feb as a special case */
+    if (timeptr->tm_mon < 2) {
+        if (timeptr->tm_mon)
+            d += 31;
+
+    } else {
+        n = 59 + is_leap_year(timeptr->tm_year + 1900);
+        d += n;
+        n = timeptr->tm_mon - MARCH;
+
+        /* account for phase change */
+        if (n > (JULY - MARCH))
+            d += 153;
+        n %= 5;
+
+        /*
+         * n is now an index into a group of alternating 31 and 30
+         * day months... 61 day pairs.
+         */
+        m = n / 2;
+        m *= 61;
+        d += m;
+
+        /*
+         * if n is odd, we are in the second half of the
+         * month pair
+         */
+        if (n & 1)
+            d += 31;
+    }
+
+    /* Add day of year to elapsed days, and convert to seconds */
+    tmp += d;
+    tmp *= ONE_DAY;
+    ret = tmp;
+
+    /* compute 'fractional' day */
+    tmp = timeptr->tm_hour;
+    tmp *= ONE_HOUR;
+    tmp += timeptr->tm_min * 60UL;
+    tmp += timeptr->tm_sec;
+
+    ret += tmp;
+
+    return ret;
+}
diff --git a/time/mktime.c b/time/mktime.c
new file mode 100644 (file)
index 0000000..1600202
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: mktime.c 2318 2013-03-30 11:59:28Z swfltek $ */
+
+/*
+       Standard mktime(). The provided broken down Local 'calendar' time is converted into
+       a binary time stamp. The process is then reversed to 'normalize' timeptr.
+*/
+
+#include <time.h>
+
+extern long     __utc_offset;
+
+extern int      (*__dst_ptr) (const time_t *, int32_t *);
+
+time_t
+mktime(struct tm * timeptr)
+{
+       time_t          ret;
+
+       ret = mk_gmtime(timeptr);
+
+       if (timeptr->tm_isdst < 0) {
+               if (__dst_ptr)
+                       timeptr->tm_isdst = __dst_ptr(&ret, &__utc_offset);
+       }
+       if (timeptr->tm_isdst > 0)
+               ret -= timeptr->tm_isdst;
+
+       ret -= __utc_offset;
+
+       localtime_r(&ret, timeptr);
+
+       return ret;
+}
diff --git a/time/month_length.c b/time/month_length.c
new file mode 100644 (file)
index 0000000..0f2f091
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: month_length.c 2358 2013-04-23 22:30:20Z swfltek $ */
+
+/*
+    Return the length of a month in days, given the year and month in question.
+    The month parameter must be '1 based', ranging from 1 to 12.
+*/
+
+#include <time.h>
+
+uint8_t
+month_length(int year, uint8_t month)
+{
+    if (month == 2)
+        return 28 + is_leap_year(year);
+
+    /* 'knuckles' algorithm */
+    if (month > 7)
+        month++;
+    return 30 + (month & 1);
+}
diff --git a/time/moon_phase.c b/time/moon_phase.c
new file mode 100644 (file)
index 0000000..5fb5826
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: moon_phase.c 2365 2013-04-27 15:32:59Z swfltek $ */
+
+/*
+    Return an approximation to the phase of the moon. Since no attempt is made to account for
+    Sol, Jupiter or Venus, it will often be off by several hours.
+*/
+
+#include <time.h>
+#include <math.h>
+
+int8_t
+moon_phase(const time_t * timestamp)
+{
+       uint32_t        t;
+       int32_t         n;
+       double          mc;
+
+       /* refer to first new moon of the epoch */
+       t = *timestamp - 1744800UL;
+
+       /* constrain to 1 lunar cycle */
+       n = t % 2551443UL;
+
+       /* offset by 1/2 lunar cycle */
+       n -= 1275721L;
+       mc = n;
+       mc /= 1275721.0;
+       mc *= M_PI;
+       mc = cos(mc) * sin(mc);
+       mc *= 12.5;
+
+       /* scale to range - 100...+ 100 */
+       n /= 12757L;
+       n -= mc;
+
+       return n;
+}
diff --git a/time/print_lz.c b/time/print_lz.c
new file mode 100644 (file)
index 0000000..95c81bd
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: print_lz.c 2357 2013-04-21 16:25:30Z swfltek $ */
+
+/* print 2 digit integer with leading zero: auxillary function for isotime and asctime */
+
+#include <stdlib.h>
+
+void
+__print_lz(int i, char *buffer, char s)
+{
+    div_t result;
+
+    result = div(i, 10);
+
+       *buffer++ = result.quot + '0';
+       *buffer++ = result.rem + '0';
+       *buffer = s;
+}
diff --git a/time/set_dst.c b/time/set_dst.c
new file mode 100644 (file)
index 0000000..9ba0964
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: set_dst.c 2318 2013-03-30 11:59:28Z swfltek $ */
+
+/*
+       Set the dst function pointer.
+*/
+
+#include <inttypes.h>
+#include <time.h>
+
+extern int      (*__dst_ptr) (const time_t *, int32_t *);
+
+void
+set_dst(int (*d) (const time_t *, int32_t *))
+{
+       __dst_ptr = d;
+}
diff --git a/time/set_position.c b/time/set_position.c
new file mode 100644 (file)
index 0000000..e268316
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: set_position.c 2318 2013-03-30 11:59:28Z swfltek $ */
+
+/*
+       Set the geographic position of the observer. Both parameters are in seconds, with
+       North latitude and East longitude being positive values.
+*/
+
+extern long     __latitude;
+extern long     __longitude;
+
+void
+set_position(long lat, long lon)
+{
+       __latitude = lat;
+       __longitude = lon;
+}
diff --git a/time/set_system_time.c b/time/set_system_time.c
new file mode 100644 (file)
index 0000000..334790e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: set_system_time.c 2356 2013-04-21 16:20:01Z swfltek $ */
+
+/*
+ * Set the system time. The values passed are assumed to represent local
+ * standard time, such as would be obtained from the typical Real Time Clock
+ * integrated circuit. It is necessary for this to be atomic, as the value may be
+ * incremented at interrupt time.
+ */
+
+#include <time.h>
+extern volatile time_t __system_time;
+
+void
+set_system_time(time_t timestamp)
+{
+
+       asm             volatile(
+                                          "in __tmp_reg__, __SREG__" "\n\t"
+                                                "cli" "\n\t"
+                                ::
+       );
+       __system_time = timestamp;
+       asm             volatile(
+                                         "out __SREG__, __tmp_reg__" "\n\t"
+                                ::
+       );
+}
diff --git a/time/set_zone.c b/time/set_zone.c
new file mode 100644 (file)
index 0000000..eb0f11b
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: set_zone.c 2318 2013-03-30 11:59:28Z swfltek $ */
+
+/*
+       Set the system time zone. The parameter is seconds offset from UTC.
+*/
+
+extern long     __utc_offset;
+
+void
+set_zone(long z)
+{
+       __utc_offset = z;
+}
diff --git a/time/solar_declination.c b/time/solar_declination.c
new file mode 100644 (file)
index 0000000..dd89028
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: solar_declination.c 2369 2013-04-28 14:19:35Z swfltek $ */
+
+/*
+    Were it not for the eccentricity of Earths orbit, this would be a trivial function.
+
+    We compute the Earths orbital position with respect to perihelion, from which we derive a
+    'velocity correction factor'. We then compute the orbital angle with respect to the
+    December solstice, as 'modulated' by that correction factor.
+
+    Due to the accumulation of rounding errors, the computed December solstice of 2135 will lag
+    the actual solstice by many hours. A fudge factor, 'LAG', distributes the error across
+    the 136 year range of this library.
+*/
+
+#include <time.h>
+#include <math.h>
+#include "ephemera_common.h"
+
+#define LAG 38520
+
+double
+solar_declination(const time_t * timer)
+{
+
+    uint32_t        fT, oV;
+    double          dV, dT;
+
+    /* Determine orbital angle relative to perihelion of January 1999 */
+    oV = *timer % ANOM_YEAR;
+    oV += PERIHELION;
+    dV = oV;
+    dV /= ANOM_CYCLE;
+
+    /* Derive velocity correction factor from the perihelion angle */
+    dV = sin(dV);
+    dV *= DELTA_V;
+
+    /* Determine orbital angle relative to solstice of December 1999 */
+    fT = *timer % TROP_YEAR;
+    fT += SOLSTICE + LAG;
+    dT = fT;
+    dT /= TROP_CYCLE;
+    dT += dV;
+
+    /* Finally having the solstice angle, we can compute the declination */
+    dT = cos(dT) * INCLINATION;
+
+    return -dT;
+}
diff --git a/time/solar_noon.c b/time/solar_noon.c
new file mode 100644 (file)
index 0000000..65bafcc
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: solar_noon.c 2365 2013-04-27 15:32:59Z swfltek $ */
+
+/*
+    Return the time of solar noon at the observers position
+*/
+
+#include <time.h>
+
+extern long     __longitude;
+
+time_t
+solar_noon(const time_t * timer)
+{
+    time_t          t;
+    long            n;
+
+    /* determine time of solar noon at the prime meridian */
+    t = *timer % ONE_DAY;
+    t = *timer - t;
+    t += 43200L;
+    t -= equation_of_time(timer);
+
+    /* rotate to observers longitude */
+    n = __longitude / 15L;
+    t -= n;
+
+    return t;
+
+}
diff --git a/time/strftime.c b/time/strftime.c
new file mode 100644 (file)
index 0000000..4dcfd30
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: strftime.c 2391 2013-05-03 20:53:06Z swfltek $ */
+
+/*
+    Standard strftime(). This is a memory hungry monster.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+extern long     __utc_offset;
+
+#ifdef __MEMX
+
+const __memx char strfwkdays[] = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday ";
+const __memx char strfmonths[] = "January February March April May June July August September October November December ";
+
+#else
+
+const char      strfwkdays[] = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday ";
+const char      strfmonths[] = "January February March April May June July August September October November December ";
+
+#endif
+
+#ifdef __MEMX
+
+unsigned char
+pgm_copystring(const char __memx * p, unsigned char i, char *b, unsigned char l)
+{
+
+#else
+
+unsigned char
+pgm_copystring(const char *p, unsigned char i, char *b, unsigned char l)
+{
+
+#endif
+
+    unsigned char   ret, c;
+
+    ret = 0;
+    while (i) {
+        c = *p++;
+        if (c == ' ')
+            i--;
+    }
+
+    c = *p++;
+    while (c != ' ' && l--) {
+        *b++ = c;
+        ret++;
+        c = *p++;
+    }
+    *b = 0;
+    return ret;
+}
+
+size_t
+strftime(char *buffer, size_t limit, const char *pattern, const struct tm * timeptr)
+{
+    unsigned int    count, length;
+    int             d, w;
+    char            c;
+    char            _store[26];
+    struct week_date wd;
+
+    count = length = 0;
+    while (count < limit) {
+        c = *pattern++;
+        if (c == '%') {
+            c = *pattern++;
+            if (c == 'E' || c == 'O')
+                c = *pattern++;
+            switch (c) {
+            case ('%'):
+                _store[0] = c;
+                length = 1;
+                break;
+
+            case ('a'):
+                length = pgm_copystring(strfwkdays, timeptr->tm_wday, _store, 3);
+                break;
+
+            case ('A'):
+                length = pgm_copystring(strfwkdays, timeptr->tm_wday, _store, 255);
+                break;
+
+            case ('b'):
+            case ('h'):
+                length = pgm_copystring(strfmonths, timeptr->tm_mon, _store, 3);
+                break;
+
+            case ('B'):
+                length = pgm_copystring(strfmonths, timeptr->tm_mon, _store, 255);
+                break;
+
+            case ('c'):
+                asctime_r(timeptr, _store);
+                length = 0;
+                while (_store[length])
+                    length++;
+                break;
+
+            case ('C'):
+                d = timeptr->tm_year + 1900;
+                d /= 100;
+                length = sprintf(_store, "%.2d", d);
+                break;
+
+            case ('d'):
+                length = sprintf(_store, "%.2u", timeptr->tm_mday);
+                break;
+
+            case ('D'):
+                length = sprintf(_store, "%.2u/%.2u/%.2u", \
+                         timeptr->tm_mon + 1, \
+                         timeptr->tm_mday, \
+                         timeptr->tm_year % 100 \
+                    );
+                break;
+
+            case ('e'):
+                length = sprintf(_store, "%2d", timeptr->tm_mday);
+                break;
+
+            case ('F'):
+                length = sprintf(_store, "%d-%.2d-%.2d", \
+                         timeptr->tm_year + 1900, \
+                         timeptr->tm_mon + 1, \
+                         timeptr->tm_mday \
+                    );
+                break;
+
+            case ('g'):
+                       case ('G'):
+                               iso_week_date_r(timeptr->tm_year + 1900, timeptr->tm_yday, &wd);
+                if (c == 'g') {
+                    length = sprintf(_store, "%.2d", wd.year % 100);
+                } else {
+                    length = sprintf(_store, "%.4d", wd.year);
+                }
+
+                               break;
+
+            case ('H'):
+                length = sprintf(_store, "%.2u", timeptr->tm_hour);
+                break;
+
+            case ('I'):
+                d = timeptr->tm_hour % 12;
+                if (d == 0)
+                    d = 12;
+                length = sprintf(_store, "%.2u", d);
+                break;
+
+            case ('j'):
+                length = sprintf(_store, "%.3u", timeptr->tm_yday + 1);
+                break;
+
+            case ('m'):
+                length = sprintf(_store, "%.2u", timeptr->tm_mon + 1);
+                break;
+
+            case ('M'):
+                length = sprintf(_store, "%.2u", timeptr->tm_min);
+                break;
+
+            case ('n'):
+                _store[0] = 10;
+                length = 1;
+                break;
+
+            case ('p'):
+                length = 2;
+                _store[0] = 'A';
+                if (timeptr->tm_hour > 11)
+                    _store[0] = 'P';
+                _store[1] = 'M';
+                _store[2] = 0;
+                break;
+
+            case ('r'):
+                d = timeptr->tm_hour % 12;
+                if (d == 0)
+                    d = 12;
+                length = sprintf(_store, "%2d:%.2d:%.2d AM", \
+                         d, \
+                         timeptr->tm_min, \
+                         timeptr->tm_sec \
+                    );
+                if (timeptr->tm_hour > 11)
+                    _store[10] = 'P';
+                break;
+
+            case ('R'):
+                length = sprintf(_store, "%.2d:%.2d", timeptr->tm_hour, timeptr->tm_min);
+                break;
+
+            case ('S'):
+                length = sprintf(_store, "%.2u", timeptr->tm_sec);
+                break;
+
+            case ('t'):
+                length = sprintf(_store, "\t");
+                break;
+
+            case ('T'):
+                length = sprintf(_store, "%.2d:%.2d:%.2d", \
+                         timeptr->tm_hour, \
+                         timeptr->tm_min, \
+                         timeptr->tm_sec \
+                    );
+                break;
+
+            case ('u'):
+                w = timeptr->tm_wday;
+                if (w == 0)
+                    w = 7;
+                length = sprintf(_store, "%d", w);
+                break;
+
+            case ('U'):
+                length = sprintf(_store, "%.2u", week_of_year(timeptr, 0));
+                break;
+
+                       case ('V'):
+                               iso_week_date_r(timeptr->tm_year + 1900, timeptr->tm_yday, &wd);
+                length = sprintf(_store, "%.2u", wd.week);
+                               break;
+
+            case ('w'):
+                length = sprintf(_store, "%u", timeptr->tm_wday);
+                break;
+
+            case ('W'):
+                w = week_of_year(timeptr, 1);
+                length = sprintf(_store, "%.2u", w);
+                break;
+
+            case ('x'):
+                length = sprintf(_store, "%.2u/%.2u/%.2u", timeptr->tm_mon + 1, timeptr->tm_mday, timeptr->tm_year % 100);
+                break;
+
+            case ('X'):
+                length = sprintf(_store, "%.2u:%.2u:%.2u", timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec);
+                break;
+
+            case ('y'):
+                length = sprintf(_store, "%.2u", timeptr->tm_year % 100);
+                break;
+
+            case ('Y'):
+                length = sprintf(_store, "%u", timeptr->tm_year + 1900);
+                break;
+
+            case ('z'):
+                d = __utc_offset / 60;
+                w = timeptr->tm_isdst / 60;
+                if (w > 0)
+                    d += w;
+                w = abs(d % 60);
+                d = d / 60;
+                length = sprintf(_store, "%+.2d%.2d", d, w);
+                break;
+
+            default:
+                length = 1;
+                _store[0] = '?';
+                _store[1] = 0;
+                break;
+            }
+
+            if ((length + count) < limit) {
+                count += length;
+                for (d = 0; d < (int) length; d++) {
+                    *buffer++ = _store[d];
+                }
+            } else {
+                *buffer = 0;
+                return count;
+            }
+
+        } else {    /* copy a literal */
+            *buffer = c;
+            buffer++;
+            count++;
+            if (c == 0)
+                return count;
+        }
+    }
+
+    *buffer = 0;
+    return count;
+}
diff --git a/time/sun_rise.c b/time/sun_rise.c
new file mode 100644 (file)
index 0000000..b2ff62c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: sun_rise.c 2365 2013-04-27 15:32:59Z swfltek $ */
+
+/*
+    Return the approximate time of sun rise.
+*/
+
+#include <time.h>
+
+time_t
+sun_rise(const time_t * timer)
+{
+    long            n;
+    time_t          t;
+
+    /* sunrise is 1/2 'day' before solar noon */
+    t = solar_noon(timer);
+    n = daylight_seconds(timer) / 2L;
+    t -= n;
+
+    return t;
+}
diff --git a/time/sun_set.c b/time/sun_set.c
new file mode 100644 (file)
index 0000000..338e35f
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: sun_set.c 2365 2013-04-27 15:32:59Z swfltek $ */
+
+/*
+    Return the approximate time of sun set.
+*/
+
+#include <time.h>
+
+time_t
+sun_set(const time_t * timer)
+{
+    long            n;
+    time_t          t;
+
+    /* sunset is 1/2 'day' after solar noon */
+    t = solar_noon(timer);
+    n = daylight_seconds(timer) / 2L;
+    t += n;
+
+    return t;
+
+}
diff --git a/time/system_tick.S b/time/system_tick.S
new file mode 100644 (file)
index 0000000..c1f90fd
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: system_tick.S 2348 2013-04-16 23:42:05Z swfltek $ */
+
+/*
+    Impoved system_tick Credit to Wouter van Gulik.
+*/
+
+#include <avr/common.h>
+
+    .global    system_tick
+       .type   system_tick, @function
+system_tick:
+    push r24
+    in r24,_SFR_IO_ADDR(SREG)
+       push r24
+       cli
+    lds r24,__system_time+0
+    subi r24, (-1)
+    sts __system_time+0,r24
+    lds r24,__system_time+1
+    sbci r24, (-1)
+    sts __system_time+1,r24
+    lds r24,__system_time+2
+    sbci r24, (-1)
+    sts __system_time+2,r24
+    lds r24,__system_time+3
+    sbci r24, (-1)
+    sts __system_time+3,r24
+    pop r24
+    out _SFR_IO_ADDR(SREG),r24
+    pop r24
+    ret
+       .size   system_tick, .-system_tick
diff --git a/time/system_time.c b/time/system_time.c
new file mode 100644 (file)
index 0000000..64bdac7
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: system_time.c 2321 2013-04-02 00:12:48Z swfltek $ */
+
+/*
+       The system time stamp.
+*/
+#include <time.h>
+
+volatile time_t __system_time;
diff --git a/time/time.c b/time/time.c
new file mode 100644 (file)
index 0000000..e794322
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: time.c 2318 2013-03-30 11:59:28Z swfltek $ */
+
+/*
+       Standard time() function. Copying from __system_time must be atomic, since it
+       may be incremented at interrupt time.
+*/
+#include <time.h>
+#include <inttypes.h>
+
+extern volatile time_t __system_time;
+
+time_t
+time(time_t * timer)
+{
+       time_t          ret;
+
+       asm             volatile(
+                                          "in __tmp_reg__, __SREG__" "\n\t"
+                                                "cli" "\n\t"
+                                ::
+       );
+       ret = __system_time;
+       asm             volatile(
+                                         "out __SREG__, __tmp_reg__" "\n\t"
+                                ::
+       );
+       if (timer)
+               *timer = ret;
+       return ret;
+}
diff --git a/time/time.h b/time/time.h
new file mode 100644 (file)
index 0000000..21d86e9
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: time.h 2427 2014-05-01 14:06:03Z amylaar $ */
+
+/** \file */
+
+/**    \defgroup avr_time <time.h>: Time
+    \code #include <time.h> \endcode
+    <h3>Introduction to the Time functions</h3>
+    This file declares the time functions implemented in \c avr-libc.
+
+    The implementation aspires to conform with ISO/IEC 9899 (C90). However, due to limitations of the
+    target processor and the nature of its development environment, a practical implementation must
+    of necessity deviate from the standard.
+
+
+
+    Section 7.23.2.1 clock()
+    The type clock_t, the macro CLOCKS_PER_SEC, and the function clock() are not implemented. We
+    consider these items belong to operating system code, or to application code when no operating
+    system is present.
+
+    Section 7.23.2.3 mktime()
+    The standard specifies that mktime() should return (time_t) -1, if the time cannot be represented.
+    This implementation always returns a 'best effort' representation.
+
+    Section 7.23.2.4 time()
+    The standard specifies that time() should return (time_t) -1, if the time is not available.
+    Since the application must initialize the time system, this functionality is not implemented.
+
+    Section 7.23.2.2, difftime()
+    Due to the lack of a 64 bit double, the function difftime() returns a long integer. In most cases
+    this change will be invisible to the user, handled automatically by the compiler.
+
+    Section 7.23.1.4 struct tm
+    Per the standard, struct tm->tm_isdst is greater than zero when Daylight Saving time is in effect.
+    This implementation further specifies that, when positive, the value of tm_isdst represents
+    the amount time is advanced during Daylight Saving time.
+
+    Section 7.23.3.5 strftime()
+    Only the 'C' locale is supported, therefore the modifiers 'E' and 'O' are ignored.
+    The 'Z' conversion is also ignored, due to the lack of time zone name.
+
+    In addition to the above departures from the standard, there are some behaviors which are different
+    from what is often expected, though allowed under the standard.
+
+    There is no 'platform standard' method to obtain the current time, time zone, or
+    daylight savings 'rules' in the AVR environment. Therefore the application must initialize
+    the time system with this information. The functions set_zone(), set_dst(), and
+    set_system_time() are provided for initialization. Once initialized, system time is maintained by
+    calling the function system_tick() at one second intervals.
+
+    Though not specified in the standard, it is often expected that time_t is a signed integer
+    representing an offset in seconds from Midnight Jan 1 1970... i.e. 'Unix time'. This implementation
+    uses an unsigned 32 bit integer offset from Midnight Jan 1 2000. The use of this 'epoch' helps to
+    simplify the conversion functions, while the 32 bit value allows time to be properly represented
+    until Tue Feb 7 06:28:15 2136 UTC. The macros UNIX_OFFSET and NTP_OFFSET are defined to assist in
+    converting to and from Unix and NTP time stamps.
+
+    Unlike desktop counterparts, it is impractical to implement or maintain the 'zoneinfo' database.
+    Therefore no attempt is made to account for time zone, daylight saving, or leap seconds in past dates.
+    All calculations are made according to the currently configured time zone and daylight saving 'rule'.
+
+    In addition to C standard functions, re-entrant versions of ctime(), asctime(), gmtime() and
+    localtime() are provided which, in addition to being re-entrant, have the property of claiming
+    less permanent storage in RAM. An additional time conversion, isotime() and its re-entrant version,
+    uses far less storage than either ctime() or asctime().
+
+    Along with the usual smattering of utility functions, such as is_leap_year(), this library includes
+    a set of functions related the sun and moon, as well as sidereal time functions.
+*/
+
+#ifndef TIME_H
+#define TIME_H
+
+#ifdef __cplusplus
+extern          "C" {
+#endif
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+    /** \ingroup avr_time */
+    /* @{ */
+
+    /**
+        time_t represents seconds elapsed from Midnight, Jan 1 2000 UTC (the Y2K 'epoch').
+        Its range allows this implementation to represent time up to Tue Feb 7 06:28:15 2136 UTC.
+    */
+    typedef uint32_t time_t;
+
+    /**
+    The time function returns the systems current time stamp.
+    If timer is not a null pointer, the return value is also assigned to the object it points to.
+    */
+    time_t          time(time_t *timer);
+
+    /**
+    The difftime function returns the difference between two binary time stamps,
+    time1 - time0.
+    */
+    int32_t         difftime(time_t time1, time_t time0);
+
+
+    /**
+        The tm structure contains a representation of time 'broken down' into components of the
+        Gregorian calendar.
+
+        The normal ranges of the elements are..
+
+    \code
+        tm_sec      seconds after the minute - [ 0 to 59 ]
+        tm_min      minutes after the hour - [ 0 to 59 ]
+        tm_hour     hours since midnight - [ 0 to 23 ]
+        tm_mday     day of the month - [ 1 to 31 ]
+        tm_wday     days since Sunday - [ 0 to 6 ]
+        tm_mon      months since January - [ 0 to 11 ]
+        tm_year     years since 1900
+        tm_yday     days since January 1 - [ 0 to 365 ]
+        tm_isdst    Daylight Saving Time flag *
+
+    \endcode
+
+        *The value of tm_isdst is zero if Daylight Saving Time is not in effect, and is negative if
+        the information is not available.
+
+        When Daylight Saving Time is in effect, the value represents the number of
+        seconds the clock is advanced.
+
+        See the set_dst() function for more information about Daylight Saving.
+
+    */
+    struct tm {
+        int8_t          tm_sec;
+        int8_t          tm_min;
+        int8_t          tm_hour;
+        int8_t          tm_mday;
+        int8_t          tm_wday;
+        int8_t          tm_mon;
+        int16_t         tm_year;
+        int16_t         tm_yday;
+        int16_t         tm_isdst;
+    };
+
+    
+    /* We have to provide clock_t / CLOCKS_PER_SEC so that libstdc++-v3 can
+       be built.  We define CLOCKS_PER_SEC via a symbol _CLOCKS_PER_SEC_
+       so that the user can provide the value on the link line, which should
+       result in little or no run-time overhead compared with a constant.  */
+    typedef unsigned long clock_t;
+    extern char *_CLOCKS_PER_SEC_;
+#define CLOCKS_PER_SEC ((clock_t) _CLOCKS_PER_SEC_)
+    extern clock_t clock(void);
+
+    /**
+    This function 'compiles' the elements of a broken-down time structure, returning a binary time stamp.
+    The elements of timeptr are interpreted as representing Local Time.
+
+    The original values of the tm_wday and tm_yday elements of the structure are ignored,
+    and the original values of the other elements are not restricted to the ranges stated for struct tm.
+
+    On successful completion, the values of all elements of timeptr are set to the appropriate range.
+    */
+    time_t          mktime(struct tm * timeptr);
+
+    /**
+    This function 'compiles' the elements of a broken-down time structure, returning a binary time stamp.
+    The elements of timeptr are interpreted as representing UTC.
+
+    The original values of the tm_wday and tm_yday elements of the structure are ignored,
+    and the original values of the other elements are not restricted to the ranges stated for struct tm.
+
+    Unlike mktime(), this function DOES NOT modify the elements of timeptr.
+    */
+    time_t          mk_gmtime(const struct tm * timeptr);
+
+    /**
+    The gmtime function converts the time stamp pointed to by timer into broken-down time,
+    expressed as UTC.
+    */
+    struct tm      *gmtime(const time_t * timer);
+
+    /**
+        Re entrant version of gmtime().
+    */
+    void            gmtime_r(const time_t * timer, struct tm * timeptr);
+
+    /**
+    The localtime function converts the time stamp pointed to by timer into broken-down time,
+    expressed as Local time.
+    */
+    struct tm      *localtime(const time_t * timer);
+
+    /**
+        Re entrant version of localtime().
+    */
+    void            localtime_r(const time_t * timer, struct tm * timeptr);
+
+    /**
+    The asctime function converts the broken-down time of timeptr, into an ascii string in the form
+
+        Sun Mar 23 01:03:52 2013
+    */
+    char           *asctime(const struct tm * timeptr);
+
+    /**
+        Re entrant version of asctime().
+    */
+    void            asctime_r(const struct tm * timeptr, char *buf);
+
+    /**
+        The ctime function is equivalent to asctime(localtime(timer))
+    */
+    char           *ctime(const time_t * timer);
+
+    /**
+        Re entrant version of ctime().
+    */
+    void            ctime_r(const time_t * timer, char *buf);
+
+    /**
+    The isotime function constructs an ascii string in the form
+        \code2013-03-23 01:03:52\endcode
+    */
+    char           *isotime(const struct tm * tmptr);
+
+    /**
+        Re entrant version of isotime()
+    */
+    void            isotime_r(const struct tm *, char *);
+
+    /**
+    A complete description of strftime() is beyond the pale of this document.
+    Refer to ISO/IEC document 9899 for details.
+
+    All conversions are made using the 'C Locale', ignoring the E or O modifiers. Due to the lack of
+    a time zone 'name', the 'Z' conversion is also ignored.
+    */
+    size_t          strftime(char *s, size_t maxsize, const char *format, const struct tm * timeptr);
+
+    /**
+        Specify the Daylight Saving function.
+
+        The Daylight Saving function should examine its parameters to determine whether
+        Daylight Saving is in effect, and return a value appropriate for tm_isdst.
+
+        Working examples for the USA and the EU are available..
+
+            \code #include <util/eu_dst.h>\endcode
+            for the European Union, and
+            \code #include <util/usa_dst.h>\endcode
+            for the United States
+
+        If a Daylight Saving function is not specified, the system will ignore Daylight Saving.
+    */
+    void            set_dst(int (*) (const time_t *, int32_t *));
+
+    /**
+        Set the 'time zone'. The parameter is given in seconds East of the Prime Meridian.
+        Example for New York City:
+        \code set_zone(-5 * ONE_HOUR);\endcode
+
+        If the time zone is not set, the time system will operate in UTC only.
+    */
+    void            set_zone(int32_t);
+
+    /**
+        Initialize the system time. Examples are...
+
+        From a Clock / Calendar type RTC:
+        \code
+        struct tm rtc_time;
+
+        read_rtc(&rtc_time);
+        rtc_time.tm_isdst = 0;
+        set_system_time( mktime(&rtc_time) );
+        \endcode
+
+        From a Network Time Protocol time stamp:
+        \code
+        set_system_time(ntp_timestamp - NTP_OFFSET);
+        \endcode
+
+        From a UNIX time stamp:
+         \code
+        set_system_time(unix_timestamp - UNIX_OFFSET);
+        \endcode
+
+    */
+    void            set_system_time(time_t timestamp);
+
+    /**
+        Maintain the system time by calling this function at a rate of 1 Hertz.
+
+        It is anticipated that this function will typically be called from within an
+        Interrupt Service Routine, (though that is not required). It therefore includes code which
+        makes it simple to use from within a 'Naked' ISR, avoiding the cost of saving and restoring
+        all the cpu registers.
+
+        Such an ISR may resemble the following example...
+        \code
+            ISR(RTC_OVF_vect, ISR_NAKED)
+            {
+                system_tick();
+                reti();
+            }
+        \endcode
+    */
+    void            system_tick(void);
+
+    /**
+        Enumerated labels for the days of the week.
+    */
+    enum _WEEK_DAYS_ {
+        SUNDAY,
+        MONDAY,
+        TUESDAY,
+        WEDNESDAY,
+        THURSDAY,
+        FRIDAY,
+        SATURDAY
+    };
+
+    /**
+        Enumerated labels for the months.
+    */
+    enum _MONTHS_ {
+        JANUARY,
+        FEBRUARY,
+        MARCH,
+        APRIL,
+        MAY,
+        JUNE,
+        JULY,
+        AUGUST,
+        SEPTEMBER,
+        OCTOBER,
+        NOVEMBER,
+        DECEMBER
+    };
+
+    /**
+        Return 1 if year is a leap year, zero if it is not.
+    */
+    uint8_t         is_leap_year(int16_t year);
+
+    /**
+        Return the length of month, given the year and month, where month is in the range 1 to 12.
+     */
+    uint8_t         month_length(int16_t year, uint8_t month);
+
+    /**
+        Return the calendar week of year, where week 1 is considered to begin on the
+        day of week specified by 'start'. The returned value may range from zero to 52.
+    */
+    uint8_t         week_of_year(const struct tm * timeptr, uint8_t start);
+
+    /**
+        Return the calendar week of month, where the first week is considered to begin on the
+        day of week specified by 'start'. The returned value may range from zero to 5.
+    */
+    uint8_t         week_of_month(const struct tm * timeptr, uint8_t start);
+
+    /**
+        Structure which represents a date as a year, week number of that year, and day of week.
+        See http://en.wikipedia.org/wiki/ISO_week_date for more information.
+    */
+    struct week_date{
+        int year;
+        int week;
+        int day;
+    };
+
+    /**
+        Return a week_date structure with the ISO_8601 week based date corresponding to the given
+        year and day of year. See http://en.wikipedia.org/wiki/ISO_week_date for more
+        information.
+    */
+    struct week_date * iso_week_date( int year, int yday);
+
+    /**
+        Re-entrant version of iso-week_date.
+    */
+    void iso_week_date_r( int year, int yday, struct week_date *);
+
+    /**
+        Convert a Y2K time stamp into a FAT file system time stamp.
+    */
+    uint32_t        fatfs_time(const struct tm * timeptr);
+
+    /** One hour, expressed in seconds */
+#define ONE_HOUR 3600
+
+    /** Angular degree, expressed in arc seconds */
+#define ONE_DEGREE 3600
+
+    /** One day, expressed in seconds */
+#define ONE_DAY 86400
+
+    /** Difference between the Y2K and the UNIX epochs, in seconds. To convert a Y2K
+        timestamp to UNIX...
+        \code
+        long unix;
+        time_t y2k;
+
+        y2k = time(NULL);
+        unix = y2k + UNIX_OFFSET;
+        \endcode
+    */
+#define UNIX_OFFSET 946684800
+
+    /** Difference between the Y2K and the NTP epochs, in seconds. To convert a Y2K
+        timestamp to NTP...
+        \code
+        unsigned long ntp;
+        time_t y2k;
+
+        y2k = time(NULL);
+        ntp = y2k + NTP_OFFSET;
+        \endcode
+    */
+#define NTP_OFFSET 3155673600
+
+    /*
+     * ===================================================================
+     *                              Ephemera
+     */
+
+    /**
+        Set the geographic coordinates of the 'observer', for use with several of the
+        following functions. Parameters are passed as seconds of North Latitude, and seconds
+        of East Longitude.
+
+        For New York City...
+        \code set_position( 40.7142 * ONE_DEGREE, -74.0064 * ONE_DEGREE); \endcode
+    */
+    void            set_position(int32_t latitude, int32_t longitude);
+
+    /**
+        Computes the difference between apparent solar time and mean solar time.
+        The returned value is in seconds.
+    */
+    int16_t         equation_of_time(const time_t * timer);
+
+    /**
+        Computes the amount of time the sun is above the horizon, at the location of the observer.
+
+        NOTE: At observer locations inside a polar circle, this value can be zero during the winter,
+        and can exceed ONE_DAY during the summer.
+
+        The returned value is in seconds.
+    */
+    int32_t         daylight_seconds(const time_t * timer);
+
+    /**
+        Computes the time of solar noon, at the location of the observer.
+    */
+    time_t          solar_noon(const time_t * timer);
+
+    /**
+        Return the time of sunrise, at the location of the observer. See the note about daylight_seconds().
+    */
+    time_t          sun_rise(const time_t * timer);
+
+    /**
+        Return the time of sunset, at the location of the observer. See the note about daylight_seconds().
+    */
+    time_t          sun_set(const time_t * timer);
+
+    /** Returns the declination of the sun in radians. */
+    double          solar_declination(const time_t * timer);
+
+    /**
+        Returns an approximation to the phase of the moon.
+        The sign of the returned value indicates a waning or waxing phase.
+        The magnitude of the returned value indicates the percentage illumination.
+    */
+    int8_t          moon_phase(const time_t * timer);
+
+    /**
+        Returns Greenwich Mean Sidereal Time, as seconds into the sidereal day.
+        The returned value will range from 0 through 86399 seconds.
+    */
+    unsigned long   gm_sidereal(const time_t * timer);
+
+    /**
+        Returns Local Mean Sidereal Time, as seconds into the sidereal day.
+        The returned value will range from 0 through 86399 seconds.
+    */
+    unsigned long   lm_sidereal(const time_t * timer);
+
+    /* @} */
+#ifdef __cplusplus
+}
+#endif
+
+#endif              /* TIME_H  */
diff --git a/time/tm_store.c b/time/tm_store.c
new file mode 100644 (file)
index 0000000..af8229b
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: tm_store.c 2379 2013-04-30 16:42:26Z joerg_wunsch $ */
+
+/*
+       Private allocation, used by gmtime() and localtime()
+*/
+
+#include <time.h>
+
+struct tm       __tm_store;
diff --git a/time/utc_offset.c b/time/utc_offset.c
new file mode 100644 (file)
index 0000000..14c8180
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: utc_offset.c 2321 2013-04-02 00:12:48Z swfltek $ */
+
+/*
+       UTC offset in seconds East
+*/
+
+long            __utc_offset;
diff --git a/time/week_of_month.c b/time/week_of_month.c
new file mode 100644 (file)
index 0000000..6eca94f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * (c)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: week_of_month.c 2362 2013-04-26 22:22:46Z swfltek $ */
+
+/*
+       Return the week of month, where 'base' represents the starting day.
+       In the USA, the week is generally considered to start on Sunday (base = 0),
+       while in Europe it is generally considered to be Monday (base = 1).
+
+       Return value ranges from 0 to 5.
+*/
+
+#include <time.h>
+
+uint8_t
+week_of_month(const struct tm * timestruct, uint8_t base)
+{
+       int             first, n;
+
+       /* zero base the day of month */
+       n = timestruct->tm_mday - 1;
+
+       /* find the first base day of the month (start of week 1) */
+       first = 7 + n - timestruct->tm_wday + base;
+       first %= 7;
+
+       /* find days since the first week began */
+       n = n - first;
+
+       /* if negative, we are in week 0 */
+       if (n < 0)
+               return 0;
+
+       return n / 7 + 1;
+
+}
diff --git a/time/week_of_year.c b/time/week_of_year.c
new file mode 100644 (file)
index 0000000..ad06f62
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * (C)2012 Michael Duane Rice All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution. Neither the name of the copyright holders
+ * nor the names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* $Id: week_of_year.c 2362 2013-04-26 22:22:46Z swfltek $ */
+
+/*
+       Return the week of year, where 'base' represents the first day of the week.
+       In the USA, the week is generally considered to start on Sunday (base = 0),
+       while in Europe it is generally considered to be Monday (base = 1).
+
+       Return value ranges from 0 to 52.
+*/
+
+#include <time.h>
+
+uint8_t
+week_of_year(const struct tm * timestruct, uint8_t base)
+{
+       int             first, n;
+
+       /* find the first base day of the year (start of week 1) */
+       first = 7 + timestruct->tm_yday - timestruct->tm_wday + base;
+    first %= 7;
+
+       /* find days since that first base day*/
+       n = timestruct->tm_yday - first;
+
+       /* if negative, we are in week 0 */
+       if (n < 0)
+               return 0;
+
+       return n / 7 + 1;
+}
diff --git a/z180/Makefile b/z180/Makefile
new file mode 100644 (file)
index 0000000..159371f
--- /dev/null
@@ -0,0 +1,127 @@
+
+
+SRC :=  init.180 ddtz.180
+SRC += console.180
+SRC += msgbuf-a.180 conbuf-a.180
+SRC += asci1-p.180
+SRC += romend.180
+
+INC := config.inc z180reg.inc z180.lib
+
+OBJ := $(SRC:.180=.rel)
+
+#CP/M emulator
+CPMEMU = zxcc
+
+#Location of CP/M binaries
+CPMBIN = /usr/local/lib/cpm/bin80
+
+#AS = $(CPMEMU) $(CPMBIN)/m80.com
+AS = $(CPMEMU) slr180.com
+LN = $(CPMEMU) slrnk+.com
+#LN = $(CPMEMU) ccpline.com
+
+AS_OPT := MFS
+
+AS_QUIET = 1
+LN_QUIET = 1
+
+#LNKCMD =
+LN_VERB = /V
+LN_PROG = 0
+LN_DATA = C000
+
+
+.suffixes:
+#.suffixes: .180 .rel
+
+.phony: all
+all: hdrom.c hdrom.h
+
+$(OBJ):  $(INC)
+
+hdrom.h: hdrom.c
+
+comma:= ,
+empty:=
+space:= $(empty) $(empty)
+
+ccpline = $(CPMEMU) $(1) -$(subst $(space),$(comma),$(strip $(2)))
+
+define cpm-asm =
+COMMAND="$(AS) -$(basename $<)/$(AS_OPT)"; \
+OUTPUT=$$(mktemp); echo $${COMMAND}; \
+$${COMMAND} > $${OUTPUT}; \
+grep -q '^ 0 Error(s) Detected' $${OUTPUT}; ERROR=$$? ; \
+if [ "$${ERROR}" != "0" ]; then cat $${OUTPUT}; rm -f $@; fi ; \
+exit $${ERROR}
+endef
+
+define cpm-link =
+  COMMAND="$(call ccpline, slrnk+, $(basename $@)/H/M /V \
+           /P:$(LN_PROG) /D:$(LN_DATA) $(basename $^) /E /Q)";\
+  OUTPUT=$$(mktemp); echo $${COMMAND};\
+  $${COMMAND} > $${OUTPUT};\
+  ERROR=0;\
+  cat $${OUTPUT};\
+  grep -q ' Duplicate Symbol ' $${OUTPUT} && ERROR=2; \
+  grep -q '\- Previously Defined' $${OUTPUT} && ERROR=2; \
+  [ "$${ERROR}" = "0" ] && grep -q '^ ** ' $${OUTPUT} && ERROR=1 ; \
+  [ "$${ERROR}" != "0" ] && rm -f $@; \
+  exit $${ERROR}
+endef
+
+#Use:   MAKESYM Filename[.ext][/PXXXX][/DXXXX][/CXXXX]
+#egrep '^[[:xdigit:]]{4}[[:space:]]+[[:xdigit:]]{4}[[:space:]]+D.*init\.rel' hdrom.map
+define cpm-mksym =
+COMMAND="$(CPMEMU) makesym -$^ -/P -D"; \
+OUTPUT=$$(mktemp); echo $${COMMAND}; \
+$${COMMAND} > $${OUTPUT}; \
+grep -q '^ 0 Error(s) Detected' $${OUTPUT}; ERROR=$$? ; \
+if [ "$${ERROR}" != "0" ]; then cat $${OUTPUT}; rm -f $@; fi ; \
+exit $${ERROR}
+endef
+
+hdrom.c: hdrom.hex
+       srec_cat -o $@ -c_array $(basename $<) -C_COMpressed -include $< -Intel
+
+hdrom.hex : $(OBJ)
+       @#$(cpm-link)
+       ld80 -o $@ -ms $(@:.hex=.map) -P $(LN_PROG) -D $(LN_DATA) $^
+
+%.rel %.lst: %.180
+       @$(cpm-asm)
+
+hdrom.map: hdrom.hex
+
+%.sym: hdrom.map %.lst
+       @$(cpm-mksym)
+
+.phony: clean realclean
+clean:
+       rm -f $(OBJ) $(OBJ:.rel=.lst) $(OBJ:.rel=.sym) hdrom.hex
+
+realclean: clean
+       rm -f *.prn *~ hdrom.map
+
+
+#==================================================================
+
+%.REL: %.MAC
+       @COMMAND="$(AS) =$<"; \
+       OUTPUT=$$(mktemp); echo $${COMMAND}; \
+       $${COMMAND} > $${OUTPUT}; \
+       grep -q 'No Fatal error(s).$$' $${OUTPUT}; ERROR=$$? ; \
+       if [ "$${ERROR}" != "0" ]; then cat $${OUTPUT}; rm $@; fi ; \
+       rm $${OUTPUT}; \
+       exit $${ERROR}
+
+
+%.PRN: %.MAC
+       @COMMAND="$(AS) ,$@=$<"; \
+       OUTPUT=$$(mktemp); echo $${COMMAND}; \
+       $${COMMAND} > $${OUTPUT}; \
+       grep -q 'No Fatal error(s).$$' $${OUTPUT}; ERROR=$$? ; \
+       if [ "$${ERROR}" != "0" ]; then cat $${OUTPUT}; fi ; \
+       rm $${OUTPUT}; \
+       exit $${ERROR}
diff --git a/z180/Tupfile b/z180/Tupfile
new file mode 100644 (file)
index 0000000..c7d79fb
--- /dev/null
@@ -0,0 +1,58 @@
+include_rules
+
+PROG   = hdrom
+CFBOOT = cfboot
+
+SRC    = init.180
+SRC    += ddtz.180
+SRC    += msgbuf-a.180 conbuf-a.180
+#SRC   += bioscio.180 chario.180
+SRC    += console.180
+SRC    += asci-p.180
+SRC    += romend.180
+
+
+AS_OPT = MFS
+
+LN_PROG = 0
+LN_DATA = C000
+
+
+###############################################################################
+# Executables
+
+CPMEMU = zxcc
+
+#AS = $(CPMEMU) ccpline.com
+AS = $(CPMEMU) slr180.com
+
+
+###############################################################################
+
+!AS-plain = |> $(AS) -%B/$(AS_OPT) |> %B.rel | %B.lst
+
+!AS = |> ^ $(AS) -%B/$(AS_OPT)^ set +e; OUTPUT=\$(mktemp);\
+$(AS) -%B/$(AS_OPT) > ${OUTPUT};\
+grep -q '^ 0 Error(s) Detected' ${OUTPUT}; ERROR=$?;\
+[ "${ERROR}" != "0" ] && cat ${OUTPUT};\
+[ "${ERROR}" != "0" ] && rm -f %B.rel;\
+rm -f ${OUTPUT}; exit ${ERROR} \
+|> %B.rel | %B.lst
+
+#!LINK = |> ld80 -o %o -ms %O.map -P $(LN_PROG) -D $(LN_DATA) %f |> | %O.map
+!LINK = |> ld80 -o %o -ms %O.map -P $(LN_PROG) %f |> | %O.map
+
+#ifndef DEBUG
+
+: foreach $(SRC) |> !AS |> {objs}
+: {objs} |> !LINK |> $(PROG).hex
+: $(PROG).hex |> srec_cat -o %o -c_array %B -C_COMpressed -include %f -Intel |> $(PROG).c | $(PROG).h
+
+
+: $(CFBOOT).180 |> $(AS) -%B/HFS |> %B.hex | %B.lst
+: $(CFBOOT).hex |> srec_cat -o %o -c_array %B -C_COMpressed -include %f -Intel |> $(CFBOOT).c | $(CFBOOT).h
+
+#COMMAND="$(AS) -%B/$(AS_OPT)"; \
+
+
+#endif
diff --git a/z180/asci-p.180 b/z180/asci-p.180
new file mode 100644 (file)
index 0000000..956faf1
--- /dev/null
@@ -0,0 +1,133 @@
+       page    200\r
+\r
+       extrn   ioiniml\r
+\r
+       global  as0init\r
+       global  as0ista,as0inp\r
+       global  as0osta,as0out\r
+       global  as1init\r
+       global  as1ista,as1inp\r
+       global  as1osta,as1out\r
+\r
+       include config.inc\r
+       include z180reg.inc\r
+\r
+\r
+;-----------------------------------------------------\r
+;\r
+;\r
+; TC = (f PHI /(2*baudrate*Clock_mode)) - 2\r
+;\r
+; TC = (f PHI / (32 * baudrate)) - 2\r
+;\r
+\r
+       cseg\r
+;\r
+; Init Serial I/O for console input and output (ASCI1)\r
+;\r
+       \r
+\r
+\r
+as0init:\r
+       ld      hl,initab0\r
+       jp      ioiniml\r
+\r
+as1init:\r
+       ld      hl,initab1\r
+       jp      ioiniml\r
+\r
+               \r
+       ld      a,M_MPBT \r
+       out0    (cntlb1),a\r
+       ld      a,M_RE + M_TE + M_MOD2  ;Rx/Tx enable \r
+       out0    (cntla1),a\r
+       ld      a,M_RIE\r
+       out0    (stat1),a       ;Enable rx interrupts\r
+\r
+       ret                     ;\r
+\r
+\r
+initab0:\r
+       db      1,stat0,0               ;Disable rx/tx interrupts\r
+                                       ;Enable baud rate generator\r
+       db      1,asext0,M_BRGMOD+M_DCD0DIS+M_CTS0DIS\r
+       db      2,astc0l,low 28, high 28\r
+       db      1,cntlb0,M_MPBT         ;No MP Mode, X16\r
+       db      1,cntla0,M_RE+M_TE+M_MOD2 ;Rx/Tx enable, 8N1\r
+       db      0\r
+\r
+initab1:\r
+       db      1,stat1,0               ;Disable rx/tx ints, disable CTS1\r
+       db      1,asext1,M_BRGMOD       ;Enable baud rate generator\r
+       db      2,astc1l,low 3, high 3\r
+       db      1,cntlb1,M_MPBT         ;No MP Mode, X16\r
+       db      1,cntla1,M_RE+M_TE+M_MOD2 ;Rx/Tx enable, 8N1\r
+       db      0\r
+\r
+\r
+\r
+as0ista:\r
+       in0     a,(stat0)\r
+       and     M_RDRF\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+       \r
+as1ista:\r
+       in0     a,(stat1)\r
+       and     M_RDRF\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+       \r
+\r
+as0inp:\r
+       in0     a,(stat0)\r
+       rlca\r
+       jr      nc,as0inp\r
+       in0     a,rdr0\r
+       ret\r
+\r
+as1inp:\r
+       in0     a,(stat1)\r
+       rlca\r
+       jr      nc,as1inp\r
+       in0     a,rdr1\r
+       ret\r
+\r
+\r
+\r
+as0osta:\r
+       in0     a,(stat0)\r
+       and     M_TDRE\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+as1osta:\r
+       in0     a,(stat1)\r
+       and     M_TDRE\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+\r
+as0out:\r
+       in0     a,(stat0)\r
+       and     M_TDRE\r
+       jr      z,as0out\r
+       out0    (tdr0),c\r
+       ld      a,c\r
+       ret\r
+\r
+as1out:\r
+       in0     a,(stat1)\r
+       and     M_TDRE\r
+       jr      z,as1out\r
+       out0    (tdr1),c\r
+       ld      a,c\r
+       ret\r
+\r
+       end\r
+\r
+\r
diff --git a/z180/asci1-i.180 b/z180/asci1-i.180
new file mode 100644 (file)
index 0000000..15e121a
--- /dev/null
@@ -0,0 +1,256 @@
+       page    200\r
+\r
+\r
+       extrn   buf.init\r
+       extrn   isv_sw\r
+\r
+\r
+       global  ser.init\r
+       global  ser.ist,ser.in\r
+       global  ser.ost,ser.out\r
+\r
+;TODO: define a trampoline area somewhere in top ram.\r
+rtxisvjmp      equ     0FF60h  ;momentan frei...\r
+\r
+       include config.inc\r
+       include z180reg.inc\r
+\r
+\r
+;-----------------------------------------------------\r
+\r
+       dseg\r
+\r
+buf_start:\r
+       mkbuf   s1.rx_id, ser1.inbuf, s1.rx_len\r
+       mkbuf   s1.tx_id, ser1.outbuf, s1.tx_len\r
+buf_end:\r
+\r
+\r
+\r
+;-----------------------------------------------------\r
+\r
+       cseg\r
+;\r
+; Init Serial I/O for console input and output (ASCI1)\r
+;\r
+\r
+\r
+ser.init:\r
+;      ld      a,i\r
+;      push    af              ;save IFF\r
+;      di\r
+\r
+       xor     a               ;\r
+       out0    (stat1),a       ;Disable rx/tx interrupts\r
+\r
+       ld hl,rxtx_src          ;move rx and tx isv to common ram\r
+       ld de,rxtx_dst          ;\r
+       ld bc,rxtx_src_e-rxtx_src ;\r
+       ldir                    ;\r
+\r
+       ld hl,rtxisvjmp         ;rx/tx int vector\r
+       ld (ivtab + IV$ASCI1),hl;\r
+       ld a,0cdh               ;\r
+       ld (rtxisvjmp),a        ;\r
+       ld hl,isv_sw            ;\r
+       ld (rtxisvjmp + 1),hl   ;\r
+       ld hl,rxtxisv           ;\r
+       ld (rtxisvjmp + 3),hl   ;\r
+\r
+; ASCI1: 8N1, highest baudrate (56700), CTS disabled\r
+\r
+       ld      a,M_MPBT\r
+       out0    (cntlb1),a\r
+       ld      a,M_RE + M_TE + M_MOD2\r
+       out0    (cntla1),a\r
+       ld      a,M_RIE\r
+       out0    (stat1),a       ;Enable rx interrupts\r
+\r
+       ld      ix,ser1.inbuf\r
+       ld      a,ser1.inbuf.mask\r
+       call    buf.init\r
+       ld      ix,ser1.outbuf\r
+       ld      a,ser1.outbuf.mask\r
+       call    buf.init\r
+\r
+;      pop     af\r
+;      ret     po\r
+;      ei\r
+       ret                     ;\r
+\r
+ser.ist:\r
+       push    ix\r
+       ld      ix,ser1.inbuf   ;\r
+\r
+buf.empty:\r
+       ld      a,(ix+o.in_idx) ;\r
+       sub     (ix+o.out_idx)  ;\r
+       pop     ix\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+ser.in:\r
+       push    hl                      ;11\r
+       push    de                      ;11\r
+       ld      hl,ser1.inbuf-1         ; 9     hl = &rx.out_idx\r
+       ld      a,(hl)                  ; 6     a = rx.out_idx\r
+       dec     hl                      ; 4     hl = &rx.in_idx\r
+       jr      bg.w1\r
+bg.wait:\r
+       halt\r
+bg.w1:\r
+       cp      (hl)                    ; 6     while (out_idx==in_idx)\r
+       jr      z,bg.wait               ; 6 (/8)        ;\r
+\r
+       ld      e,a                     ; 4\r
+       ld      d,0                     ; 6\r
+       inc     de\r
+       inc     de\r
+\r
+       ex      de,hl                   ; 3\r
+       add     hl,de                   ;10\r
+       ld      l,(hl)                  ; 6\r
+       ex      de,hl                   ; 3\r
+\r
+       inc     a                       ; 4\r
+       dec     hl                      ; 4\r
+       and     (hl)                    ; 6\r
+       inc     hl                      ; 4\r
+       inc     hl                      ; 4\r
+       ld      (hl),a                  ; 7\r
+\r
+       ld      a,e                     ; 4\r
+       pop     de                      ; 9\r
+       pop     hl                      ; 9\r
+       ret                             ; 9\r
+                                       ;   153\r
+\r
+ser.ost:\r
+       push    ix\r
+       ld      ix,ser1.outbuf          ;\r
+buf.full:\r
+       ld      a,(ix+o.in_idx)         ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       sub     (ix+o.out_idx)          ;\r
+       pop     ix\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+\r
+ser.out:\r
+       push    ix\r
+       ld      ix,ser1.outbuf          ;\r
+buf.put:\r
+       push    hl                      ;\r
+       push    bc\r
+       push    ix\r
+       pop     hl\r
+       ld      a,c\r
+       ld      c,(ix+o.in_idx)         ;\r
+       ld      b,0\r
+       add     hl,bc\r
+       ld      (hl),a\r
+\r
+       ld      a,c                     ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+bp.wait:\r
+       cp      (ix+o.out_idx)          ;\r
+       jr      z,bp.wait\r
+       ld      (ix+o.in_idx),a\r
+\r
+       di                      ;036f\r
+       in0     a,(stat1)       ;0374\r
+       set     TIE,a           ;0377\r
+       out0    (stat1),a       ;0379\r
+       ei                      ;037c\r
+\r
+       ld      a,b\r
+       pop     bc\r
+       pop     hl\r
+       pop     ix\r
+       ret\r
+\r
+\r
+;------------------------------------------\r
+; ASCI 1 Transmit/Receive interupt routines\r
+; moved to common ram\r
+\r
+rxtx_src:\r
+       dseg\r
+rxtx_dst:                              ; (0c097h)  old\r
+\r
+rxtxisv:\r
+       inidat\r
+       in0 a,(stat1)                   ;receive flag set?\r
+       jp p,txisv                      ;\r
+\r
+       in0     d,(rdr1)                ;todo: break detection\r
+       bit     FE,a                    ;framing error?\r
+       jr      nz,??ri_1\r
+\r
+       push    ix\r
+       ld      ix,ser1.inbuf           ;\r
+       ld      hl,ser1.inbuf           ;\r
+       ld      c,(ix+o.in_idx)         ;\r
+       ld      b,0\r
+       add     hl,bc\r
+\r
+       ld      a,c                     ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       cp      (ix+o.out_idx)          ;\r
+       jr      z,??ri_0\r
+       ld      (hl),d\r
+       ld      (ix+o.in_idx),a\r
+??ri_0:\r
+       pop     ix\r
+??ri_1:\r
+       in0     a,(cntla1)              ;0705   c0c0\r
+       res     EFR,a                   ;0708\r
+       out0    (cntla1),a              ;070a\r
+       ret\r
+\r
+       inidate\r
+\r
+txisv:\r
+       inidat\r
+       push    ix\r
+       ld      ix,ser1.outbuf          ;\r
+\r
+       ld      a,(ix+o.out_idx)        ;\r
+       cp      (ix+o.in_idx)           ;\r
+       jr      z,??ti_2\r
+\r
+       ld      hl,ser1.outbuf          ;\r
+       add     a,l\r
+       ld      l,a\r
+       jr      nc,??ti_1\r
+       inc     h\r
+??ti_1:\r
+       ld      l,(hl)\r
+       out0    (tdr1),l                ;071b\r
+\r
+       ld      a,(ix+o.out_idx)        ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       ld      (ix+o.out_idx),a\r
+       jr      ??ti_3\r
+??ti_2:\r
+       in0     a,(stat1)               ;0730   disable tx-int\r
+       res     TIE,a                   ;0733\r
+       out0    (stat1),a               ;0735\r
+??ti_3:\r
+       pop     ix\r
+       ret\r
+\r
+       inidate\r
+\r
+       cseg\r
+rxtx_src_e:\r
+\r
+\r
+       end\r
diff --git a/z180/bioscio.180 b/z180/bioscio.180
new file mode 100644 (file)
index 0000000..2d8e5e0
--- /dev/null
@@ -0,0 +1,326 @@
+\r
+       .z80\r
+\r
+;                Copyright (C), 1982\r
+;               Digital Research, Inc\r
+;                   P.O. Box 579\r
+;              Pacific Grove, CA  93950\r
+\r
+;   This is the invariant portion of the modular BIOS and is\r
+;      distributed as source for informational purposes only.\r
+;      All desired modifications should be performed by\r
+;      adding or changing externally defined modules.\r
+;      This allows producing "standard" I/O modules that\r
+;      can be combined to support a particular system\r
+;      configuration.\r
+;\r
+;   Modified for faster character I/O by Udo Munk\r
+\r
+cr     equ     13\r
+lf     equ     10\r
+bell   equ     7\r
+ctlQ   equ     'Q'-'@'\r
+ctlS   equ     'S'-'@'\r
+\r
+       cseg                    ; GENCPM puts CSEG stuff in common memory\r
+\r
+       ; variables in system data page\r
+\r
+;;     extrn   @covec,@civec,@aovec,@aivec,@lovec ; I/O redirection vectors\r
+                               \r
+       ; user defined character I/O routines\r
+\r
+       extrn   ?ci,?co,?cist,?cost     ; each take device in <B>\r
+       extrn   ?cinit                  ; (re)initialize device in <C>\r
+       extrn   @ctbl                   ; physical character device table\r
+\r
+\r
+       include modebaud.inc    ; define mode bits\r
+\r
+\r
+       public  @covec,@civec,@aovec,@aivec,@lovec ; I/O redirection vectors\r
+       public  ?const,?conin,?cono,?list,?auxo,?auxi\r
+       public  ?lists,?conos,?auxis,?auxos,?dvtbl,charini\r
+\r
+\r
+@CIVEC:        dw      0               ; Console Input Redirection\r
+                               ; Vector (word, r/w)\r
+@COVEC:        dw      0               ; Console Output Redirection\r
+                               ; Vector (word, r/w)\r
+@AIVEC:        dw      0               ; Auxiliary Input Redirection\r
+                               ; Vector (word, r/w)\r
+@AOVEC:        dw      0               ; Auxiliary Output Redirection\r
+                               ; Vector (word, r/w)\r
+@LOVEC:        dw      0               ; List Output Redirection\r
+                               ; Vector (word, r/w)\r
+\r
+\r
+charini:\r
+\r
+       ld      c,15            ; initialize all 16 character devices\r
+c$init$loop:\r
+       push    bc\r
+       call    ?cinit\r
+       pop     bc\r
+       dec     c\r
+       jp      p,c$init$loop\r
+\r
+;      ld      hl,1000000000000000b    ; assign console to HOST\r
+       ld      hl,0010000000000000b    ; assign console to ASCI1\r
+       ld      (@civec),hl\r
+       ld      (@covec),hl\r
+       ld      hl,0000000000000000b    ; assign auxiliary to nothing\r
+       ld      (@aivec),hl\r
+       ld      (@aovec),hl\r
+       ld      hl,0000000000000000b    ; assign printer to nothing\r
+       ld      (@lovec),hl\r
+       ret\r
+\r
+\r
+       ; DEVTBL\r
+       ;       Return address of character device table\r
+\r
+?dvtbl:\r
+devtbl:\r
+       ld      hl,@ctbl\r
+       ret\r
+\r
+\r
+       ; CONOUT\r
+       ;       Console Output. Send character in <C>\r
+       ;                       to all selected devices\r
+\r
+?cono:\r
+conout:\r
+       ld      hl,(@covec)     ; fetch console output bit vector\r
+       jr      out$scan\r
+\r
+\r
+       ; AUXOUT\r
+       ;       Auxiliary Output. Send character in <C>\r
+       ;                       to all selected devices\r
+\r
+?auxo:\r
+auxout:\r
+       ld      hl,(@aovec)     ; fetch aux output bit vector\r
+       jr      out$scan\r
+\r
+\r
+       ; LIST\r
+       ;       List Output. Send character in <C>\r
+       ;                       to all selected devices.\r
+\r
+?list:\r
+list:\r
+       ld      hl,(@lovec)     ; fetch list output bit vector\r
+\r
+out$scan:\r
+       ld      b,0             ; start with device 0\r
+co$next:\r
+       add     hl,hl           ; shift out next bit\r
+       jr      nc,not$out$device\r
+       push    hl              ; save the vector\r
+       push    bc              ; save the count and character\r
+       call    ?co             ; if device selected, print it\r
+       pop     bc              ; recover count and character\r
+       pop     hl              ; recover the rest of the vector\r
+not$out$device:\r
+       inc     b               ; next device number\r
+       ld      a,h\r
+       or      l               ; see if any devices left\r
+       jr      nz,co$next      ; and go find them...\r
+       ret\r
+\r
+\r
+       ; CONOST\r
+       ;       Console Output Status. Return true if\r
+       ;               all selected console output devices\r
+       ;               are ready.\r
+\r
+?conos:\r
+conost:\r
+       ld      hl,(@covec)     ; get console output bit vector\r
+       jr      ost$scan\r
+\r
+\r
+       ; AUXOST\r
+       ;       Auxiliary Output Status. Return true if\r
+       ;               all selected auxiliary output devices\r
+       ;               are ready.\r
+\r
+?auxos:\r
+auxost:\r
+       ld      hl,(@aovec)     ; get aux output bit vector\r
+       jr      ost$scan\r
+\r
+\r
+       ; LISTST\r
+       ;       List Output Status. Return true if\r
+       ;               all selected list output devices\r
+       ;               are ready.\r
+\r
+?lists:\r
+listst:\r
+       ld      hl,(@lovec)     ; get list output bit vector\r
+\r
+ost$scan:\r
+       ld      b,0             ; start with device 0\r
+cos$next:\r
+       add     hl,hl           ; check next bit\r
+       push    hl              ; save the vector\r
+       push    bc              ; save the count\r
+       ld      a,0FFh          ; assume device ready\r
+       call    c,coster        ; check status for this device\r
+       pop     bc              ; recover count\r
+       pop     hl              ; recover bit vector\r
+       or      a               ; see if device ready\r
+       ret     z               ; if any not ready, return false\r
+       inc     b               ; drop device number\r
+       ld      a,h\r
+       or      l               ; see if any more selected devices\r
+       jr      nz,cos$next\r
+       or      0FFh            ; all selected were ready, return true\r
+       ret\r
+\r
+coster:                ; check for output device ready, including optional\r
+               ;       xon/xoff support\r
+               ;\r
+               ;TODO: interrupt driven devices should xon/xoff handle\r
+               ;       in isv\r
+\r
+       ld      l,b\r
+       ld      h,0             ; make device code 16 bits\r
+       push    hl              ; save it in stack\r
+       add     hl,hl\r
+       add     hl,hl\r
+       add     hl,hl           ; create offset into device characteristics tbl\r
+       ld      de,@ctbl+6\r
+       add     hl,de           ; make address of mode byte\r
+       ld      a,(hl)\r
+       and     mb$xon$xoff\r
+       pop     hl              ; recover console number in <HL>\r
+       jp      z,?cost         ; not a xon device, go get output status direct\r
+       ld      de,xofflist\r
+       add     hl,de           ; make pointer to proper xon/xoff flag\r
+       call    cist1           ; see if this keyboard has character\r
+       ld      a,(hl)\r
+       call    nz,ci1          ; get flag or read key if any\r
+       cp      ctlq\r
+       jr      nz,not$q        ; if its a ctl-Q,\r
+       ld      a,0FFh          ;       set the flag ready\r
+not$q:\r
+       cp      ctls\r
+       jr      nz,not$s        ; if its a ctl-S,\r
+       ld      a,00h           ;       clear the flag\r
+not$s:\r
+       ld      (hl),a          ; save the flag\r
+       call    cost1           ; get the actual output status,\r
+       and     (hl)            ; and mask with ctl-Q/ctl-S flag\r
+       ret                     ; return this as the status\r
+\r
+cist1:         ; get input status with <BC> and <HL> saved\r
+       push    bc\r
+       push    hl\r
+       call    ?cist\r
+       pop     hl\r
+       pop     bc\r
+       or      a\r
+       ret\r
+\r
+cost1:         ; get output status, saving <BC> & <HL>\r
+       push    bc\r
+       push    hl\r
+       call    ?cost\r
+       pop     hl\r
+       pop     bc\r
+       or      a\r
+       ret\r
+\r
+ci1:           ; get input, saving <BC> & <HL>\r
+       push    bc\r
+       push    hl\r
+       call    ?ci\r
+       pop     hl\r
+       pop     bc\r
+       ret\r
+\r
+\r
+       ; AUXIST\r
+       ;       Auxiliary Input Status. Return true if\r
+       ;               any selected auxiliary input device\r
+       ;               has an available character.\r
+?auxis:\r
+auxist:\r
+       ld      hl,(@aivec)     ; get aux input bit vector\r
+       jr      ist$scan\r
+\r
+\r
+       ; CONST\r
+       ;       Console Input Status. Return true if\r
+       ;               any selected console input device\r
+       ;               has an available character.\r
+?const:\r
+const:\r
+       ld      hl,(@civec)     ; get console input bit vector\r
+\r
+\r
+ist$scan:\r
+       ld      b,0             ; start with device 0\r
+cis$next:\r
+       add     hl,hl           ; check next bit\r
+       ld      a,0             ; assume device not ready\r
+       call    c,cist1         ; check status for this device\r
+       or      a\r
+       ret     nz              ; if any ready, return true\r
+       inc     b               ; next device number\r
+       ld      a,h\r
+       or      l               ; see if any more selected devices\r
+       jr      nz,cis$next\r
+       xor     a               ; all selected were not ready, return false\r
+       ret\r
+\r
+\r
+       ; AUXIN\r
+       ;       Auxiliary Input. Return character from first\r
+       ;               ready auxiliary input device.\r
+?auxi:\r
+auxin:\r
+       ld      hl,(@aivec)\r
+       jr      in$scan\r
+\r
+\r
+       ; CONIN\r
+       ;       Console Input. Return character from first\r
+       ;               ready console input device.\r
+?conin:\r
+conin:\r
+       ld      hl,(@civec)\r
+\r
+in$scan:\r
+       push    hl              ; save bit vector\r
+       ld      b,0\r
+ci$next:\r
+       add     hl,hl           ; shift out next bit\r
+       ld      a,0             ; insure zero a (nonexistant device not ready).\r
+       call    c,cist1         ; see if the device has a character\r
+       or      a\r
+       jr      nz,ci$rdy       ; this device has a character\r
+       inc     b               ; else, next device\r
+       ld      a,h\r
+       or      l               ; see if any more devices\r
+       jr      nz,ci$next      ; go look at them\r
+       pop     hl              ; recover bit vector\r
+       jr      in$scan         ; loop til we find a character\r
+ci$rdy:\r
+       pop     hl              ; discard extra stack\r
+       jp      ?ci\r
+\r
+\r
+\r
+xofflist:\r
+       db      -1,-1,-1,-1,-1,-1,-1,-1 ; ctl-s clears to zero\r
+       db      -1,-1,-1,-1,-1,-1,-1,-1\r
+\r
+\r
+       end\r
+\r
diff --git a/z180/cfboot.180 b/z180/cfboot.180
new file mode 100644 (file)
index 0000000..083aa4c
--- /dev/null
@@ -0,0 +1,352 @@
+       TITLE 'CF cold boot loader'\r
+\r
+    ; Port Address Equates\r
+\r
+       include config.inc\r
+       include z180reg.inc\r
+\r
+    ; IDE Task File Register Definitions\r
+\r
+IDEDat equ     IDEBASE+0       ; Data Register\r
+IDEErr equ     IDEBASE+1       ; Error Register\r
+IDEFeat        equ     IDEBASE+1       ; Feature Register\r
+IDESCnt        equ     IDEBASE+2       ; Sector Count\r
+IDESNum        equ     IDEBASE+3       ; Sector Number\r
+IDECLo equ     IDEBASE+4       ; Cylinder Low\r
+IDECHi equ     IDEBASE+5       ; Cylinder High\r
+IDESDH equ     IDEBASE+6       ; Drive and Head\r
+IDECmd equ     IDEBASE+7       ; Command / Status\r
+\r
+    ; IDE Hard disk commands:\r
+\r
+CmdNOP equ     00h             ; NOP Command\r
+CmdHome        equ     10h             ; Recalibrate\r
+CmdRd  equ     20h             ; Read Sector\r
+CmdWr  equ     30h             ; Write Sector\r
+CmdId  equ     0ECh            ; Read ID\r
+CmdSF  equ     0EFh            ; Set Feature\r
+\r
+    ; Partition Table Structures\r
+\r
+PTYPE  equ     4\r
+PSTART equ     8\r
+PSIZE  equ     12\r
+\r
+    ; Partition table id\r
+    ; (see http://www.win.tue.nl/~aeb/partitions/partition_types-1.html)\r
+\r
+PARTID1_FAT16  equ     00EH\r
+PARTID2_FAT16  equ     006H\r
+PARTID_CPM     equ     052H\r
+\r
+\r
+DEBUG          equ     false           ; not used\r
+DO_WAIT_NBSY   equ     false\r
+RUN_TPA                equ     false\r
+\r
+   if RUN_TPA\r
+base           equ     0100h\r
+   else\r
+base           equ     0\r
+   endif\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+       aseg\r
+\r
+       org     base\r
+\r
+       jr      start\r
+\r
+para:          equ     $\r
+loadaddr:      dw      base+100h\r
+sec_start:     db      0\r
+sec_cnt:       db      7\r
+part_id:       db      PARTID_CPM\r
+timeout:       dw      10000\r
+stages:                db      number_of_stages\r
+done:          db      0\r
+result:                db      0\r
+ide_result:    db      0,0\r
+\r
+o_part_id      equ     part_id - para\r
+o_stages       equ     stages - para\r
+o_done         equ     done    - para\r
+o_result       equ     result  - para\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+start:\r
+       ld      sp,stack\r
+       pop     ix\r
+       pop     de\r
+loop:\r
+       dec     (ix+o_stages)\r
+       jp      m,stop\r
+\r
+       pop     hl\r
+       push    de\r
+       push    hl\r
+       exx\r
+       ld      hl,(loadaddr)\r
+       ret\r
+continue:\r
+       exx\r
+       ld      (ix+o_result),a\r
+       or      a\r
+       jr      z,loop\r
+stop:\r
+       in      a,(Idecmd)      ;2\r
+       ld      l,a             ;1\r
+       in      a,(IdeErr)      ;2\r
+       ld      h,a             ;1\r
+       ld      (ide_result),hl ;3      9\r
+       dec     (ix+o_done)\r
+       halt\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+chk_to:\r
+       xor     a       ;\r
+to_l:\r
+       dec     a\r
+       ex      (sp),hl\r
+       ex      (sp),hl\r
+       jr      nz,to_l ;\r
+       dec     hl      ; 4\r
+       ld      a,h     ; 4\r
+       or      l       ; 4\r
+       ret     nz      ; 10/5\r
+       ccf             ; 3\r
+       ret             ; 9\r
+\r
+   if base = 0\r
+     if 044h-$ > 0\r
+       rept    044h-$\r
+       db      0\r
+       endm\r
+     endif\r
+   endif\r
+\r
+part_start:\r
+;      dw      0\r
+;      dw      0       ; part_start is 4 byte long, but stack gets free\r
+stack:\r
+       dw      para\r
+       dw      continue\r
+stage_table:\r
+   if  DO_WAIT_NBSY\r
+       dw      s_wait_not_bsy\r
+   endif\r
+       dw      s_wait_rdy\r
+       dw      s_check_io\r
+       dw      s_set_xfermode8\r
+       dw      s_read_parttbl\r
+       dw      s_check_signature\r
+       dw      s_find_partition\r
+       dw      s_read_sectors\r
+       dw      s_go\r
+number_of_stages equ ($-stage_table)/2\r
+\r
+   if  DO_WAIT_NBSY\r
+;-------------------------------------------------------------------------------\r
+; Wait while device is busy with time out\r
+;     return:\r
+;       a = 0 if ok\r
+;       a = ff in timeout\r
+;     destroys hl\r
+\r
+s_wait_not_bsy:\r
+       ld      hl,(timeout)\r
+wnb_l:\r
+       in      a,(IdeCmd)\r
+       rla\r
+       jr      nc,wnb_e\r
+       call    chk_to\r
+       jr      nc,wnb_l\r
+wnb_e:\r
+       sbc     a,a\r
+       ret\r
+   endif\r
+\r
+;-------------------------------------------------------------------------------\r
+; Wait for ready signal with time out\r
+;     return:\r
+;       a = 0 if ok\r
+;       a = ff in timeout\r
+;     destroys hl\r
+\r
+s_wait_rdy:\r
+wait_rdy_to:\r
+       ld      hl,(timeout)\r
+wrdy_l:\r
+       in      a,(IdeCmd)\r
+       xor     01000000b\r
+       and     11000000b       ; clears carry\r
+       jr      z,wrdy_e\r
+       call    chk_to\r
+       jr      nc,wrdy_l\r
+wrdy_e:\r
+       sbc     a,a\r
+       ret\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+s_check_io:\r
+       ld      a,0E0h          ; unit 0, lba mode\r
+       out     (IdeSDH),a      ;\r
+\r
+       xor     a               ; execute NOP command\r
+       call    do_ide_cmd      ; should return error\r
+       ret     c\r
+       xor     1\r
+       ret     nz\r
+       ld      a,CmdHome       ; execute RECALIBRATE command\r
+       jr      do_ide_cmd\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+s_set_xfermode8:\r
+       ld      a,1             ; Enable 8-bit data transfer.\r
+       out     (IDEFeat),a\r
+       ld      a,CmdSF         ; Set feature command\r
+\r
+;      fall thru\r
+;      jr      do_ide_cmd\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+do_ide_cmd:\r
+       out     (IdeCmd),a      ;\r
+       call    wait_rdy_to\r
+       ret     c\r
+       in      a,(IdeCmd)\r
+       and     10001001b       ;\r
+       ret\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+s_check_signature:\r
+;      ld      hl,(loadaddr)\r
+       inc     h               ; Point to last byte of MBR\r
+       inc     h\r
+       dec     hl\r
+       ld      a,0aah\r
+       cp      (hl)                    ; Test, if it has a valid MBR\r
+       ret     nz\r
+       dec     hl\r
+       cpl                             ; a=055h\r
+       sub     (hl)                    ;\r
+       ret                             ; should be 0\r
+\r
+;-------------------------------------------------------------------------------\r
+; Read partition table (lbr)\r
+\r
+s_read_parttbl:\r
+;      ld      hl,(loadaddr)\r
+       ld      bc,1*256 + 0    ; sector 0 (lba)\r
+       ld      e,c\r
+       ld      d,c\r
+       jr      read_sectors\r
+\r
+;-------------------------------------------------------------------------------\r
+; Find CP/M paartition\r
+;      Look for first CP/M partition\r
+;      and save partition offset\r
+\r
+s_find_partition:\r
+;      ld      hl,(loadaddr)\r
+       ld      de,512-2-64+PTYPE       ; Point to  partition type of first first partition table entry\r
+       add     hl,de\r
+       ld      de,16\r
+       ld      b,4                     ; Max # of partition table entries\r
+ploop:\r
+       ld      a,(ix+o_part_id)\r
+       sub     (HL)                    ; Test for CP/M Partition\r
+       jr      nz,pnext\r
+       ld      bc,4\r
+       add     hl,bc                   ; Point to partition start (lba)\r
+       ld      de,part_start\r
+       ldir\r
+       ret                             ;a=0\r
+pnext:\r
+       add     hl,de\r
+       djnz    ploop\r
+       ret\r
+\r
+\r
+;-------------------------------------------------------------------------------\r
+; Read sec_count sectors, beginning at part_start+sec_start\r
+\r
+s_read_sectors:\r
+;      ld      hl,(loadaddr)\r
+       push    hl\r
+       ld      bc,(sec_start)          ;b=sec_count, c=sec_start\r
+       ld      e,c\r
+       ld      d,0\r
+       ld      hl,(part_start)         ;add partition offset to sector number\r
+       add     hl,de\r
+       ld      a,(part_start+2)\r
+       adc     a,d                     ;d=0\r
+       ld      c,a\r
+       ex      de,hl\r
+       pop     hl\r
+\r
+;      fall thru\r
+\r
+;-------------------------------------------------------------------------------\r
+; Read a number of sectors\r
+;      hl:  memory address\r
+;      cde: sector number (24 bit)\r
+;      b:   sector count\r
+\r
+read_sectors:\r
+       ld      a,e             ; lba 0..7\r
+       out     (IdeSNum),a\r
+       ld      a,d             ; lba 0..7\r
+       out     (IdeClo),a\r
+       ld      a,c             ; lba 0..7\r
+       out     (IdeCHi),a\r
+       ld      a,b             ; number of sectors to read\r
+       out     (IdeSCnt),a     ; set sector count\r
+\r
+       ld      a,CmdRd\r
+       out     (IdeCmd),a      ; command: read sector data\r
+       ld      d,b\r
+       ld      bc,IdeDat       ; I/O address\r
+wdrq:\r
+       in      a,(IdeCmd)      ; wait for DRQ to become active\r
+       bit     3,a\r
+       jr      z,wdrq\r
+       inir                    ; read 512 data bytes (2 x 256)\r
+       inir\r
+wnb:                           ; wait while busy\r
+       in      a,(IdeCmd)      ;\r
+       rlca\r
+       jr      c,wnb\r
+       rrca                    ; restore status\r
+       bit     0,a\r
+       jr      nz,err_out\r
+       dec     d\r
+       jr      nz,wdrq\r
+err_out:\r
+       and     10001001b       ; Busy, DRQ, or Error?\r
+       ret                     ; return 0, if everything is ok\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+s_go:\r
+;      ld      hl,(loadaddr)\r
+       dec     (ix+o_done)\r
+       jp      (hl)\r
+\r
+\r
+;-------------------------------------------------------------------------------\r
+   if base = 0\r
+     if $ > 100h\r
+       .printx Error: Program to large to fit in page 0!\r
+       db "Stop\r
+     endif\r
+   endif\r
+\r
+       end\r
diff --git a/z180/chario.180 b/z180/chario.180
new file mode 100644 (file)
index 0000000..4d37b89
--- /dev/null
@@ -0,0 +1,113 @@
+       page    255\r
+       .z80\r
+\r
+\r
+;      CP/M 3  compatible character i/o\r
+\r
+       public  ?cinit,?ci,?co,?cist,?cost\r
+       public  @ctbl\r
+\r
+       extrn   ff.init,ff.i.st,ff.in,ff.o.st,ff.out\r
+       extrn   as0init,as0ista,as0inp,as0osta,as0out\r
+       extrn   as1init,as1ista,as1inp,as1osta,as1out\r
+\r
+       include config.inc\r
+       include z180reg.inc\r
+       include modebaud.inc    ; define mode bits and baud eqautes\r
+\r
+\r
+max$device     equ 3\r
+\r
+       cseg\r
+\r
+; c = device\r
+\r
+?cinit:                                ; init devices\r
+       ld      b,c\r
+       call    vector$io\r
+       dw      ff.init\r
+       dw      as0init\r
+       dw      as1init\r
+       dw      rret\r
+\r
+; b = device, c = output char, a = input char\r
+\r
+?ci:                           ; character input\r
+       call    vector$io\r
+       dw      ff.in\r
+       dw      as0inp\r
+       dw      as1inp\r
+       dw      null$input\r
+\r
+?cist:                         ; character input status\r
+       call    vector$io\r
+       dw      ff.i.st\r
+       dw      as0ista\r
+       dw      as1ista\r
+       dw      null$status\r
+\r
+?co:                           ; character output\r
+       call    vector$io\r
+       dw      ff.out\r
+       dw      as0out\r
+       dw      as1out\r
+       dw      rret\r
+\r
+?cost:                         ; character output status\r
+       call    vector$io\r
+       dw      ff.o.st\r
+       dw      as0osta\r
+       dw      as1osta\r
+       dw      ret$true\r
+\r
+vector$io:\r
+       ld      a,max$device\r
+       ld      e,b\r
+vector:\r
+       pop     hl\r
+       ld      d,0\r
+       cp      e\r
+       jr      nc,exist\r
+       ld      e,a             ; use null device if a >= max$device\r
+exist: add     hl,de\r
+       add     hl,de\r
+       ld      a,(hl)\r
+       inc     hl\r
+       ld      h,(hl)\r
+       ld      l,a\r
+       jp      (hl)\r
+\r
+\r
+null$input:\r
+       ld      a,1Ah\r
+rret:\r
+       ret\r
+ret$true:\r
+       or      0FFh\r
+       ret\r
+\r
+null$status:\r
+       xor     a\r
+       ret\r
+\r
+;--------------------------------------------------------------\r
+\r
+\r
+@ctbl:\r
+       db      'HOST  '        ; device 0\r
+       db      mb$in$out\r
+       db      baud$none\r
+\r
+       db      'ASCI0 '        ; device 1\r
+       db      mb$in$out+mb$serial+mb$soft$baud\r
+ser0$baud:\r
+       db      baud$19200\r
+\r
+       db      'ASCI1 '        ; device 2\r
+       db      mb$in$out+mb$serial+mb$soft$baud\r
+ser1$baud:\r
+       db      baud$19200\r
+\r
+       db      0               ; table terminator\r
+\r
+       end\r
diff --git a/z180/conbuf-a.180 b/z180/conbuf-a.180
new file mode 100644 (file)
index 0000000..f69b86d
--- /dev/null
@@ -0,0 +1,163 @@
+       page    255\r
+       .z80\r
+\r
+;\r
+; FIFO channels for communication with avr\r
+;\r
+       global  ff.init,ff.in,ff.out,ff.i.st,ff.o.st\r
+\r
+       extrn   bufinit\r
+\r
+       include config.inc\r
+       if CPU_Z180\r
+       include z180reg.inc\r
+       endif\r
+\r
+\r
+;--------------------------------------------------------------\r
+\r
+       dseg\r
+\r
+\r
+       mkbuf   ci.fifo_id, ci.fifo, ci.fifo_len\r
+       mkbuf   co.fifo_id, co.fifo, co.fifo_len\r
+\r
+\r
+;--------------------------------------------------------------\r
+\r
+       cseg\r
+\r
+; Init Serial I/O for console input and output\r
+;\r
+\r
+ff.init:\r
+       ld      ix,ci.fifo\r
+       call    bufinit\r
+       ld      ix,co.fifo\r
+       jp      bufinit\r
+\r
+\r
+ff.i.st:\r
+       push    ix\r
+       ld      ix,ci.fifo              ;\r
+\r
+buf.empty:\r
+       ld      a,(ix+o.in_idx)         ;\r
+       sub     (ix+o.out_idx)          ;\r
+       pop     ix\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+\r
+ff.in:\r
+       push    ix\r
+       ld      ix,ci.fifo              ;\r
+\r
+buf.get:\r
+       ld      a,(ix+o.out_idx)        ;\r
+bg.wait:\r
+       cp      (ix+o.in_idx)           ;\r
+       jr      z,bg.wait\r
+\r
+       push    hl                      ;\r
+       push    ix\r
+       pop     hl\r
+       add     a,l\r
+       ld      l,a\r
+       jr      nc,bg.nc\r
+       inc     h\r
+bg.nc:\r
+       ld      l,(hl)\r
+\r
+       ld      a,(ix+o.out_idx)        ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       ld      (ix+o.out_idx),a\r
+\r
+       ld      a,l\r
+       pop     hl\r
+       pop     ix\r
+       ret\r
+\r
+\r
+ff.o.st:\r
+       push    ix\r
+       ld      ix,co.fifo              ;\r
+\r
+buf.full:\r
+       ld      a,(ix+o.in_idx)         ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       sub     (ix+o.out_idx)          ;\r
+       pop     ix\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+\r
+       if 1\r
+ff.out:\r
+       push    ix                      ;15\r
+       ld      ix,co.fifo              ;14\r
+\r
+buf.put:\r
+       push    hl                      ;11\r
+       push    bc                      ;11\r
+       push    ix                      ;15\r
+       pop     hl                      ;10\r
+       ld      a,c                     ;4\r
+       ld      c,(ix+o.in_idx)         ;19\r
+       ld      b,0                     ;7\r
+       add     hl,bc                   ;11\r
+       ld      (hl),a                  ;7\r
+       ld      b,a                     ;4\r
+\r
+       ld      a,c                     ;4\r
+       inc     a                       ;4\r
+       and     (ix+o.mask)             ;19\r
+bp.wait:\r
+       cp      (ix+o.out_idx)          ;19\r
+       jr      z,bp.wait               ;12/7\r
+       ld      (ix+o.in_idx),a         ;19\r
+\r
+       out     (AVRINT6),a             ;11\r
+       ld      a,b                     ;4\r
+       pop     bc                      ;10\r
+       pop     hl                      ;10\r
+       pop     ix                      ;14\r
+       ret                             ;10\r
+\r
+       else\r
+\r
+ff.out:\r
+       push    ix                      ;15\r
+       ld      ix,co.fifo              ;14\r
+\r
+buf.put:\r
+       push    hl                      ;11\r
+       push    ix                      ;15\r
+       pop     hl                      ;10\r
+       ld      a,(ix+o.in_idx)         ;19\r
+       add     a,l                     ;4\r
+       ld      l,a                     ;4\r
+       jr      nc,bp.1                 ;12/7\r
+       inc     l                       ;4\r
+       ld      (hl),c                  ;7\r
+       ld      a,(ix+o.in_idx)         ;19\r
+       inc     a                       ;4\r
+       and     (ix+o.mask)             ;19\r
+bp.wait:\r
+       cp      (ix+o.out_idx)          ;19\r
+       jr      z,bp.wait               ;12/7\r
+       ld      (ix+o.in_idx),a         ;19\r
+\r
+       out     (AVRINT6),a             ;11\r
+       ld      a,c                     ;4\r
+       pop     hl                      ;10\r
+       pop     ix                      ;14\r
+       ret                             ;10             |\r
+\r
+       endif\r
+\r
+       end\r
diff --git a/z180/config.inc b/z180/config.inc
new file mode 100644 (file)
index 0000000..bea6e05
--- /dev/null
@@ -0,0 +1,220 @@
+\r
+FALSE  equ     0\r
+TRUE   equ     NOT FALSE\r
+\r
+\r
+banked equ     true\r
+\r
+;-----------------------------------------------------\r
+; CPU and BANKING types\r
+\r
+\r
+CPU_Z180       equ     TRUE\r
+CPU_Z80                equ     FALSE\r
+\r
+ROMSYS         equ     FALSE\r
+\r
+AVRCLK         equ     18432           ;[KHz]\r
+\r
+    if CPU_Z180\r
+\r
+;-----------------------------------------------------\r
+;FOSC          equ     AVRCLK/2        ;Oscillator frequency [KHz]\r
+;PHI           equ     FOSC*2          ;CPU frequency (clock doubler enabled)\r
+\r
+;----------------------------------------------------------------------\r
+; Baudrate Generator for x16 clock mode:\r
+; TC = (f PHI / (32 * baudrate)) - 2\r
+;\r
+;     PHI [MHz]: 9.216 18.432\r
+;     baudrate     TC     TC\r
+;     ----------------------\r
+;      115200      -      3\r
+;      57600       3      8\r
+;      38400       -     13\r
+;      19200      13     28\r
+;       9600      28     58\r
+\r
+\r
+;-----------------------------------------------------\r
+; Programmable Reload Timer (PRT)\r
+\r
+PRT_PRE                equ     20              ;PRT prescaler\r
+\r
+;-----------------------------------------------------\r
+; MMU\r
+\r
+COMMON_SIZE    equ     4*1024          ;Common Area size in bytes\r
+                                       ;must be multiple of 4K\r
+if (COMMON_SIZE mod 1000h)\r
+       .printx COMMON_SIZE not multiple of 4K!\r
+       end     ;stop assembly\r
+endif\r
+CMN_SIZE       equ     COMMON_SIZE/1000h               ;4K units\r
+BNK_SIZE       equ     64/4 - CMN_SIZE                 ;bank size (4K units)\r
+BANKS          equ     (512/4 - CMN_SIZE)/BNK_SIZE     ;max nr. of banks\r
+\r
+; Logical address space, CBAR values\r
+\r
+CA             equ     10h - CMN_SIZE          ;common area start (64K - common size)\r
+BA             equ     0                       ;banked area start\r
+\r
+   if 0\r
+\r
+SYS$CBR                equ     0\r
+SYS$CBAR       equ     CA*16 + CA      ;CBAR in system mode\r
+USR$CBAR       equ     CA*16 + BA      ;CBAR in user mode (CP/M)\r
+\r
+   endif\r
+   if 1\r
+\r
+SYS$CBR                equ     BNK_SIZE\r
+SYS$CBAR       equ     CA*16 + CA      ;CBAR in system mode\r
+USR$CBAR       equ     CA*16 + BA      ;CBAR in user mode (CP/M)\r
+\r
+   endif\r
+\r
+\r
+;-----------------------------------------------------\r
+\r
+CREFSH         equ     0               ;Refresh rate register (disable refresh)\r
+CWAITIO                equ     3 shl IWI0      ;Max I/O Wait States, 0 Memory Wait States\r
+PHI_X2         equ     0               ;set to M_X2CM to enable the clock doubler\r
+\r
+    endif              ;CPU_Z180\r
+    if CPU_Z80\r
+\r
+PHI            equ     AVRCLK/5        ;CPU frequency [KHz]\r
+BAUDCLCK       equ     AVRCLK/10       ;Baudrate clock [KHz]\r
+;BDCLK16               equ\r
+\r
+SIOAD  EQU     0bch\r
+SIOAC  EQU     0bdh\r
+SIOBD  EQU     0beh\r
+SIOBC  EQU     0bfh\r
+\r
+CTC0   EQU     0f4h\r
+CTC1   EQU     0f5h\r
+CTC2   EQU     0f6h\r
+CTC3   EQU     0f7h\r
+\r
+;\r
+; Init Serial I/O for console input and output (SIO-A)\r
+;\r
+; Baudrate clock: 1843200 Hz (Bus connector pin A17)\r
+;\r
+; Baudrate   Divider   SIO     CTC\r
+; ---------------------------------\r
+; 115200         16     16       1\r
+;  57600         32     16       2\r
+;  38400         48     16       3\r
+;  19200         96     16       6\r
+;   9600        192     16      12\r
+;   4800        384     16      24\r
+;   2400        768     16      48\r
+;   1200       1536     16      96\r
+;    600       3072     16     192\r
+;    300       6144     64      92\r
+\r
+    endif      ; CPU_Z80\r
+\r
+    if ROMSYS\r
+c$rom          equ     0a5h\r
+ROM_EN         equ     0C0h\r
+ROM_DIS                equ     ROMEN+1\r
+     if CPU_Z180\r
+CWAITROM       equ     2 shl MWI0\r
+     endif\r
+    endif\r
+\r
+\r
+DDTZRSTVEC     equ     030h            ;DDTZ Restart vector (breakpoints)\r
+\r
+INIDONE                equ     03Fh            ;CP/M skip hw init, if this address\r
+INIDONEVAL     equ     080h            ;    is set to this value.\r
+\r
+mtx.fifo_len   equ     64              ;Message transfer fifos\r
+mtx.fifo_id    equ     0               ;    This *must* have #0\r
+mrx.fifo_len   equ     64\r
+mrx.fifo_id    equ     1\r
+\r
+ci.fifo_len    equ     32              ;AVRCON (USB0) Character I/O via AVR\r
+ci.fifo_id     equ     2\r
+co.fifo_len    equ     32\r
+co.fifo_id     equ     3\r
+\r
+s0.rx_len      equ     128             ;Serial 0 (ASCI0) buffers\r
+s0.rx_id       equ     4               ;\r
+s0.tx_len      equ     128             ;\r
+s0.tx_id       equ     5               ;\r
+\r
+s1.rx_len      equ     128             ;Serial 1 (ASCI1) buffers\r
+s1.rx_id       equ     6               ;\r
+s1.tx_len      equ     128             ;\r
+s1.tx_id       equ     7               ;\r
+\r
+AVRINT5                equ     4Fh\r
+AVRINT6                equ     5Fh\r
+;PMSG          equ     80h\r
+\r
+IDEBASE                equ     60h\r
+\r
+;-----------------------------------------------------\r
+; Definition of (logical) top 2 memory pages\r
+\r
+sysram_start   equ     0FE00h\r
+bs$stack$size  equ     80\r
+\r
+isvsw_loc      equ     0FEE0h\r
+\r
+ivtab          equ     0ffc0h          ;int vector table\r
+iv2tab         equ     ivtab + 2*9\r
+\r
+\r
+\r
+;-----------------------------------------------------\r
+\r
+o.id           equ     -4\r
+o.mask         equ     -3\r
+o.in_idx       equ     -2\r
+o.out_idx      equ     -1\r
+\r
+       .lall\r
+\r
+mkbuf  macro   id,name,size\r
+  if ((size AND (size-1)) NE 0) OR (size GT 256)\r
+    .printx Error: buffer ^size must be power of 2 and in range 0..256!\r
+    name&.mask equ ;wrong size error\r
+  else\r
+    db id\r
+    db size-1\r
+    ds 2\r
+    name:: ds size\r
+    name&.mask equ low (size-1)\r
+    if size ne 0\r
+      name&.end equ $-1\r
+      name&.len equ size\r
+      name&.id equ id\r
+    endif\r
+  endif\r
+endm\r
+\r
+;-----------------------------------------------------\r
+\r
+inidat macro\r
+       cseg\r
+??ps.a defl    $\r
+       endm\r
+\r
+inidate        macro\r
+??ps.len defl  $ - ??ps.a\r
+       dseg\r
+       ds      ??ps.len\r
+       endm\r
+\r
+;-----------------------------------------------------\r
+\r
+b0call macro   address\r
+       call    _b0call\r
+       dw      address\r
+       endm\r
diff --git a/z180/console.180 b/z180/console.180
new file mode 100644 (file)
index 0000000..1241d5a
--- /dev/null
@@ -0,0 +1,137 @@
+       ;page   255\r
+       .z80\r
+       \r
+\r
+; iobyte:\r
+;              0 = console on AVR-System\r
+;              1 = console on SIO/ASCI\r
+\r
+\r
+       extrn   iobyte\r
+       extrn   ff.init,ff.i.st,ff.in\r
+       extrn   ff.o.st,ff.out\r
+    if CPU_Z180\r
+       extrn   as0init,as0ista,as0inp,as0osta,as0out\r
+       extrn   as1init,as1ista,as1inp,as1osta,as1out\r
+    else\r
+       extrn   ser.init,ser.ist,ser.in,ser.ost,ser.out\r
+    endif\r
+       \r
+       public  charini\r
+       public  ?const,?conin\r
+       public  ?conos,?cono\r
+\r
+       include config.inc\r
+    if CPU_Z180\r
+       include z180reg.inc\r
+    endif\r
+\r
+       cseg\r
+\r
+    if CPU_Z180\r
+charini:\r
+       call    ff.init\r
+       call    as0init\r
+       jp      as1init\r
+\r
+?const:\r
+       ld      a,(iobyte)\r
+       and     03h\r
+       jp      z,ff.i.st\r
+       dec     a\r
+       jp      z,as0ista\r
+       dec     a\r
+       jp      z,as1ista\r
+       jr      nullstatus\r
+\r
+?conin:\r
+       ld      a,(iobyte)\r
+       and     03h\r
+       jp      z,ff.in\r
+       dec     a\r
+       jp      z,as0inp\r
+       dec     a\r
+       jp      z,as1inp\r
+       jr      nullinput\r
+\r
+?conos:\r
+       ld      a,(iobyte)\r
+       and     03h\r
+       jp      z,ff.o.st\r
+       dec     a\r
+       jp      z,as0osta\r
+       dec     a\r
+       jp      z,as1osta\r
+       jr      rettrue\r
+\r
+?cono:\r
+       ld      a,(iobyte)\r
+       and     03h\r
+       jp      z,ff.out\r
+       dec     a\r
+       jp      z,as0out\r
+       dec     a\r
+       jp      z,as1out\r
+       jr      nulloutput\r
+\r
+    else\r
+\r
+charini:\r
+       call    ff.init\r
+       ld      c,0\r
+       call    ser.init\r
+       ld      c,1\r
+       jp      ser.init\r
+\r
+?const:\r
+       ld      a,(iobyte)\r
+       and     03h\r
+       jp      z,ff.i.st\r
+       dec     a\r
+       ld      b,a\r
+       jp      ser.ist\r
+\r
+?conin:\r
+       ld      a,(iobyte)\r
+       and     03h\r
+       jp      z,ff.in\r
+       dec     a\r
+       ld      b,a\r
+       jp      ser.in\r
+\r
+?conos:\r
+       ld      a,(iobyte)\r
+       and     03h\r
+       jp      z,ff.o.st\r
+       dec     a\r
+       ld      b,a\r
+       jp      ser.ost\r
+\r
+?cono:\r
+       ld      a,(iobyte)\r
+       and     03h\r
+       jp      z,ff.out\r
+       dec     a\r
+       ld      b,a\r
+       jp      ser.out\r
+    endif\r
+\r
+\r
+nullinput:\r
+       ld      a,1Ah\r
+       ret\r
+\r
+nulloutput:\r
+       ld      a,c\r
+       ret\r
+\r
+rettrue:\r
+       or      0FFh\r
+       ret\r
+\r
+nullstatus:\r
+       xor     a\r
+       ret\r
+\r
+       end\r
+\r
diff --git a/z180/ddtz.180 b/z180/ddtz.180
new file mode 100644 (file)
index 0000000..d18330c
--- /dev/null
@@ -0,0 +1,6062 @@
+       page    255\r
+       .z80\r
+\r
+       extrn   ?const,?conin,?cono\r
+       extrn   getiff\r
+       extrn   selbnk,@cbnk\r
+\r
+       global  ddtz,bpent\r
+       global  $stack\r
+\r
+\r
+       include config.inc\r
+       if CPU_Z180\r
+       include z180reg.inc\r
+       include z180.lib\r
+       endif\r
+\r
+BS     equ     08h\r
+TAB    equ     09h\r
+CR     equ     0dh\r
+LF     equ     0ah\r
+DEL    equ     7fh\r
+CNTRX  equ     'X'-'@'\r
+\r
+TPA    equ     100h\r
+TOPRAM equ     0f000h\r
+\r
+\r
+MEMDUMP_CNT    equ     16              ;mem dump bytes per line\r
+BP_CNT                 equ     12              ;number of breakbpoints\r
+\r
+\r
+;--------------------------------------------------\r
+;\r
+\r
+; copy code to common memory and execute it there\r
+comst  macro\r
+       call    ?excom\r
+       ds      1\r
+?lcs   defl    $\r
+       endm\r
+\r
+; mark end of common code snippet\r
+comend macro\r
+?lce   defl    $\r
+?lclen defl    ?lce-?lcs\r
+       org     ?lcs-1\r
+       db      ?lclen\r
+       org     ?lce\r
+       ifndef  ?lcmax\r
+?lcmax defl    0\r
+       endif\r
+       if      ?lclen gt ?lcmax\r
+?lcmax defl    ?lclen\r
+       endif\r
+       endm\r
+\r
+\r
+\r
+\r
+       cseg\r
+\r
+;----------------------------------------------------------\r
+\r
+MSG:\r
+       DB      'DDT/Z - HD64180  (ROM)'\r
+       DB      CR,LF,0\r
+\r
+HLPMSG:\r
+       DB 'DDT/Z180 (ROM) Commands:',CR,LF\r
+       DB '> @                             examine/substitute the displacement register @',CR,LF\r
+       DB '> A [address]                   Assemble',CR,LF\r
+       DB '> B[X]                          display [or clear] all Breakpoints',CR,LF\r
+       DB '  B breakp [:count] [breakp..]  set Breakpoints',CR,LF\r
+       DB '  BX address [address..]        clear Breakpoints',CR,LF\r
+       DB '>>C[N][J] [count]               trace over Calls [No list] [Jumps only]',CR,LF\r
+       DB '  C[N][J] W|U expression        trace over Calls While|Until ...',CR,LF\r
+       DB '>>D [startadr] [endadr]         Display memory in hex and ascii',CR,LF\r
+       DB '> G [startadr] [;breakp..]      Go [to start] [temporary breakpoints]',CR,LF\r
+       DB '> H [expression [expression]]   compute expressions / show High/max load adr.',CR,LF\r
+       DB '>>I [port]                      Input a byte from port',CR,LF\r
+       DB '>>L [startadr] [endadr]         List disassembled code',CR,LF\r
+       DB '> M[V] startadr endadr destadr  Move memory [and verify]',CR,LF\r
+       DB '>>O [byte] [port]               Output a byte to port',CR,LF\r
+       DB '> Q[J] startadr endadr bytes    Qery memory for byte string [Justified]',CR,LF\r
+       DB '> R [displacement]              Read intel hex from console [add displacemt]',CR,LF\r
+       DB '> S address                     Substitute memory',CR,LF\r
+       DB '>>T[N][J] [count]               Trace [No list] [Jumps only] [count steps]',CR,LF\r
+       DB '  T[N][J] W|U expression        Trace While|Until expression',CR,LF\r
+       DB '> V startadr endadr destadr     Verify (compare) two memory areas',CR,LF\r
+       DB '> X[register]                   eXamine [and substitute] registers',CR,LF\r
+       DB '> Y[0..9]                       eXamine [and substitute] Y variables',CR,LF\r
+       DB '> Z startadr endadr bytes       Zap (fill) memory with a byte string',CR,LF\r
+       DB 0\r
+\r
+ddtz:\r
+       ld      sp,$stack\r
+       ld      a,(wstrtflg)            ;check warm start flag\r
+       or      a\r
+;;;    jr      nz,ddtz_w\r
+\r
+       exx\r
+       ld      hl,sysramc\r
+       ld      de,topcodbeg\r
+       ld      bc,topcodend-topcodbeg\r
+       ldir\r
+\r
+       exx\r
+\r
+       if CPU_Z180\r
+       ld      a,e\r
+       ld      (ubbr),a\r
+       endif\r
+\r
+ddtz_w:\r
+       ld hl,MSG\r
+       call PSTR\r
+       call ddtei\r
+\r
+; DDTZ main loop\r
+\r
+DDTZML:\r
+       ld sp,$stack\r
+       ld hl,l07eah\r
+       ld (CMD_ERR),hl\r
+       ld hl,(REG.PC)\r
+       ld (OFFS.pc),hl\r
+       call sub_0e68h\r
+       ld hl,(CMD_RPT)\r
+       ld de,DDTZML\r
+       call CP.HL.DE\r
+       ld a,'>'\r
+       call OUTCHAR\r
+       call nz,OUTCHAR\r
+       call z,OUTBL\r
+       call INLINE\r
+       call SKIPBL\r
+       jr z,exe_hl\r
+       ld hl,DDTZML\r
+       ld (CMD_RPT),hl\r
+       inc de\r
+       sub '?'\r
+       jr c,ERROR\r
+       cp 'Z'+1-'?'\r
+       jr nc,ERROR\r
+       add a,a\r
+       ld hl,CMDTAB\r
+       call ADD_HL_A\r
+       ld a,(hl)\r
+       inc hl\r
+       ld h,(hl)\r
+       ld l,a\r
+       jr exe_hl\r
+ERROR:\r
+       ld hl,(CMD_ERR)\r
+exe_hl:\r
+       call CALL.HL\r
+       jr DDTZML\r
+\r
+CALL.HL:\r
+       jp (hl)\r
+\r
+\r
+CMDTAB:\r
+       defw CMD.?              ;Help\r
+       defw CMD.@              ;Offset\r
+       defw CMD.A              ;Assemble\r
+       defw CMD.B              ;Breakpoint\r
+       defw CMD.C              ;Call\r
+       defw CMD.D              ;Display\r
+       defw ERROR              ;\r
+       defw ERROR              ;\r
+       defw CMD.G              ;Go\r
+       defw CMD.H              ;Hex Math\r
+       defw CMD.I              ;In Port\r
+       defw ERROR              ;\r
+       defw ERROR              ;\r
+       defw CMD.L              ;List\r
+       defw CMD.M              ;Move\r
+       defw ERROR              ;\r
+       defw CMD.O              ;Out Port\r
+       defw ERROR              ;\r
+       defw CMD.Q              ;Query\r
+       defw CMD.R              ;Read Intel Hex\r
+       defw CMD.S              ;Substitute\r
+       defw CMD.T              ;Trace\r
+       defw ERROR              ;\r
+       defw CMD.V              ;Verify\r
+       defw ERROR              ;\r
+       defw CMD.X              ;eXamine\r
+       defw CMD.Y              ;eXamine Y Registers\r
+       defw CMD.Z              ;Zap (fill) memory\r
+l07eah:\r
+       ld a,'?'\r
+       call OUTCHAR\r
+       jp CRLF\r
+\r
+CMD.?:\r
+       call    assert_eol\r
+       ld      hl,HLPMSG\r
+       call    PSTR\r
+       ret\r
+\r
+$ci:\r
+       push    hl\r
+       push    de\r
+       push    bc\r
+       call    ?conin\r
+       pop     bc\r
+       pop     de\r
+       pop     hl\r
+       ret\r
+\r
+$co:\r
+       push    hl\r
+       push    de\r
+       push    bc\r
+       ld      c,a\r
+       call    ?cono\r
+       pop     bc\r
+       pop     de\r
+       pop     hl\r
+       ret\r
+\r
+DELC:\r
+       ld      a,b\r
+       or      a\r
+       ret     z\r
+       call    DELC1\r
+       dec     hl\r
+       dec     b\r
+       inc     c\r
+       ld      a,(hl)\r
+       cp      ' '\r
+       ret     nc\r
+DELC1:\r
+       push    de\r
+       push    hl\r
+       push    bc\r
+       ld      c,BS\r
+       call    ?cono\r
+       ld      c,' '\r
+       call    ?cono\r
+       ld      c,BS\r
+       call    ?cono\r
+       pop     bc\r
+       pop     hl\r
+       pop     de\r
+       ret\r
+\r
+DELL:\r
+       ld a,b                  ;\r
+       or a                    ;\r
+       ret z                   ;\r
+       call DELC               ;\r
+       jr DELL                 ;\r
+\r
+INLINE:\r
+       push hl                 ;\r
+       ld hl,CI.BUF            ;\r
+       ld c,(hl)               ;\r
+       inc hl                  ;\r
+       ld b,000h               ;\r
+       inc hl                  ;\r
+inlnxtch:\r
+       ld a,c                  ;\r
+       or a                    ;\r
+       jr z,inl_e              ;\r
+       call $ci                ;\r
+       cp CR                   ;\r
+       jr z,inl_e              ;Accept line\r
+       cp LF                   ;\r
+       jr z,inl_e              ;Accept line\r
+       cp BS                   ;\r
+       jr nz,l0844h            ;\r
+       call DELC               ;Delete Char\r
+       jr inlnxtch             ;\r
+l0844h:\r
+       cp DEL                  ;\r
+       jr nz,l084dh            ;\r
+       call DELC               ;Delete Char\r
+       jr inlnxtch             ;\r
+l084dh:\r
+       cp CNTRX                ;\r
+       jr nz,l0856h            ;\r
+       call DELL               ;Delete Line\r
+       jr inlnxtch             ;\r
+l0856h:\r
+       cp TAB                  ;\r
+       jr nz,l085ch            ;\r
+       ld a,' '                ;\r
+l085ch:\r
+       ld (hl),a               ;\r
+       cp ' '                  ;\r
+       jr nc,l0869h            ;\r
+       ld a,'^'                ;Controll characters\r
+       call $co                ;\r
+       ld a,(hl)               ;\r
+       add a,'@'               ;\r
+l0869h:\r
+       call $co                ;\r
+       inc hl                  ;\r
+       inc b                   ;\r
+       dec c                   ;\r
+       jr inlnxtch             ;\r
+\r
+inl_e:\r
+       ld hl,ci.buf+1          ;\r
+       ld (hl),b               ;\r
+       call CRLF               ;\r
+       ld de,ci.buf+1          ;\r
+       ld a,(de)               ;\r
+       ld b,a                  ;\r
+       ld c,000h               ;\r
+       inc b                   ;\r
+l0880h:\r
+       inc de                  ;\r
+       dec b                   ;\r
+       jr z,l08b2h             ;\r
+       ld a,(de)               ;\r
+       bit 0,c                 ;\r
+       call z,UPCASE           ;\r
+       ld (de),a               ;\r
+       cp ''''                 ;\r
+       jr nz,l0880h            ;\r
+       push de                 ;\r
+       dec de                  ;\r
+       ld a,(de)               ;\r
+       cp ''''                 ;\r
+       jr z,l08aeh             ;\r
+       dec de                  ;\r
+       ld a,(de)               ;\r
+       cp '^'                  ;\r
+       jr z,l08a2h             ;\r
+       dec de                  ;\r
+       ld a,(de)               ;\r
+       cp '^'                  ;\r
+       jr nz,l08aeh            ;\r
+l08a2h:\r
+       inc de                  ;\r
+       push bc                 ;\r
+       call sub_0a0eh          ;\r
+       pop bc                  ;\r
+       dec de                  ;\r
+       ld a,(de)               ;\r
+       cp ''''                 ;\r
+       jr z,l08afh             ;\r
+l08aeh:\r
+       inc c                   ;\r
+l08afh:\r
+       pop de                  ;\r
+       jr l0880h               ;\r
+l08b2h:\r
+       xor a                   ;\r
+       ld (de),a               ;\r
+       ld de,ci.buf+2          ;\r
+       pop hl                  ;\r
+       ret                     ;\r
+\r
+UPCASE:\r
+       cp 'a'                  ;\r
+       ret c                   ;\r
+       cp 'z'+1                ;\r
+       ret nc                  ;\r
+       and 05fh                ;\r
+       ret                     ;\r
+\r
+out.hl.@:\r
+       call out.hl             ;\r
+       push de                 ;\r
+       push hl                 ;\r
+       ld de,(offs.@)          ;\r
+       ld a,d                  ;\r
+       or e                    ;\r
+       jr z,l08ddh             ;\r
+       call OUTBL              ;\r
+       ld a,'@'                ;\r
+       call OUTCHAR            ;\r
+       and a                   ;\r
+       sbc hl,de               ;\r
+       call out.hl             ;\r
+l08ddh:\r
+       pop hl                  ;\r
+       pop de                  ;\r
+       ret                     ;\r
+\r
+out.bin.w:\r
+       ld a,h                  ;\r
+       call out.bin.b          ;\r
+       ld a,l                  ;\r
+out.bin.b:\r
+       ld b,008h               ;\r
+l08e7h:\r
+       add a,a                 ;\r
+       push af                 ;\r
+       ld a,0                  ;\r
+       adc a,a                 ;\r
+       call out.digit          ;\r
+       pop af                  ;\r
+       djnz l08e7h             ;\r
+       ld a,'"'                ;\r
+       jp OUTCHAR              ;\r
+\r
+sub_08f7h:\r
+       ld a,'-'                ;\r
+       call OUTCHAR            ;\r
+       dec hl                  ;\r
+       jp cpl.hl               ;\r
+\r
+out.hl.decm:\r
+       push hl                 ;\r
+       call sub_08f7h          ;\r
+       db      3eh             ;  ld a,0E5h\r
+out.hl.dec:\r
+       push    hl\r
+       ld b,6                  ;\r
+       call sub_0917h          ;\r
+       pop hl                  ;\r
+       ld a,'.'                ;\r
+       call OUTCHAR            ;\r
+l0911h:\r
+       call OUTBL              ;\r
+       djnz l0911h             ;\r
+       ret                     ;\r
+\r
+\r
+sub_0917h:\r
+       dec b\r
+       push de\r
+       ld de,10\r
+       call DIV_HL_DE\r
+       ld a,h\r
+       or l\r
+       call nz,sub_0917h\r
+       ld a,e\r
+       pop de\r
+       jr out.digit\r
+\r
+sub_0928h:\r
+       push hl\r
+       call sub_08f7h\r
+       call out.hl\r
+       pop hl\r
+       ret\r
+out.hl:\r
+       ld a,h\r
+       call out.hex\r
+       ld a,l\r
+out.hex:\r
+       push af\r
+       rra\r
+       rra\r
+       rra\r
+       rra\r
+       call out.digit\r
+       pop af\r
+out.digit:\r
+       and 00fh\r
+       cp 10\r
+       jr c,l0947h\r
+       add a,007h\r
+l0947h:\r
+       add a,'0'\r
+       jr OUTCHAR\r
+l094bh:\r
+       ld a,'-'\r
+       call OUTCHAR\r
+       ld a,040h\r
+out.ascii:\r
+       ex af,af'\r
+       call outquote\r
+       ex af,af'\r
+       push af\r
+       res 7,a\r
+       cp ' '\r
+       jr nc,l0960h\r
+       sub 0c0h\r
+l0960h:\r
+       call OUTCHAR\r
+       push af\r
+       cp ''''\r
+       call z,OUTCHAR\r
+       pop af\r
+       ex af,af'\r
+       call outquote\r
+       pop af\r
+       or a\r
+       ld a,'.'\r
+       call m,OUTCHAR\r
+       ex af,af'\r
+       jr c,l094bh\r
+       ret\r
+\r
+outquote:\r
+       ld a,''''\r
+OUTCHAR:\r
+       push    hl\r
+       push    de\r
+       push    bc\r
+       push    af\r
+       and     07fh\r
+       ld      c,a\r
+       call    ?cono\r
+       ld      hl,CON.COL\r
+       inc     (hl)\r
+       pop     af\r
+       pop     bc\r
+       pop     de\r
+       pop     hl\r
+       ret\r
+\r
+inchar:\r
+       push    hl\r
+       push    de\r
+       push    bc\r
+       call    ?const\r
+       and     a\r
+       jr      z,inch1\r
+       call    ?conin\r
+       scf\r
+inch1:\r
+       pop     bc\r
+       pop     de\r
+       pop     hl\r
+       ret\r
+\r
+PSTR:\r
+       ld c,000h\r
+l0995h:\r
+       ld a,(hl)\r
+       and a\r
+       ret z\r
+       call OUTCHAR\r
+       inc c\r
+       inc hl\r
+       and a\r
+       ret m\r
+       jr l0995h\r
+\r
+outbl6:\r
+       call outbl2\r
+outbl4:\r
+       call outbl2\r
+outbl2:\r
+       call OUTBL\r
+OUTBL:\r
+       ld a,' '\r
+       jr OUTCHAR\r
+CRLF:\r
+       call inchar\r
+       ld a,CR\r
+       call OUTCHAR\r
+       ld a,LF\r
+       call OUTCHAR\r
+       ld a,000h\r
+       ld (CON.COL),a\r
+       jp c,DDTZML\r
+       ret\r
+\r
+ADD_HL_A:\r
+       add a,l\r
+       ld l,a\r
+       ret nc\r
+       inc h\r
+       ret\r
+\r
+SKIPBL0:\r
+       inc de\r
+SKIPBL:\r
+       ld a,(de)\r
+       cp ' '\r
+       jr z,SKIPBL0\r
+       cp 009h\r
+       jr z,SKIPBL0\r
+       or a\r
+       ret\r
+\r
+skip_to_nextarg:\r
+       call SKIPBL\r
+       cp ','\r
+       ret nz\r
+       inc de\r
+       call SKIPBL\r
+       cp a\r
+       ret\r
+\r
+assert_eol:\r
+       call SKIPBL\r
+       ret z\r
+l09e5h:\r
+       jp ERROR\r
+\r
+chk.sp:\r
+       push hl\r
+       push de\r
+       ld hl,0\r
+       add hl,sp\r
+       ld de,$stack-50\r
+       call CP.HL.DE\r
+       pop de\r
+       pop hl\r
+       jr c,l09e5h\r
+       ret\r
+\r
+CP.HL.DE:\r
+       and a\r
+       sbc hl,de\r
+       add hl,de\r
+       ret\r
+\r
+lookupch:\r
+       ld b,000h\r
+l0a00h:\r
+       ld a,(hl)\r
+       and a\r
+       ret z\r
+       ld a,(de)\r
+       cp (hl)\r
+       jr z,l0a0bh\r
+       inc hl\r
+       inc b\r
+       jr l0a00h\r
+l0a0bh:\r
+       scf\r
+       inc de\r
+       ret\r
+\r
+sub_0a0eh:\r
+       ld hl,b_0x132A_start\r
+       ld b,07fh\r
+       jr l0a17h\r
+\r
+sub_0a15h:\r
+       ld b,0ffh\r
+l0a17h:\r
+       inc b\r
+       ld a,(hl)\r
+       and a\r
+       ret z\r
+       call l0a27\r
+       jr nc,l0a17h\r
+       res 7,b\r
+       ret\r
+\r
+sub_0a23h:\r
+       push bc\r
+       res 7,b\r
+       db      3eh             ;0a26  ld a,0c5h\r
+l0a27:\r
+       push bc\r
+       push de\r
+l0a29h:\r
+       ld a,(de)\r
+       xor (hl)\r
+       and 07fh\r
+       jr nz,l0a41h\r
+       bit 7,(hl)\r
+       inc hl\r
+       inc de\r
+       jr z,l0a29h\r
+       scf\r
+       bit 7,b\r
+       call z,sub_0d20h\r
+       jr nc,l0a44h\r
+       pop af\r
+       scf\r
+       pop bc\r
+       ret\r
+\r
+l0a41h:\r
+       call sub_0a50h\r
+l0a44h:\r
+       pop de\r
+       and a\r
+       pop bc\r
+       ret\r
+\r
+sub_0a48h:\r
+       inc b\r
+l0a49h:\r
+       dec b\r
+       ret z\r
+       call sub_0a50h\r
+       jr l0a49h\r
+sub_0a50h:\r
+       ld a,(hl)\r
+       and a\r
+       ret z\r
+l0a53h:\r
+       ld a,(hl)\r
+       inc hl\r
+       and a\r
+       ret m\r
+       jr l0a53h\r
+\r
+get_arg3:\r
+       call get_arg_range\r
+       push hl\r
+       push bc\r
+       call skip_to_nextarg\r
+       call get_arg\r
+       ex de,hl\r
+       pop bc\r
+       pop hl\r
+       ret\r
+\r
+sub_0a68h:\r
+       call EXPR\r
+       jr c,error0\r
+       ret\r
+\r
+get_arg:\r
+       call sub_0a68h\r
+l0a71h:\r
+       jp assert_eol\r
+\r
+get_lastarg_def:\r
+       call get_arg_def\r
+       jr l0a71h\r
+\r
+get_arg_def:\r
+       push hl\r
+       call EXPR\r
+       jr c,l0a80h\r
+       ex (sp),hl\r
+l0a80h:\r
+       pop hl\r
+       ret\r
+\r
+sub_0a82h:\r
+       call sub_0a87h\r
+       jr l0a71h\r
+\r
+sub_0a87h:\r
+       db      0e6h            ;0a87  and 037h (clear carry)\r
+get_arg_range:\r
+       scf\r
+       ex af,af'\r
+       push bc\r
+       push hl\r
+       call EXPR\r
+       jr nc,l0a97h\r
+       ex af,af'\r
+       jr c,error0\r
+       ex af,af'\r
+       pop hl\r
+\r
+       defb 03eh\r
+l0a97h:\r
+       pop af\r
+       call sub_0aa5h\r
+       jr nc,l0aa3h\r
+       ex af,af'\r
+       pop bc\r
+       ret nc\r
+error0:\r
+       jp ERROR\r
+\r
+l0aa3h:\r
+       pop af\r
+       ret\r
+\r
+sub_0aa5h:\r
+       call skip_to_nextarg\r
+       cp 'S'\r
+       jr nz,l0aadh\r
+       inc de\r
+l0aadh:\r
+       push hl\r
+       push af\r
+       call EXPR\r
+       jr c,l0ac3h\r
+       ld b,h\r
+       ld c,l\r
+       pop af\r
+       pop hl\r
+       jr z,l0ac1h\r
+       ld a,c\r
+       sub l\r
+       ld c,a\r
+       ld a,b\r
+       sbc a,h\r
+       ld b,a\r
+       inc bc\r
+l0ac1h:\r
+       and a\r
+       ret\r
+\r
+l0ac3h:\r
+       pop af\r
+       pop hl\r
+       jr z,error0\r
+       scf\r
+       ret\r
+\r
+EXPR:\r
+       call SKIPBL\r
+EXPR1:\r
+       call do_subexpr\r
+       ret c\r
+       call do_rel_op\r
+       ret nc\r
+       push bc\r
+       push hl\r
+       call do_subexpr\r
+       jr c,error0\r
+       ex de,hl\r
+       ex (sp),hl\r
+       and a\r
+       sbc hl,de\r
+       ld hl,0ffffh\r
+       pop de\r
+       ret\r
+\r
+do_op_eq:\r
+       jr z,l0af8h\r
+       jr l0af7h\r
+do_op_ne:\r
+       jr nz,l0af8h\r
+       jr l0af7h\r
+do_op_le:\r
+       jr z,l0af8h\r
+do_op_lt:\r
+       jr c,l0af8h\r
+       jr l0af7h\r
+do_op_gt:\r
+       jr z,l0af7h\r
+do_op_ge:\r
+       jr nc,l0af8h\r
+l0af7h:\r
+       inc hl\r
+l0af8h:\r
+       and a\r
+       ret\r
+\r
+do_rel_op:\r
+       push hl\r
+       ld hl,tab_eq_le_ge\r
+       call lookupch\r
+       jr nc,l0b28h\r
+       ld a,b\r
+       or a\r
+       jr z,l0b1ch\r
+       ld a,(de)\r
+       cp '='\r
+       jr nz,l0b11h\r
+       inc de\r
+       inc b\r
+       inc b\r
+       jr l0b1ch\r
+\r
+l0b11h:\r
+       bit 0,b\r
+       jr z,l0b1ch\r
+       cp '>'\r
+       jr nz,l0b1ch\r
+       inc de\r
+       ld b,005h\r
+l0b1ch:\r
+       ld hl,tab_func_eqlege\r
+       ld a,b\r
+       add a,a\r
+       call ADD_HL_A\r
+       ld c,(hl)\r
+       inc hl\r
+       ld b,(hl)\r
+       scf\r
+l0b28h:\r
+       pop hl\r
+       ret\r
+\r
+tab_eq_le_ge:\r
+       db      '=<>',0\r
+\r
+tab_func_eqlege:\r
+       defw do_op_eq\r
+       defw do_op_lt\r
+       defw do_op_gt\r
+       defw do_op_le\r
+       defw do_op_ge\r
+       defw do_op_ne\r
+\r
+do_subexpr:\r
+       call do_factor\r
+       ret c\r
+l0b3eh:\r
+       call do_binary_op\r
+       push hl\r
+       push bc\r
+       call do_factor\r
+       pop bc\r
+       ex de,hl\r
+       ex (sp),hl\r
+       jr nc,l0b52h\r
+       pop de\r
+       ld a,b\r
+       or c\r
+       ret z\r
+       jp ERROR\r
+\r
+l0b52h:\r
+       ld a,b\r
+       or c\r
+       push bc\r
+       ret nz\r
+       pop bc\r
+do_op_add:\r
+       add hl,de\r
+l0b58h:\r
+       pop de\r
+       jr l0b3eh\r
+\r
+do_op_sub:\r
+       and a\r
+       sbc hl,de\r
+       jr l0b58h\r
+\r
+do_op_mlt:\r
+       push    bc\r
+       if CPU_Z180\r
+       ld      b,h\r
+       ld      c,e\r
+       ld      h,e\r
+       ld      e,l\r
+       mlt     bc\r
+       mlt     de\r
+       mlt     hl\r
+       ld      a,h\r
+       add     a,c\r
+       add     a,e\r
+       ld      h,a\r
+       else\r
+        ld     b,h\r
+        ld     c,l\r
+        ld     hl,0\r
+        ld     a,16\r
+mlt_1:\r
+        add    hl,hl\r
+        ex     de,hl\r
+        add    hl,hl\r
+        ex     de,hl\r
+        jr     nc,mlt_2\r
+        add    hl,bc\r
+mlt_2:\r
+        dec    a\r
+        jr     nz,mlt_1\r
+       endif\r
+       pop     bc\r
+       jr      l0b58h\r
+\r
+do_op_div:\r
+       call DIV_HL_DE\r
+       jr l0b58h\r
+\r
+do_op_mod:\r
+       call DIV_HL_DE\r
+       ex de,hl\r
+       jr l0b58h\r
+\r
+; divide x/y\r
+;     hl: x\r
+;     de: y\r
+;   return:\r
+;     hl: q  (x/y)\r
+;     de: r  (x%y)\r
+\r
+DIV_HL_DE:\r
+       push    bc\r
+       ex      de,hl           ;de = x, hl = y\r
+       ld      b,h             ;bc = y\r
+       ld      c,l\r
+       ld      hl,0            ;r = 0\r
+       ld      a,16            ;count\r
+\r
+;  de: x   (x shifted out, q shifted in)\r
+;  bc: y\r
+;  hl: r   (initially 0)\r
+\r
+l0b89h:\r
+       ex      de,hl           ;x\r
+       add     hl,hl           ;x <<= 1\r
+       ex      de,hl           ;r\r
+       adc     hl,hl           ;r <<= 1\r
+\r
+       or      a\r
+       sbc     hl,bc\r
+       inc     de\r
+       jr      nc,div_no_restore\r
+       add     hl,bc\r
+       dec     de\r
+div_no_restore:\r
+       dec     a\r
+       jr      nz,l0b89h\r
+       ex      de,hl           ;hl: q   de: r\r
+       pop     bc\r
+       ret\r
+\r
+do_op_and:\r
+       ld      a,h\r
+       and     d\r
+       ld      h,a\r
+       ld      a,l\r
+       and     e\r
+       ld      l,a\r
+       jr      l0b58h\r
+\r
+do_op_or:\r
+       ld      a,h\r
+       or      d\r
+       ld      h,a\r
+       ld      a,l\r
+       or      e\r
+       ld      l,a\r
+       jr      l0b58h\r
+\r
+do_op_xor:\r
+       ld      a,h\r
+       xor     d\r
+       ld      h,a\r
+       ld      a,l\r
+       xor     e\r
+       ld      l,a\r
+       jr      l0b58h\r
+\r
+do_binary_op:\r
+       push    hl\r
+       ld      hl,tab_op_a\r
+       call    lookupch\r
+       ld      a,b\r
+       ld      hl,tab_func_opa\r
+       add     a,a\r
+       call    ADD_HL_A\r
+       ld      c,(hl)\r
+       inc     hl\r
+       ld      b,(hl)\r
+       pop     hl\r
+       ret\r
+\r
+tab_op_a:\r
+       DB      '+-*/%&!#',0\r
+tab_func_opa:\r
+       defw    do_op_add\r
+       defw    do_op_sub\r
+       defw    do_op_mlt\r
+       defw    do_op_div\r
+       defw    do_op_mod\r
+       defw    do_op_and\r
+       defw    do_op_or\r
+       defw    do_op_xor\r
+       defw    0\r
+\r
+fact_factor:\r
+       call    do_factor\r
+       ret     nc\r
+       jp      ERROR\r
+\r
+do_factor:\r
+       call    chk.sp\r
+       call    get.number\r
+       ret     nc\r
+       inc     de\r
+       ld      hl,TOPRAM\r
+       cp      'T'\r
+       ret     z\r
+       ld      hl,(HILOD)\r
+       cp      'H'\r
+       ret     z\r
+       ld      hl,(MAXLOD)\r
+       cp      'M'\r
+       ret     z\r
+       ld      hl,TPA\r
+       cp      'L'\r
+       ret     z\r
+       ld      hl,(offs.@)\r
+       cp      '@'\r
+       ret     z\r
+       ld      hl,(OFFS.pc)\r
+       cp      '$'\r
+       ret     z\r
+       cp      '-'\r
+       jr      z,fact_factneg\r
+       cp      '~'\r
+       jr      z,fact_factinv\r
+       cp      '+'\r
+       jr      z,fact_factor\r
+       cp      '^'\r
+       jr      z,fact_reg.CPU\r
+       cp      'Y'\r
+       jr      z,fact_reg.Y\r
+       cp      '('\r
+       jr      z,fact_mem\r
+       cp      '['\r
+       jp      z,EXPR_BRCKT            ;0c35   [ expression ]\r
+       cp      ''''\r
+       jr      z,fact_factstring\r
+       dec     de\r
+       scf\r
+       ret\r
+\r
+fact_reg.Y:\r
+       call    get.decdigit\r
+       jp      c,ERROR\r
+       inc     de\r
+       add     a,a\r
+       ld      hl,reg.Y\r
+       call    ADD_HL_A\r
+       ld      a,(hl)\r
+       inc     hl\r
+       ld      h,(hl)\r
+       ld      l,a\r
+       and     a\r
+       ret\r
+fact_factstring:\r
+       ld      hl,0\r
+l0c56h:\r
+       ld      a,(de)\r
+       cp      ''''\r
+       jr      z,l0c62h\r
+       and     a\r
+       ret     z\r
+l0c5dh:\r
+       ld      h,l\r
+       ld      l,a\r
+       inc     de\r
+       jr      l0c56h\r
+\r
+l0c62h:\r
+       inc     de\r
+       ld      a,(de)\r
+       cp      ''''\r
+       jr      z,l0c5dh\r
+       sub     '.'\r
+       or      a\r
+       ret     nz\r
+       inc     de\r
+       set     7,l\r
+       ret\r
+\r
+fact_reg.CPU:\r
+       call    sub_1315h\r
+       jr      nc,l0cbbh\r
+       ld      a,(hl)\r
+       inc     hl\r
+       ld      h,(hl)\r
+       ld      l,a\r
+       and     a\r
+       bit     0,c\r
+       ret     nz\r
+       ld      h,000h\r
+       ret\r
+\r
+fact_factneg:\r
+       call    fact_factor\r
+       dec     hl\r
+cpl.hl:\r
+       ld      a,h\r
+       cpl\r
+       ld      h,a\r
+       ld      a,l\r
+       cpl\r
+       ld      l,a\r
+       ret\r
+fact_factinv:\r
+       call    fact_factor\r
+       jr      cpl.hl\r
+\r
+fact_mem:\r
+       call    EXPR1\r
+       jr      c,l0cbbh\r
+       ld      a,(de)\r
+       cp      ')'\r
+       jr      nz,l0cbbh\r
+       inc     de\r
+       comst\r
+        ld     a,(hl)\r
+        inc    hl                      ;\r
+        ld     h,(hl)          ;\r
+       comend\r
+       ld      l,a\r
+       ld      a,(de)\r
+       inc     de\r
+       cp      '.'\r
+       ret     z\r
+       dec     de\r
+       xor     a\r
+       ld      h,a\r
+       ret\r
+\r
+EXPR_BRCKT:\r
+       call    EXPR1\r
+       jr      c,l0cbbh\r
+       ld      a,(de)\r
+       cp      ']'\r
+       inc     de\r
+       ret     z\r
+l0cbbh:\r
+       jp      ERROR\r
+\r
+get.number:\r
+       call    get.hexdigit\r
+       ret     c\r
+       push    de\r
+l0cc3h:\r
+       inc     de\r
+       call    get.hexdigit\r
+       jr      nc,l0cc3h\r
+       pop     de\r
+       cp      '.'\r
+       jr      z,l0d04h\r
+       cp      '"'\r
+       jr      z,l0ce9h\r
+       ld      hl,0\r
+l0cd5h:\r
+       call    get.hexdigit\r
+       jr      c,l0ce4h\r
+       add     hl,hl\r
+       add     hl,hl\r
+       add     hl,hl\r
+       add     hl,hl\r
+       call    ADD_HL_A\r
+       inc     de\r
+       jr      l0cd5h\r
+l0ce4h:\r
+       xor     'H'\r
+       ret     nz\r
+       inc     de\r
+       ret\r
+\r
+l0ce9h:\r
+       ld      hl,0\r
+l0cech:\r
+       call    get.bindigit\r
+l0cefh:\r
+       inc     de\r
+       jr      c,l0cf8h\r
+       add     hl,hl\r
+       call    ADD_HL_A\r
+       jr      l0cech\r
+l0cf8h:\r
+       cp      '"'\r
+       jp      nz,ERROR\r
+       call    get.bindigit\r
+       jr      nc,l0cefh\r
+       or      a\r
+       ret\r
+l0d04h:\r
+       ld      hl,0\r
+l0d07h:\r
+       call    get.decdigit\r
+       inc     de\r
+       jr      c,l0d1ah\r
+       push    bc\r
+       add     hl,hl           ;0d0e   hl *= 10\r
+       ld      b,h\r
+       ld      c,l\r
+       add     hl,hl\r
+       add     hl,hl\r
+       add     hl,bc\r
+       pop     bc\r
+       call    ADD_HL_A\r
+       jr      l0d07h\r
+l0d1ah:\r
+       cp      '.'\r
+       ret     z\r
+       jp      ERROR\r
+\r
+sub_0d20h:\r
+       ld      a,(de)\r
+       cp      05bh\r
+       jr      l0d28h\r
+\r
+get.hexdigit:\r
+       ld      a,(de)\r
+sub_0d26h:\r
+       cp      'F'+1\r
+l0d28h:\r
+       ccf\r
+       ret     c\r
+       cp      'A'\r
+       jr      c,l0d32h\r
+       sub     'A'-10\r
+       ret\r
+\r
+get.decdigit:\r
+       ld      a,(de)\r
+l0d32h:\r
+       cp      '9'+1\r
+       jr      l0d39h\r
+get.bindigit:\r
+       ld      a,(de)\r
+       cp      '1'+1\r
+l0d39h:\r
+       ccf\r
+       ret     c\r
+       cp      '0'\r
+       ret     c\r
+       sub     '0'\r
+       ret\r
+\r
+l0d41h:\r
+       call    assert_eol\r
+\r
+prnt_cpustat:\r
+       call    prnt_f\r
+       call    outbl2\r
+       ld      hl,b_0x0DFD_start\r
+       ld      de,b_0x0E1D_start\r
+       ld      b,006h\r
+l0d52h:\r
+       call    prnt_regs\r
+       djnz    l0d52h\r
+       push    hl\r
+       push    de\r
+       ld      iy,(REG.PC)\r
+       call    sub_1f77h\r
+       exx\r
+       ex      af,af'\r
+       call    CRLF\r
+       call    prnt_f2\r
+       call    outbl2\r
+       pop     de\r
+       pop     hl\r
+       ld      b,007h\r
+l0d6fh:\r
+       call    prnt_regs\r
+       djnz    l0d6fh\r
+       exx\r
+       ex      af,af'\r
+       and     a\r
+       jr      z,l0d7fh\r
+       call    outbl6\r
+       call    sub_1f5bh\r
+l0d7fh:\r
+       jp      crlf\r
+\r
+prnt_f:\r
+       ld      a,(reg.f)\r
+       call    prnt_flags\r
+       ld      a,(reg.iff)\r
+       cp      0f3h\r
+       jp      z,outbl\r
+       ld      a,'E'\r
+       jp      outchar\r
+\r
+prnt_f2:\r
+       ld      a,(reg.f2)\r
+       call    prnt_flags\r
+       jp      outbl\r
+\r
+prnt_flags:\r
+       ld      b,a\r
+       ld      a,'S'\r
+       call    sub_0dbeh\r
+       ld      a,'Z'\r
+       call    sub_0dbeh\r
+       rl      b\r
+       ld      a,'H'\r
+       call    sub_0dbeh\r
+       rl      b\r
+       ld      a,'V'\r
+       call    sub_0dbeh\r
+       ld      a,'N'\r
+       call    sub_0dbeh\r
+       ld      a,'C'\r
+sub_0dbeh:\r
+       rl      b\r
+       jp      c,OUTCHAR\r
+       jp      OUTBL\r
+\r
+prnt_regs:\r
+       push    bc\r
+       push    de\r
+       call    PSTR\r
+       ld      a,'='\r
+       call    OUTCHAR\r
+       ex      (sp),hl\r
+       ld      e,(hl)\r
+       inc     hl\r
+       ld      d,(hl)\r
+       inc     hl\r
+       ld      a,(hl)\r
+       inc     hl\r
+       push    hl\r
+       and     a\r
+       jr      z,l0df2h\r
+       push    af\r
+       ld      a,(de)\r
+       ld      l,a\r
+       inc     de\r
+       ld      a,(de)\r
+       ld      h,a\r
+       pop     af\r
+       dec     a\r
+       jr      z,l0dedh\r
+       call    out.hl.@\r
+       call    z,outbl6\r
+       jr      l0df6h\r
+l0dedh:\r
+       call    out.hl\r
+       jr      l0df6h\r
+l0df2h:\r
+       ld      a,(de)\r
+       call    out.hex\r
+l0df6h:\r
+       call    OUTBL\r
+       pop     de\r
+       pop     hl\r
+       pop     bc\r
+       ret\r
+\r
+b_0x0DFD_start:\r
+       DC      'A '\r
+       DC      'BC '\r
+       DC      'DE '\r
+       DC      'HL '\r
+       DC      'SP'\r
+       DC      'PC'\r
+       DC      'A'''\r
+       DC      'BC'''\r
+       DC      'DE'''\r
+       DC      'HL'''\r
+       DC      'IX'\r
+       DC      'IY'\r
+       DC      'I'\r
+       DB      0\r
+\r
+b_0x0E1D_start:\r
+       defw    reg.a\r
+       defb    000h\r
+       defw    reg.c\r
+       defb    001h\r
+       defw    reg.e\r
+       defb    001h\r
+       defw    reg.l\r
+       defb    001h\r
+       defw    reg.sp\r
+       defb    001h\r
+       defw    reg.pc\r
+       defb    002h\r
+       defw    reg.a2\r
+       defb    000h\r
+       defw    reg.c2\r
+       defb    001h\r
+       defw    reg.e2\r
+       defb    001h\r
+       defw    reg.l2\r
+       defb    001h\r
+       defw    reg.ix\r
+       defb    001h\r
+       defw    reg.iy\r
+       defb    001h\r
+       defw    reg.i\r
+       dw      0\r
+\r
+CMD.G:\r
+       sub     a\r
+       ld      (TCFLG),a\r
+       ld      (XA747),a\r
+       call    EXPR\r
+       jr      c,l0e54h\r
+       ld      (REG.PC),hl\r
+l0e54h:\r
+       call    SKIPBL\r
+       jp      z,l1183h\r
+       cp      ';'\r
+       jp      nz,ERROR\r
+       inc     de\r
+       ld      a,002h\r
+       call    sub_0f24h\r
+       jp      l1183h\r
+\r
+sub_0e68h:\r
+       ld      b,BP_CNT\r
+       ld      ix,bp_tab\r
+l0e6eh:\r
+       ld      a,(ix+000h)\r
+       and     0f1h\r
+       ld      (ix+000h),a\r
+       call    sub_11c5h\r
+       ld      de,BP_SIZE\r
+       add     ix,de\r
+       djnz    l0e6eh\r
+       ret\r
+\r
+CMD.B:\r
+       call    SKIPBL\r
+       jr      z,l0ecbh\r
+       inc     de\r
+       cp      'X'\r
+       jr      z,l0e91h\r
+       dec     de\r
+       ld      a,001h\r
+       jp      sub_0f24h\r
+l0e91h:\r
+       call    SKIPBL\r
+       jr      z,l0ea6h\r
+l0e96h:\r
+       call    EXPR\r
+       jp      c,assert_eol\r
+       push    de\r
+       call    sub_0ea7h\r
+       pop     de\r
+       call    skip_to_nextarg\r
+       jr      l0e96h\r
+l0ea6h:\r
+       scf\r
+sub_0ea7h:\r
+       ld      b,BP_CNT\r
+       ld      ix,bp_tab\r
+l0eadh:\r
+       push    af\r
+       jr      c,l0ebbh\r
+       ld      e,(ix+002h)\r
+       ld      d,(ix+003h)\r
+       call    CP.HL.DE\r
+       jr      nz,l0ec2h\r
+l0ebbh:\r
+       ld      (ix+000h),000h\r
+       call    sub_11c5h\r
+l0ec2h:\r
+       ld      de,BP_SIZE\r
+       add     ix,de\r
+       pop     af\r
+       djnz    l0eadh\r
+       ret\r
+l0ecbh:\r
+       ld      b,BP_CNT\r
+       ld      ix,bp_tab\r
+l0ed1h:\r
+       bit     0,(ix+000h)\r
+       jr      z,l0f1ch\r
+       ld      a,'R'\r
+       bit     4,(ix+000h)\r
+       jr      nz,l0ee1h\r
+       ld      a,' '\r
+l0ee1h:\r
+       call    OUTCHAR\r
+       call    OUTBL\r
+       ld      l,(ix+002h)\r
+       ld      h,(ix+003h)\r
+       call    out.hl.@\r
+       call    outbl2\r
+       ld      a,':'\r
+       call    OUTCHAR\r
+       ld      l,(ix+004h)\r
+       ld      h,(ix+005h)\r
+       call    out.hl\r
+       ld      l,(ix+006h)\r
+       ld      h,(ix+007h)\r
+       ld      a,h\r
+       or      l\r
+       jr      z,l0f19h\r
+       call    outbl4\r
+       ld      a,'I'\r
+       call    OUTCHAR\r
+       call    outbl2\r
+       call    PSTR\r
+l0f19h:\r
+       call    CRLF\r
+l0f1ch:\r
+       ld      de,BP_SIZE\r
+       add     ix,de\r
+       djnz    l0ed1h\r
+       ret\r
+\r
+sub_0f24h:\r
+       ld      b,a\r
+       call    SKIPBL\r
+       ret     z\r
+       cp      'R'\r
+       jr      nz,l0f30h\r
+       inc     de\r
+       set     4,b\r
+l0f30h:\r
+       push    bc\r
+       call    EXPR\r
+       jp      c,ERROR\r
+       pop     bc\r
+       bit     0,b\r
+       push    bc\r
+       push    de\r
+       push    hl\r
+       call    nz,sub_0ea7h\r
+       pop     hl\r
+       call    sub_0f68h\r
+       pop     de\r
+       ld      (ix+002h),l\r
+       ld      (ix+003h),h\r
+       call    sub_0f80h\r
+       ld      (ix+004h),l\r
+       ld      (ix+005h),h\r
+       call    sub_0f91h\r
+       ld      (ix+006h),l\r
+       ld      (ix+007h),h\r
+       call    skip_to_nextarg\r
+       pop     af\r
+       ld      (ix+000h),a\r
+       and     00fh\r
+       jr      sub_0f24h\r
+sub_0f68h:\r
+       ld      b,BP_CNT\r
+       ld      ix,bp_tab\r
+l0f6eh:\r
+       ld      a,(ix+000h)\r
+       and     00fh\r
+       ret     z\r
+       push    bc\r
+       ld      bc,BP_SIZE\r
+       add     ix,bc\r
+       pop     bc\r
+       djnz    l0f6eh\r
+       jp      ERROR\r
+\r
+sub_0f80h:\r
+       call    SKIPBL\r
+       ld      hl,1\r
+       cp      03ah\r
+       ret     nz\r
+       inc     de\r
+       call    EXPR\r
+       jp      c,ERROR\r
+       ret\r
+sub_0f91h:\r
+       call    SKIPBL\r
+       cp      049h\r
+       ld      hl,0\r
+       ret     nz\r
+       inc     de\r
+       call    SKIPBL\r
+       push    de\r
+       call    EXPR\r
+       jp      c,ERROR\r
+       ex      de,hl\r
+       pop     de\r
+       push    de\r
+       sbc     hl,de\r
+       ld      b,h\r
+       ld      c,l\r
+       ld      hl,(sexp1)\r
+       push    hl\r
+       add     hl,bc\r
+       ld      de,sexpbufe\r
+       call    CP.HL.DE\r
+       jp      nc,ERROR\r
+       pop     hl\r
+       ld      (sexp2),hl\r
+       pop     de\r
+       ex      de,hl\r
+       ldir\r
+       xor     a\r
+       ld      (de),a\r
+       inc     de\r
+       ex      de,hl\r
+       ld      (sexp1),hl\r
+       ld      hl,(sexp2)\r
+       ret\r
+\r
+bpddtz:\r
+       if ROMSYS\r
+        ld     h,ROMEN\r
+        jr     z,l0fd2h\r
+        inc    h\r
+l0fd2h:\r
+        push   hl              ;save rom enable stat\r
+       endif\r
+       push    bc\r
+       push    de\r
+       push    ix\r
+       push    iy\r
+       ld      a,i\r
+       ld      h,a\r
+       ld      l,000h\r
+       push    hl              ;save I register\r
+\r
+       if CPU_Z180\r
+        ld     a,0f3h          ;DI\r
+        jp     po,l0fe6h\r
+        ld     a,0fbh          ;EI\r
+       else                    ;NMOS Z80 design flaw\r
+        call   getiff          ;return Carry set, if INTs are disabled.\r
+        ld     a,0f3h          ;DI\r
+        jr     c,l0fe6h\r
+        ld     a,0fbh          ;EI\r
+       endif\r
+l0fe6h:\r
+       ld      (reg.iff),a\r
+       ld      hl,ivtab\r
+       ld      a,h\r
+       ld      i,a\r
+       call    ddtei\r
+       ex      af,af'\r
+       push    af\r
+       exx\r
+       push    bc\r
+       push    de\r
+       push    hl\r
+       call    bp.unset\r
+       if CPU_Z180\r
+        in0    a,(itc)\r
+        jp     p,l1017h\r
+        res    TRAP,a\r
+        out0   (itc),a\r
+        bit    UFO,a\r
+        jr     z,l1011h\r
+        ld     hl,(REG.PC)\r
+        dec    hl\r
+        ld     (REG.PC),hl\r
+l1011h:\r
+        ld     hl,MSG_trap\r
+        call   PSTR\r
+l1017h:\r
+       endif\r
+\r
+       ld      a,(XBFE8)\r
+       dec     a\r
+       jr      z,l1051h\r
+       call    inchar\r
+       jr      c,l102eh\r
+       call    sub_1059h\r
+       and     a\r
+       jp      z,l1183h\r
+       and     083h\r
+       jp      z,l284ah\r
+l102eh:\r
+       call    sub_0e68h\r
+       call prnt_cpustat\r
+       jp      DDTZML\r
+\r
+       if CPU_Z180\r
+MSG_trap:\r
+       DB      CR,LF,'Undefined opcode trap'\r
+       DB      CR,LF,0\r
+       endif\r
+\r
+l1051h:\r
+       ld (XBFE8),a\r
+       ld c,007h\r
+       jp l119fh\r
+sub_1059h:\r
+       ld a,080h\r
+       ex af,af'\r
+       sub a\r
+       ld (XA747),a\r
+       ld b,BP_CNT\r
+       ld ix,bp_tab\r
+l1066h:\r
+       ld a,(ix+000h)\r
+       and 007h\r
+       jr z,l107eh\r
+       ld e,(ix+002h)\r
+       ld d,(ix+003h)\r
+       ld hl,(REG.PC)\r
+       call CP.HL.DE\r
+       push bc\r
+       call z,sub_1087h\r
+       pop bc\r
+l107eh:\r
+       ld de,BP_SIZE\r
+       add ix,de\r
+       djnz l1066h\r
+       ex af,af'\r
+       ret\r
+sub_1087h:\r
+       ex af,af'\r
+       res 7,a\r
+       ex af,af'\r
+       ld e,(ix+006h)\r
+       ld d,(ix+007h)\r
+       ld a,d\r
+       or e\r
+       ld hl,0ffffh\r
+       call nz,EXPR\r
+       ld a,h\r
+       or l\r
+       jr z,l10aeh\r
+       ld e,(ix+004h)\r
+       ld d,(ix+005h)\r
+       dec de\r
+       ld a,d\r
+       or e\r
+       jr z,l10b9h\r
+       ld (ix+004h),e\r
+       ld (ix+005h),d\r
+l10aeh:\r
+       bit 4,(ix+000h)\r
+       ret z\r
+       ld a,001h\r
+       ld (XA747),a\r
+       ret\r
+l10b9h:\r
+       ex af,af'\r
+       or (ix+000h)\r
+       ex af,af'\r
+       ret\r
+\r
+bp.unset:\r
+       ld b,BP_CNT\r
+       ld ix,bp_tab\r
+l10c5h:\r
+       bit 5,(ix+000h)\r
+       res 5,(ix+000h)\r
+       jr z,l10e7h\r
+       ld l,(ix+002h)\r
+       ld h,(ix+003h)\r
+       ld a,(ddtzrst)\r
+       comst\r
+       cp (hl)\r
+       comend\r
+       jr nz,l10e7h\r
+       ld a,(ix+001h)\r
+       comst\r
+        ld (hl),a\r
+       comend\r
+l10e7h:\r
+       res 3,(ix+000h)\r
+       ld de,BP_SIZE\r
+       add ix,de\r
+       djnz l10c5h\r
+       ret\r
+sub_10f3h:\r
+       ld b,BP_CNT\r
+       ld ix,bp_tab\r
+l10f9h:\r
+       ld a,(ix+000h)\r
+       and 003h\r
+       jr z,l110dh\r
+       ld e,(ix+002h)\r
+       ld d,(ix+003h)\r
+       ld hl,(REG.PC)\r
+       call CP.HL.DE\r
+       ret z\r
+l110dh:\r
+       ld de,BP_SIZE\r
+       add ix,de\r
+       djnz l10f9h\r
+       sub a\r
+       inc a\r
+       ret\r
+sub_1117h:\r
+       call sub_0f68h\r
+       ld (ix+004h),001h\r
+       ld (ix+005h),000h\r
+       ld (ix+002h),l\r
+       ld (ix+003h),h\r
+       ld (ix+006h),000h\r
+       ld (ix+007h),000h\r
+       ld a,(XBFE8)\r
+       and a\r
+       ld a,008h\r
+       jr nz,l113ah\r
+       ld a,004h\r
+l113ah:\r
+       ld (ix+000h),a\r
+       ret\r
+\r
+bp.set:\r
+       ld b,BP_CNT\r
+       ld ix,bp_tab\r
+l1144h:\r
+       ld a,(ix+000h)\r
+       and c\r
+       jr z,l117bh\r
+       set 5,(ix+000h)\r
+       ld l,(ix+002h)\r
+       ld h,(ix+003h)\r
+\r
+\r
+       ld a,(ddtzrst)\r
+       comst\r
+       ld e,(hl)\r
+       ld (hl),a\r
+       comend\r
+       ld (ix+001h),e\r
+       and 038h\r
+       ld h,0\r
+       ld l,a\r
+       ld de,bpent\r
+       comst                   ;\r
+       ld (hl),0c3h\r
+       inc hl\r
+       ld (hl),e\r
+       inc hl\r
+       ld (hl),d\r
+       comend\r
+\r
+\r
+l117bh:\r
+       ld de,BP_SIZE\r
+       add ix,de\r
+       djnz l1144h\r
+       ret\r
+\r
+l1183h:\r
+       sub a\r
+       ld (XBFE8),a\r
+       ld a,(XA747)\r
+       and a\r
+       call nz,prnt_cpustat\r
+       call sub_10f3h\r
+       ld c,007h\r
+       jr nz,l119fh\r
+       ld a,001h\r
+       ld (XBFE8),a\r
+       call sub_26e7h\r
+       ld c,008h\r
+l119fh:\r
+       call bp.set\r
+       ld sp,$stack            ;11a2   set/restore user cpu state\r
+       pop hl\r
+       pop de\r
+       pop bc\r
+       pop af\r
+       exx\r
+       ex af,af'\r
+       pop af\r
+       ld i,a\r
+       pop iy\r
+       pop ix\r
+       pop de\r
+       pop bc\r
+       if ROMSYS\r
+        pop hl\r
+        ld a,l\r
+        and M_MWI\r
+        ld l,a\r
+        di\r
+        in0 a,(dcntl)\r
+        and ~M_MWI\r
+        or l\r
+        ld l,a\r
+        ld a,h\r
+       else\r
+        pop hl\r
+        di\r
+       endif\r
+       jp $go                  ;11c2   common ram, switch banks and go to user prog\r
+\r
+sub_11c5h:\r
+       ld a,(ix+000h)\r
+       and 003h\r
+       ret nz\r
+       ld e,(ix+006h)\r
+       ld d,(ix+007h)\r
+       ld a,d\r
+       or e\r
+       ret z\r
+       push bc\r
+       ld h,d\r
+       ld l,e\r
+       sub a\r
+       ld (ix+006h),a\r
+       ld (ix+007h),a\r
+       ld bc,0ffffh\r
+       cpir\r
+l11e3h:\r
+       push de\r
+       ld de,(sexp1)\r
+       call CP.HL.DE\r
+       pop de\r
+       jr nc,l11f9h\r
+       call sub_11ffh\r
+l11f1h:\r
+       ld a,(hl)\r
+       ldi\r
+       and a\r
+       jr nz,l11f1h\r
+       jr l11e3h\r
+l11f9h:\r
+       ld (sexp1),de\r
+       pop bc\r
+       ret\r
+sub_11ffh:\r
+       ld iy,bp_tab\r
+       push de\r
+l1204h:\r
+       ld e,(iy+006h)\r
+       ld d,(iy+007h)\r
+       call CP.HL.DE\r
+       jr z,l1216h\r
+       ld de,BP_SIZE\r
+       add iy,de\r
+       jr l1204h\r
+l1216h:\r
+       pop de\r
+       ld (iy+006h),e\r
+       ld (iy+007h),d\r
+       ret\r
+\r
+CMD.Y:\r
+       call get.decdigit\r
+       jr c,l122fh\r
+       inc de\r
+       push af\r
+       call assert_eol\r
+       pop af\r
+       call sub_1248h\r
+       jp l127ch\r
+l122fh:\r
+       call assert_eol\r
+       xor a\r
+l1233h:\r
+       push af\r
+       call sub_1248h\r
+       call outbl4\r
+       pop af\r
+       inc a\r
+       bit 0,a\r
+       push af\r
+       call z,CRLF\r
+       pop af\r
+       cp LF\r
+       jr c,l1233h\r
+       ret\r
+\r
+sub_1248h:\r
+       ld c,a\r
+       ld b,0\r
+       add a,'0'+080h\r
+       ld de,msg.Y+1\r
+       ld (de),a\r
+       dec de\r
+       ld hl,reg.Y\r
+       add hl,bc\r
+       add hl,bc\r
+       ex de,hl\r
+       ld c,003h\r
+       jp l129ah\r
+\r
+CMD.X:\r
+       call SKIPBL\r
+       call sub_1315h\r
+       jp nc,l0d41h\r
+       call assert_eol\r
+       ld a,b\r
+       cp 01fh\r
+       jr z,l12c6h\r
+       cp 020h\r
+       jr z,l12b6h\r
+       ex de,hl\r
+       ld hl,b_0x132A_start\r
+       call sub_0a48h\r
+l1279h:\r
+       call l129ah\r
+l127ch:\r
+       call OUTBL\r
+       push de\r
+       push bc\r
+       call INLINE\r
+       call SKIPBL\r
+       jr z,l1297h\r
+       call get_arg\r
+       ld b,h\r
+       ld c,l\r
+       pop af\r
+       pop hl\r
+       ld (hl),c\r
+       bit 0,a\r
+       ret z\r
+       inc hl\r
+       ld (hl),b\r
+       ret\r
+l1297h:\r
+       pop af\r
+       pop hl\r
+       ret\r
+l129ah:\r
+       ld b,c\r
+       call PSTR\r
+       ld a,'='\r
+       call OUTCHAR\r
+       ld a,(de)\r
+       bit 0,b\r
+       jp z,out.hex\r
+       ld l,a\r
+       inc de\r
+       ld a,(de)\r
+       dec de\r
+       ld h,a\r
+       bit 1,b\r
+       jp z,out.hl\r
+       jp out.hl.@\r
+\r
+l12b6h:\r
+       call prnt_f\r
+       ld a,0f3h\r
+       ld (reg.iff),a\r
+       scf\r
+       call sub_12d1h\r
+       ld (reg.f),a\r
+       ret\r
+\r
+l12c6h:\r
+       call prnt_f2\r
+       and a\r
+       call sub_12d1h\r
+       ld (reg.f2),a\r
+       ret\r
+\r
+sub_12d1h:\r
+       ex af,af'\r
+       ld b,000h\r
+       call outbl\r
+       call assert_eol\r
+       call inline\r
+l12ddh:\r
+       call skipbl\r
+       ld a,b\r
+       ret z\r
+       push bc\r
+       ld hl,tab_pr_flags\r
+       call lookupch\r
+       jp nc,error\r
+       ld a,b\r
+       cp 008h\r
+       jr z,l12feh\r
+       inc b\r
+       ld a,001h\r
+       jr l12f7h\r
+l12f6h:\r
+       rlca\r
+l12f7h:\r
+       djnz l12f6h\r
+       pop bc\r
+       or b\r
+       ld b,a\r
+       jr l12ddh\r
+l12feh:\r
+       ex af,af'\r
+       jp nc,ERROR\r
+       ex af,af'\r
+       ld a,0FBh\r
+       ld (reg.iff),a\r
+       pop bc\r
+       jr l12ddh\r
+\r
+tab_pr_flags:\r
+       db      'CNV H ZSE'\r
+       db      0\r
+\r
+sub_1315h:\r
+       call sub_0a0eh\r
+       ret nc\r
+       ld a,b\r
+       add a,b\r
+       add a,b\r
+       ld hl,b_0x136C_start\r
+       call ADD_HL_A\r
+       ld c,(hl)\r
+       inc hl\r
+       ld a,(hl)\r
+       inc hl\r
+       ld h,(hl)\r
+       ld l,a\r
+       scf\r
+       ret\r
+\r
+b_0x132A_start:\r
+       if ROMSYS\r
+        DC     'ROMSEL'\r
+       endif\r
+       if CPU_Z180\r
+       DC      'CBAR'\r
+       DC      'BBR'\r
+       else\r
+        DC     'BNK'\r
+       endif\r
+       DC      'BC'''\r
+       DC      'DE'''\r
+       DC      'HL'''\r
+       DC      'BC'\r
+       DC      'DE'\r
+       DC      'HL'\r
+       DC      'A'''\r
+       DC      'B'''\r
+       DC      'C'''\r
+       DC      'D'''\r
+       DC      'E'''\r
+       DC      'H'''\r
+       DC      'L'''\r
+       DC      'A'\r
+       DC      'B'\r
+       DC      'C'\r
+       DC      'D'\r
+       DC      'E'\r
+       DC      'H'\r
+       DC      'L'\r
+       DC      'IX'\r
+       DC      'IY'\r
+       DC      'SP'\r
+       DC      'PC'\r
+       DC      'X'\r
+       DC      'Y'\r
+       DC      'S'\r
+       DC      'P'\r
+       DC      'I'\r
+       DC      'F'''\r
+       DC      'F'\r
+       DB      0\r
+b_0x136C_start:\r
+       if      ROMSYS\r
+        defb   000h\r
+        defw   uromen\r
+       endif\r
+       if CPU_Z180\r
+       defb    000h\r
+       defw    ucbar\r
+       defb    000h\r
+       defw    ubbr\r
+       else\r
+        defb   000h\r
+        defw   ubnk\r
+       endif\r
+       defb    003h\r
+       defw    reg.c2\r
+       defb    003h\r
+       defw    reg.e2\r
+       defb    003h\r
+       defw    reg.l2\r
+       defb    003h\r
+       defw    reg.c\r
+       defb    003h\r
+       defw    reg.e\r
+       defb    003h\r
+       defw    reg.l\r
+       defb    000h\r
+       defw    reg.a2\r
+       defb    000h\r
+       defw    reg.b2\r
+       defb    000h\r
+       defw    reg.c2\r
+       defb    000h\r
+       defw    reg.d2\r
+       defb    000h\r
+       defw    reg.e2\r
+       defb    000h\r
+       defw    reg.h2\r
+       defb    000h\r
+       defw    reg.l2\r
+       defb    000h\r
+       defw    reg.a\r
+       defb    000h\r
+       defw    reg.b\r
+       defb    000h\r
+       defw    reg.c\r
+       defb    000h\r
+       defw    reg.d\r
+       defb    000h\r
+       defw    reg.e\r
+       defb    000h\r
+       defw    reg.h\r
+       defb    000h\r
+       defw    reg.l\r
+       defb    003h\r
+       defw    reg.ix\r
+       defb    003h\r
+       defw    reg.iy\r
+       defb    003h\r
+       defw    reg.sp\r
+       defb    003h\r
+       defw    reg.pc\r
+       defb    003h\r
+       defw    reg.ix\r
+       defb    003h\r
+       defw    reg.iy\r
+       defb    003h\r
+       defw    reg.sp\r
+       defb    003h\r
+       defw    reg.pc\r
+       defb    000h\r
+       defw    reg.i\r
+       defb    000h\r
+       defw    reg.f2\r
+       defb    000h\r
+       defw    reg.f\r
+CMD.S:\r
+       ld      hl,(lst.S)\r
+       call    get_lastarg_def\r
+l13d8h:\r
+       ld      (lst.S),hl\r
+       call    out.hl.@\r
+       call    OUTBL\r
+       comst\r
+       ld      a,(hl)\r
+       comend\r
+       call    out.hex\r
+       call    outbl2\r
+       call    INLINE\r
+       call    SKIPBL\r
+       inc     hl\r
+       jr      z,l13d8h\r
+       dec     hl\r
+       inc     de\r
+       cp      '.'\r
+       jp      z,assert_eol\r
+       cp      '-'\r
+       jr      nz,l1406h\r
+       ld      a,(de)\r
+       or      a\r
+       dec     hl\r
+       jr      z,l13d8h\r
+       inc     hl\r
+l1406h:\r
+       dec     de\r
+       call    get_bytes_m\r
+       jr      l13d8h\r
+\r
+CMD.@:\r
+       call    assert_eol\r
+       ld      hl,MSG_at\r
+       ld      de,offs.@\r
+       ld      c,001h\r
+       jp      l1279h\r
+MSG_at:\r
+       dc      '@'\r
+\r
+CMD.I:\r
+       ld      hl,CMD.I\r
+       ld      (CMD_RPT),hl\r
+       ld      hl,(lst.IP)\r
+       call    get_lastarg_def\r
+       ld      (lst.IP),hl\r
+       ld      b,h\r
+       ld      c,l\r
+       if CPU_Z180\r
+        ld     a,b\r
+        or     a\r
+        jr     nz,l1442h\r
+        ld     a,c\r
+        ld     hl,ucbar\r
+        cp     cbar\r
+        jr     z,l143fh\r
+        ld     hl,ubbr\r
+        cp     bbr\r
+        jr     nz,l1442h\r
+l143fh:\r
+        ld     a,(hl)\r
+        jr     l1444h\r
+l1442h:\r
+       endif\r
+       in      a,(c)\r
+l1444h:\r
+       push    af\r
+       call    out.hex\r
+       call    outbl4\r
+       pop     af\r
+       call    out.bin.b\r
+       jp      CRLF\r
+CMD.O:\r
+       ld      hl,CMD.O\r
+       ld      (CMD_RPT),hl\r
+       ld      hl,(lst.OD)\r
+       call    get_arg_def\r
+       ld      a,l\r
+       ld      (lst.OD),a\r
+       push    af\r
+       call    skip_to_nextarg\r
+       ld      hl,(lst.OP)\r
+       call    get_lastarg_def\r
+       ld      (lst.OP),hl\r
+       ld      b,h\r
+       ld      c,l\r
+       if CPU_Z180\r
+        ld     a,b\r
+        or     a\r
+        jr     nz,l1489h\r
+        ld     a,c\r
+        ld     hl,ucbar\r
+        cp     cbar\r
+        jr     z,l148dh\r
+        ld     hl,ubbr\r
+        cp     bbr\r
+        jr     z,l148dh\r
+        cp     cbr\r
+        jp     z,ERROR\r
+l1489h:\r
+       endif\r
+       pop     af\r
+       out     (c),a\r
+       ret\r
+       if CPU_Z180\r
+l148dh:\r
+        pop    af\r
+        ld     (hl),a\r
+        ret\r
+       endif\r
+\r
+CMD.V:\r
+       call    get_arg3                ;1490   get from, size, to\r
+cmp_mem:\r
+       push    bc\r
+       comst\r
+        ld     a,(de)\r
+        ld     b,(hl)\r
+       comend\r
+       cp      b\r
+       jr      z,l14bah\r
+       ld      c,a\r
+       call    out.hl.@\r
+       call    OUTBL\r
+       ld      a,b\r
+       call    out.hex\r
+       call    outbl2\r
+       ld      a,c\r
+       call    out.hex\r
+       call    OUTBL\r
+       ex      de,hl\r
+       call    out.hl.@\r
+       ex      de,hl\r
+       call    CRLF\r
+l14bah:\r
+       pop     bc\r
+       inc     hl\r
+       inc     de\r
+       dec     bc\r
+       ld      a,b\r
+       or      c\r
+       jr      nz,cmp_mem\r
+       ret\r
+\r
+CMD.M:\r
+       ld      a,(de)\r
+       cp      'V'\r
+       jr      nz,bm_nv\r
+       inc     de\r
+bm_nv:\r
+       push    af                      ;14c9   save 'V' flag\r
+       call    get_arg3\r
+       push    hl\r
+       push    de\r
+       push    bc\r
+       call    CP.HL.DE\r
+       jr      nc,bm_mvdown\r
+       add     hl,bc\r
+       ex      de,hl\r
+       add     hl,bc\r
+       ex      de,hl\r
+       dec     hl\r
+       dec     de\r
+       comst\r
+        lddr\r
+       comend\r
+       jr      bm_done\r
+bm_mvdown:\r
+       comst\r
+       ldir\r
+       comend\r
+bm_done:\r
+       pop     bc\r
+       pop     de\r
+       pop     hl\r
+       pop     af\r
+       jr      z,cmp_mem               ;14ed   validate?\r
+       ret\r
+CMD.H:\r
+       call    EXPR\r
+       jp      c,l173ch                ;no parameters, print High and Max\r
+       call    skip_to_nextarg\r
+       push    hl\r
+       call    EXPR\r
+       push    af\r
+       call    assert_eol\r
+       pop     af\r
+       ex      de,hl\r
+       pop     hl\r
+       jr      c,l1511h\r
+       push    hl\r
+       push    de\r
+       add     hl,de\r
+       call    l1511h\r
+       pop     de\r
+       pop     hl\r
+       and     a\r
+       sbc     hl,de\r
+l1511h:\r
+       call    out.hl                  ;1511   val\r
+       call    outbl2\r
+       call    sub_0928h               ;1517   -val\r
+       call    outbl4\r
+       call    out.hl.dec              ;151d   dec\r
+       call    outbl2\r
+       call    out.hl.decm             ;1523   -dec\r
+       call    outbl4\r
+       call    out.bin.w               ;1529   bin\r
+       call    outbl2\r
+       ld      a,l\r
+       call    out.ascii\r
+       jp      CRLF\r
+\r
+CMD.Q:\r
+       ld a,(de)\r
+       sub 'J'\r
+       ld (lst.Qj),a\r
+       jr nz,l153fh\r
+       inc de\r
+l153fh:\r
+       call get_arg_range\r
+       push bc\r
+       push hl\r
+       call sub_15a7h\r
+       pop hl\r
+l1548h:\r
+       call sub_1594h\r
+       jr nz,l1562h\r
+       push bc\r
+       push hl\r
+       ld a,(lst.Qj)\r
+       or a\r
+       jr nz,l1559h\r
+       ld bc,-8\r
+       add hl,bc\r
+l1559h:\r
+       ld bc,MEMDUMP_CNT\r
+       and a\r
+       call memdump\r
+       pop hl\r
+       pop bc\r
+l1562h:\r
+       inc hl\r
+       ex (sp),hl\r
+       dec hl\r
+       ld a,h\r
+       or l\r
+       ex (sp),hl\r
+       jr nz,l1548h\r
+       pop bc\r
+       ret\r
+\r
+CMD.Z:\r
+       call get_arg_range\r
+       push bc\r
+       push hl\r
+       call sub_15a7h\r
+       ld a,b\r
+       pop hl\r
+       pop bc\r
+       push hl\r
+       ex de,hl\r
+l1579h:\r
+       push af\r
+       ld a,(hl)\r
+       comst\r
+       ld (de),a\r
+       comend\r
+       pop af\r
+       inc de\r
+       cpi\r
+       jp po,l1592h\r
+       dec a\r
+       jr nz,l1579h\r
+       pop hl\r
+       comst\r
+       ldir\r
+       comend\r
+       ret\r
+l1592h:\r
+       pop hl\r
+       ret\r
+\r
+sub_1594h:\r
+       push hl\r
+       push de\r
+       push bc\r
+l1597h:\r
+       ld a,(de)\r
+       comst\r
+       cp (hl)\r
+       comend\r
+       jr nz,l15a3h\r
+       inc de\r
+       inc hl\r
+       djnz l1597h\r
+l15a3h:\r
+       pop bc\r
+       pop de\r
+       pop hl\r
+       ret\r
+\r
+sub_15a7h:\r
+       ld hl,ci.buf+1\r
+       call get_bytes\r
+       ld de,ci.buf+1\r
+       and a\r
+       sbc hl,de\r
+       ld b,l\r
+       ret nz\r
+       jp ERROR\r
+\r
+get_bytes:\r
+       db      0e6h            ;15b8  and 037h (clear carry, skip next opc)\r
+get_bytes_m:\r
+       scf\r
+l15bah:\r
+       push af\r
+       call skip_to_nextarg\r
+       cp 'W'\r
+       jr nz,l15d9h\r
+       inc de\r
+       push hl\r
+       call sub_0a68h\r
+       ex de,hl\r
+       pop bc\r
+       pop af\r
+       push af\r
+       push bc\r
+       ex (sp),hl\r
+       jr nc,l15d3h\r
+       comst\r
+l15d3h:\r
+       ld (hl),e\r
+       comend\r
+       inc hl\r
+       ld c,d\r
+       pop de\r
+       jr l15e5h\r
+l15d9h:\r
+       cp ''''\r
+       jr z,l15f1h\r
+       push hl\r
+       call EXPR\r
+       ld c,l\r
+       pop hl\r
+       jr c,l1626h\r
+l15e5h:\r
+       pop af\r
+       push af\r
+       jr nc,l15edh\r
+       comst\r
+l15edh:\r
+       ld (hl),c\r
+       comend\r
+       inc hl\r
+       jr l161eh\r
+l15f1h:\r
+       inc de\r
+       ld a,(de)\r
+       cp ''''\r
+       jr z,l1607h\r
+       or a\r
+       jr z,l1626h\r
+l15fah:\r
+       ld c,a\r
+       pop af\r
+       push af\r
+       jr nc,l1603h\r
+       comst\r
+l1603h:\r
+       ld (hl),c\r
+       comend\r
+       inc hl\r
+       jr l15f1h\r
+l1607h:\r
+       inc de\r
+       ld a,(de)\r
+       cp ''''\r
+       jr z,l15fah\r
+       cp '.'\r
+       jr nz,l161eh\r
+       inc de\r
+       dec hl\r
+       pop af\r
+       push af\r
+       jr nc,l161bh\r
+       comst\r
+l161bh:\r
+       set 7,(hl)\r
+       comend\r
+       inc hl\r
+l161eh:\r
+       pop af\r
+       jr nc,l15bah\r
+       ld (lst.S),hl\r
+       jr l15bah\r
+\r
+l1626h:\r
+       pop af\r
+       ret nc\r
+       ld (lst.S),hl\r
+       ret\r
+\r
+CMD.D:\r
+       ld hl,CMD.D\r
+       ld (CMD_RPT),hl\r
+       ld hl,(lst.D)\r
+       ld bc,00080h\r
+       call sub_0a82h\r
+       scf\r
+memdump:\r
+       push bc\r
+       push de\r
+       push hl\r
+       ex af,af'\r
+l1640h:\r
+       call out.hl.@\r
+       call z,outbl2\r
+       call OUTBL\r
+       ld de,0\r
+l164ch:\r
+       comst\r
+       ld a,(hl)\r
+       comend\r
+       inc hl\r
+       call out.hex\r
+       call OUTBL\r
+       dec bc\r
+       inc e\r
+       ld a,e\r
+       cp 010h\r
+       jr z,l1668h\r
+       and 003h\r
+       call z,OUTBL\r
+       ld a,b\r
+       or c\r
+       jr nz,l164ch\r
+l1668h:\r
+       call OUTBL\r
+       and a\r
+       sbc hl,de\r
+l166eh:\r
+       comst\r
+       ld a,(hl)\r
+       comend\r
+       call sub_168fh\r
+       call OUTCHAR\r
+       inc hl\r
+       dec e\r
+       jr nz,l166eh\r
+       ex af,af'\r
+       jr nc,l1683h\r
+       ld (lst.D),hl\r
+l1683h:\r
+       ex af,af'\r
+       call CRLF\r
+       ld a,b\r
+       or c\r
+       jr nz,l1640h\r
+       pop hl\r
+       pop de\r
+       pop bc\r
+       ret\r
+sub_168fh:\r
+       and 07fh\r
+       cp 07fh\r
+       jr z,l1698h\r
+       cp 020h\r
+       ret nc\r
+l1698h:\r
+       ld a,02eh\r
+       ret\r
+\r
+;      Read Intel Hex File from console.\r
+CMD.R:\r
+       ld hl,0\r
+       call get_lastarg_def    ;169e   get offset from command line\r
+       push hl\r
+       ld hl,0\r
+       ld (HILOD),hl\r
+w_recstart:\r
+       call i.getchar\r
+       jr z,l16deh\r
+       cp ':'\r
+       jr nz,w_recstart\r
+       ld c,0                  ;16b1   init checksum\r
+       call i.gethexbyte       ;16b3   record len\r
+       ld b,a\r
+       call i.gethexbyte       ;16b7   address high\r
+       ld h,a\r
+       call i.gethexbyte       ;16bb   address low\r
+       ld l,a\r
+       call i.gethexbyte       ;16bf   record type (ignored)\r
+       ld a,b\r
+       and a                   ;16c3   record len == 0?\r
+       jr z,l16deh\r
+l16c6h:\r
+       call i.gethexbyte\r
+       pop de                  ;16c9   offset\r
+       push de\r
+       push hl\r
+       add hl,de\r
+       call i.storebyte\r
+       pop hl\r
+       inc hl\r
+       djnz l16c6h             ;16d2   repeat for record len\r
+       call i.gethexbyte       ;16d4   checksum\r
+       ld a,c\r
+       and a\r
+       jp nz,ERROR             ;16d9   exit if checksum error\r
+       jr w_recstart           ;16dc   next record\r
+l16deh:\r
+       pop hl\r
+       call i.gethexbyte\r
+       jp l173fh\r
+\r
+i.gethexbyte:\r
+       call sub_16f6h\r
+       rlca\r
+       rlca\r
+       rlca\r
+       rlca\r
+       ld d,a\r
+       call sub_16f6h\r
+       add a,d\r
+       ld d,a\r
+       add a,c\r
+       ld c,a\r
+       ld a,d\r
+       ret\r
+\r
+sub_16f6h:\r
+       call i.getchar\r
+       jr z,l16ffh\r
+       call sub_0d26h\r
+       ret nc\r
+l16ffh:\r
+       jp ERROR\r
+\r
+i.getchar:\r
+       call $ci\r
+       cp 01ah\r
+       ret\r
+\r
+i.storebyte:\r
+       push af\r
+       push de\r
+       ld de,TPA               ;170a   lowest allowed load address\r
+       call CP.HL.DE\r
+       jp c,ERROR\r
+       ld de,$stcka            ;1713   highest allowed load address\r
+       call CP.HL.DE\r
+       jp nc,ERROR\r
+       ld de,(HILOD)\r
+       call CP.HL.DE\r
+       jr c,l1728h\r
+       ld (HILOD),hl\r
+l1728h:\r
+       ld de,(MAXLOD)\r
+       call CP.HL.DE\r
+       jr c,l1734h\r
+       ld (MAXLOD),hl\r
+l1734h:\r
+       pop de\r
+       pop af\r
+       comst\r
+       ld (hl),a               ;173a   store byte\r
+       comend\r
+       ret\r
+\r
+l173ch:\r
+       call assert_eol\r
+l173fh:\r
+       ld hl,MSG_high\r
+       call PSTR\r
+       ld hl,(HILOD)\r
+       call out.hl\r
+       ld hl,MSG_max\r
+       call PSTR\r
+       ld hl,(MAXLOD)\r
+       call out.hl\r
+       jp CRLF\r
+\r
+MSG_high:\r
+       DC      'High = '\r
+MSG_max:\r
+       DC      '  Max = '\r
+\r
+CMD.A:\r
+       ld hl,(lst.A)\r
+       call get_lastarg_def\r
+       push hl\r
+       pop iy\r
+       ld hl,l17c4h\r
+       ld (CMD_ERR),hl\r
+       ld (XB068),sp\r
+l177ch:\r
+       push iy\r
+       pop hl\r
+       ld (lst.A),hl\r
+       ld (OFFS.pc),hl\r
+       push hl\r
+       call sub_1f3fh\r
+       pop iy\r
+       ld c,b\r
+       ld de,(offs.@)\r
+       ld a,d\r
+       or e\r
+       ld b,011h\r
+       jr z,l1798h\r
+       ld b,019h\r
+l1798h:\r
+       call OUTBL\r
+       ld a,(CON.COL)\r
+       cp b\r
+       jr c,l1798h\r
+       push bc\r
+       call INLINE\r
+       pop bc\r
+       call SKIPBL\r
+       cp '.'\r
+       ret z\r
+       cp '-'\r
+       jr nz,l17b6h\r
+       ld iy,(XB06C)\r
+       jr l177ch\r
+l17b6h:\r
+       and a\r
+       call nz,sub_17cdh\r
+       ld (XB06C),iy\r
+       ld b,0\r
+       add iy,bc\r
+       jr l177ch\r
+l17c4h:\r
+       call l07eah\r
+       ld sp,(XB068)\r
+       jr l177ch\r
+\r
+sub_17cdh:\r
+       call SKIPBL\r
+       ld hl,t_MNEMONICS\r
+       call sub_0a15h\r
+       jp nc,ERROR\r
+       call SKIPBL\r
+       push de\r
+       ld a,b\r
+       add a,b\r
+       add a,b\r
+       ld hl,b_0x17EE_start\r
+       call ADD_HL_A\r
+       ld e,(hl)\r
+       inc hl\r
+       ld d,(hl)\r
+       inc hl\r
+       ld b,(hl)\r
+       ex de,hl\r
+       pop de\r
+       jp (hl)\r
+\r
+b_0x17EE_start:\r
+       defw l1b54h\r
+       defb 088h\r
+       defw l1b74h\r
+       defb 080h\r
+       defw l1babh\r
+       defb 0a0h\r
+       defw l1c14h\r
+       defb 040h\r
+       defw l1c38h\r
+       defb 0c4h\r
+       defw l1b36h\r
+       defb 03fh\r
+       defw l1babh\r
+       defb 0b8h\r
+       defw gen.opc.ED2\r
+       defb 0a9h\r
+       defw gen.opc.ED2\r
+       defb 0b9h\r
+       defw gen.opc.ED2\r
+       defb 0a1h\r
+       defw gen.opc.ED2\r
+       defb 0b1h\r
+       defw l1b36h\r
+       defb 02fh\r
+       defw l1b36h\r
+       defb 027h\r
+       defw l1dabh\r
+       defb 005h\r
+       defw l1b36h\r
+       defb 0f3h\r
+       defw l1ca4h\r
+       defb 010h\r
+       defw l1b36h\r
+       defb 0fbh\r
+       defw l1d54h\r
+       defb 0e3h\r
+       defw l1b36h\r
+       defb 0d9h\r
+       defw l1b36h\r
+       defb 076h\r
+       defw l1cbfh\r
+       defb 046h\r
+       defw l1cf8h\r
+       defb 040h\r
+       defw l1dabh\r
+       defb 004h\r
+       defw gen.opc.ED2\r
+       defb 0aah\r
+       defw gen.opc.ED2\r
+       defb 0bah\r
+       defw gen.opc.ED2\r
+       defb 0a2h\r
+       defw gen.opc.ED2\r
+       defb 0b2h\r
+       defw l1c5eh\r
+       defb 0c2h\r
+       defw l1cabh\r
+       defb 020h\r
+       defw l1934h\r
+       defb 040h\r
+       defw gen.opc.ED2\r
+       defb 0a8h\r
+       defw gen.opc.ED2\r
+       defb 0b8h\r
+       defw gen.opc.ED2\r
+       defb 0a0h\r
+       defw gen.opc.ED2\r
+       defb 0b0h\r
+       defw gen.opc.ED2\r
+       defb 044h\r
+       defw l1b36h\r
+       defb 000h\r
+       defw l1babh\r
+       defb 0b0h\r
+       defw gen.opc.ED2\r
+       defb 0bbh\r
+       defw gen.opc.ED2\r
+       defb 0b3h\r
+       defw l1d2ch\r
+       defb 041h\r
+       defw gen.opc.ED2\r
+       defb 0abh\r
+       defw gen.opc.ED2\r
+       defb 0a3h\r
+       defw l1ce4h\r
+       defb 0c1h\r
+       defw l1ce4h\r
+       defb 0c5h\r
+       defw l1c14h\r
+       defb 080h\r
+       defw l1c50h\r
+       defb 0c0h\r
+       defw gen.opc.ED2\r
+       defb 04dh\r
+       defw gen.opc.ED2\r
+       defb 045h\r
+       defw l1bd8h\r
+       defb 010h\r
+       defw l1b36h\r
+       defb 017h\r
+       defw l1bd8h\r
+       defb 000h\r
+       defw l1b36h\r
+       defb 007h\r
+       defw gen.opc.ED2\r
+       defb 06fh\r
+       defw l1bd8h\r
+       defb 018h\r
+       defw l1b36h\r
+       defb 01fh\r
+       defw l1bd8h\r
+       defb 008h\r
+       defw l1b36h\r
+       defb 00fh\r
+       defw gen.opc.ED2\r
+       defb 067h\r
+       defw l1cd5h\r
+       defb 0c7h\r
+       defw l1b54h\r
+       defb 098h\r
+       defw l1b36h\r
+       defb 037h\r
+       defw l1c14h\r
+       defb 0c0h\r
+       defw l1bd8h\r
+       defb 020h\r
+       defw l1bd8h\r
+       defb 028h\r
+       defw l1bd8h\r
+       defb 038h\r
+       defw l1babh\r
+       defb 090h\r
+       defw l1babh\r
+       defb 0a8h\r
+       defw A.IN0\r
+       defb 000h\r
+       defw A.MLT\r
+b_0x18BC_start:\r
+       defb 04ch\r
+       ld b,e\r
+       dec de\r
+\r
+b_0x18BF_start:\r
+       defb 08bh\r
+       defw gen.opc.ED2\r
+       defb 09bh\r
+       defw gen.opc.ED2\r
+       defb 083h\r
+       defw gen.opc.ED2\r
+       defb 093h\r
+       defw l18fdh\r
+       defb 001h\r
+       defw gen.opc.ED2\r
+       defb 076h\r
+       defw l191dh\r
+       defb 004h\r
+       defw l192ch\r
+       defb 074h\r
+A.IN0:\r
+       call sub_1e41h\r
+       jr nc,l1931h\r
+       cp 006h\r
+       jr z,l1931h\r
+       rlca\r
+       rlca\r
+       rlca\r
+       add a,b\r
+       ld b,a\r
+       call sub_1ed1h\r
+       call sub_1e06h\r
+l18e9h:\r
+       call assert_eol\r
+       comst\r
+       ld (iy+000h),0edh\r
+       ld (iy+001h),b\r
+       ld (iy+002h),l\r
+       comend\r
+       ld c,003h\r
+       ret\r
+l18fdh:\r
+       call sub_1e06h\r
+       call sub_1ed1h\r
+       call sub_1e41h\r
+       jr nc,l1931h\r
+       cp 006h\r
+       jr z,l1931h\r
+       rlca\r
+       rlca\r
+       rlca\r
+       add a,b\r
+       ld b,a\r
+       jr l18e9h\r
+A.MLT:\r
+       call sub_1e2eh\r
+       jr nc,l1931h\r
+       add a,b\r
+       ld b,a\r
+       jp gen.opc.ED2\r
+l191dh:\r
+       call sub_1e41h\r
+       jr nc,l192ah\r
+       rlca\r
+       rlca\r
+       rlca\r
+       add a,b\r
+       ld b,a\r
+       jp gen.opc.ED2\r
+l192ah:\r
+       ld b,064h\r
+l192ch:\r
+       call sub_1e12h\r
+       jr l18e9h\r
+l1931h:\r
+       jp ERROR\r
+l1934h:\r
+       call sub_1e41h\r
+       jp c,l19bfh\r
+       call sub_1e68h\r
+       jp c,l1a64h\r
+       call sub_1e2eh\r
+       jp c,l1a93h\r
+       call sub_1e50h\r
+       jp c,l1af0h\r
+       ld a,(de)\r
+       cp 049h\r
+       jp z,l1b0ch\r
+       cp 052h\r
+       jp z,l1b14h\r
+       cp 028h\r
+       jp nz,ERROR\r
+       inc de\r
+       call sub_1e2eh\r
+       jp c,l1b23h\r
+       call tst_EXPR\r
+       call sub_1ed8h\r
+       call sub_1ed1h\r
+       call sub_1e2eh\r
+       jr c,l19adh\r
+       call sub_1e50h\r
+       jr nc,l1991h\r
+       ld b,022h\r
+l1978h:\r
+       call assert_eol\r
+       ld a,(pfx.IXY)\r
+l197eh:\r
+       comst\r
+       ld (iy+000h),a\r
+       ld (iy+001h),b\r
+       ld (iy+002h),l\r
+       ld (iy+003h),h\r
+       comend\r
+       ld c,004h\r
+       ret\r
+l1991h:\r
+       ld a,(de)\r
+       cp 041h\r
+       jp nz,ERROR\r
+       inc de\r
+       ld b,032h\r
+l199ah:\r
+       call assert_eol\r
+       comst\r
+       ld (iy+000h),b\r
+       ld (iy+001h),l\r
+       ld (iy+002h),h\r
+       comend\r
+       ld c,003h\r
+       ret\r
+l19adh:\r
+       cp 020h\r
+       jr z,l19bbh\r
+       add a,043h\r
+       ld b,a\r
+l19b4h:\r
+       call assert_eol\r
+       ld a,0edh\r
+       jr l197eh\r
+l19bbh:\r
+       ld b,022h\r
+       jr l199ah\r
+l19bfh:\r
+       ld b,a\r
+       call sub_1ed1h\r
+       call sub_1e41h\r
+       jr nc,l19dbh\r
+       push af\r
+       ld a,b\r
+       rlca\r
+       rlca\r
+       rlca\r
+       ld b,a\r
+       pop af\r
+       add a,b\r
+       add a,040h\r
+       cp 076h\r
+       jp z,ERROR\r
+l19d7h:\r
+       ld b,a\r
+       jp l1b36h\r
+l19dbh:\r
+       call sub_1e68h\r
+       jr nc,l1a02h\r
+       ld a,b\r
+       rlca\r
+       rlca\r
+       rlca\r
+       add a,046h\r
+       cp 076h\r
+       jp z,ERROR\r
+l19ebh:\r
+       ld b,a\r
+       call assert_eol\r
+       ld a,(pfx.IXY)\r
+       comst\r
+       ld (iy+000h),a\r
+       ld (iy+001h),b\r
+       ld (iy+002h),c\r
+       comend\r
+       ld c,003h\r
+       ret\r
+l1a02h:\r
+       ld a,(de)\r
+       cp 'I'\r
+       jr z,l1a15h\r
+       cp 'R'\r
+       jr nz,l1a21h\r
+       ld a,b\r
+       cp 007h\r
+       jp nz,ERROR\r
+       ld b,05fh\r
+       jr l1a1dh\r
+l1a15h:\r
+       ld a,b\r
+       cp 007h\r
+       jp nz,ERROR\r
+       ld b,057h\r
+l1a1dh:\r
+       inc de\r
+       jp gen.opc.ED2\r
+l1a21h:\r
+       cp '('\r
+       jr z,l1a3fh\r
+       call sub_1e12h\r
+       ld a,b                  ;1a28   ld r,nn\r
+       rlca\r
+       rlca\r
+       rlca\r
+       add a,006h\r
+l1a2eh:\r
+       ld b,a\r
+l1a2fh:\r
+       call assert_eol\r
+       comst\r
+       ld (iy+000h),b\r
+       ld (iy+001h),l\r
+       comend\r
+       ld c,002h\r
+       ret\r
+l1a3fh:\r
+       inc de\r
+       ld a,b\r
+       cp 007h\r
+       jp nz,ERROR\r
+       call sub_1e2eh\r
+       jr nc,l1a59h\r
+       cp 030h\r
+       jp nc,ERROR\r
+       add a,00ah\r
+       ld b,a\r
+       call sub_1ed8h\r
+       jp l1b36h\r
+l1a59h:\r
+       call tst_EXPR\r
+       call sub_1ed8h\r
+       ld b,03ah\r
+       jp l199ah\r
+l1a64h:\r
+       call sub_1ed1h\r
+       call sub_1e41h\r
+       jr nc,l1a76h\r
+       cp 006h\r
+       jp z,ERROR\r
+       add a,070h\r
+       jp l19ebh\r
+l1a76h:\r
+       call sub_1e12h\r
+       call assert_eol\r
+       ld a,(pfx.IXY)\r
+       comst\r
+       ld (iy+000h),a          ;1a83   dd/fd\r
+       ld (iy+001h),036h\r
+       ld (iy+002h),c          ;1a8a   displacement\r
+       ld (iy+003h),l          ;1a8d   nn\r
+       comend\r
+       ld c,4\r
+       ret\r
+l1a93h:\r
+       ld b,a\r
+       call sub_1ed1h\r
+       ld hl,t_HL.AF\r
+       call sub_0a23h\r
+       jr c,l1abeh\r
+       call sub_1e50h\r
+       jr nc,l1ac7h\r
+       ld a,b\r
+       cp 030h\r
+       jr nz,l1b20h\r
+       ld b,0f9h\r
+l1aabh:\r
+       call assert_eol\r
+       ld a,(pfx.IXY)\r
+       comst\r
+       ld (iy+000h),a\r
+       ld (iy+001h),b\r
+       comend\r
+       ld c,002h\r
+       ret\r
+l1abeh:\r
+       ld a,b\r
+       cp 030h\r
+       jr nz,l1b20h\r
+       ld b,0f9h\r
+       jr l1b36h\r
+l1ac7h:\r
+       ld a,(de)\r
+       cp 028h\r
+       jr nz,l1ae3h\r
+       inc de\r
+       call tst_EXPR\r
+       call sub_1ed8h\r
+       ld a,b\r
+       cp 020h\r
+       jr z,l1adeh\r
+       add a,04bh\r
+       ld b,a\r
+       jp l19b4h\r
+l1adeh:\r
+       ld b,02ah\r
+       jp l199ah\r
+l1ae3h:\r
+       call tst_EXPR\r
+       call assert_eol\r
+       ld a,001h\r
+       add a,b\r
+       ld b,a\r
+       jp l199ah\r
+l1af0h:\r
+       call sub_1ed1h\r
+       ld a,(de)\r
+       cp 028h\r
+       jr nz,l1b04h\r
+       inc de\r
+       call tst_EXPR\r
+       call sub_1ed8h\r
+       ld b,02ah\r
+       jp l1978h\r
+l1b04h:\r
+       call tst_EXPR\r
+       ld b,021h\r
+       jp l1978h\r
+l1b0ch:\r
+       inc de\r
+       call sub_1ed1h\r
+       ld b,047h\r
+       jr l1b1ah\r
+l1b14h:\r
+       inc de\r
+       call sub_1ed1h\r
+       ld b,04fh\r
+l1b1ah:\r
+       ld a,(de)\r
+       inc de\r
+       cp 041h\r
+       jr z,gen.opc.ED2\r
+l1b20h:\r
+       jp ERROR\r
+l1b23h:\r
+       cp 020h\r
+       jr nc,l1b20h\r
+       add a,002h\r
+       ld b,a\r
+       call sub_1ed8h\r
+       call sub_1ed1h\r
+       ld a,(de)\r
+       cp 041h\r
+       jr nz,l1b20h\r
+       inc de\r
+l1b36h:\r
+       call assert_eol\r
+       comst\r
+       ld (iy+000h),b\r
+       comend\r
+       ld c,001h\r
+       ret\r
+gen.opc.ED2:\r
+       call assert_eol\r
+       comst\r
+       ld (iy+000h),0edh\r
+       ld (iy+001h),b\r
+       comend\r
+       ld c,002h\r
+       ret\r
+l1b54h:\r
+       ld hl,t_HL.AF\r
+       call sub_0a23h\r
+       jr nc,l1babh\r
+       call sub_1ed1h\r
+       call sub_1e2eh\r
+       jp nc,ERROR\r
+       push af\r
+       ld a,b\r
+       cp 088h\r
+       ld b,04ah\r
+       jr z,l1b6fh\r
+       ld b,042h\r
+l1b6fh:\r
+       pop af\r
+       add a,b\r
+l1b71h:\r
+       ld b,a\r
+       jr gen.opc.ED2\r
+l1b74h:\r
+       ld hl,t_HL.AF\r
+       call sub_0a23h\r
+       jr c,l1b9dh\r
+       call sub_1e50h\r
+       jr nc,l1babh\r
+       call sub_1ed1h\r
+       ld hl,t_BC.DE.IX.SP\r
+       ld a,(pfx.IXY)\r
+       cp 0fdh\r
+       jr nz,l1b91h\r
+       ld hl,t_BC.DE.IY.SP\r
+l1b91h:\r
+       call sub_1e2bh\r
+       jp nc,ERROR\r
+       add a,009h\r
+l1b99h:\r
+       ld b,a\r
+       jp l1aabh\r
+l1b9dh:\r
+       call sub_1ed1h\r
+       call sub_1e2eh\r
+       jp nc,ERROR\r
+       add a,009h\r
+       jp l19d7h\r
+l1babh:\r
+       ld a,(de)\r
+       cp 041h\r
+       jr nz,l1bbbh\r
+       push de\r
+       inc de\r
+       call skip_to_nextarg\r
+       jr z,l1bbah\r
+       pop de\r
+       jr l1bbbh\r
+l1bbah:\r
+       pop af\r
+l1bbbh:\r
+       call sub_1e41h\r
+       jr c,l1bceh\r
+       call sub_1e68h\r
+       jr c,l1bd2h\r
+       call sub_1e12h\r
+       ld a,b\r
+       add a,046h\r
+       jp l1a2eh\r
+l1bceh:\r
+       add a,b\r
+       jp l19d7h\r
+l1bd2h:\r
+       ld a,b\r
+       add a,006h\r
+       jp l19ebh\r
+l1bd8h:\r
+       call sub_1e41h\r
+       jr c,l1c01h\r
+       call sub_1e68h\r
+       jp nc,ERROR\r
+       ld a,b\r
+       add a,006h\r
+       ld b,a\r
+l1be7h:\r
+       call assert_eol\r
+       ld a,(pfx.IXY)\r
+       comst\r
+       ld (iy+000h),a\r
+       ld (iy+001h),0cbh\r
+       ld (iy+002h),c\r
+       ld (iy+003h),b\r
+       comend\r
+       ld c,004h\r
+       ret\r
+l1c01h:\r
+       add a,b\r
+l1c02h:\r
+       ld b,a\r
+       call assert_eol\r
+       comst\r
+       ld (iy+000h),0cbh\r
+       ld (iy+001h),b\r
+       comend\r
+       ld c,002h\r
+       ret\r
+l1c14h:\r
+       call sub_1de6h\r
+       call sub_1ed1h\r
+       call sub_1e41h\r
+       jr c,l1c2fh\r
+       call sub_1e68h\r
+       jp nc,ERROR\r
+       ld a,l\r
+       rlca\r
+       rlca\r
+       rlca\r
+       add a,006h\r
+       add a,b\r
+       ld b,a\r
+       jr l1be7h\r
+l1c2fh:\r
+       add a,b\r
+       ld b,a\r
+       ld a,l\r
+       rlca\r
+       rlca\r
+       rlca\r
+       add a,b\r
+       jr l1c02h\r
+l1c38h:\r
+       push de\r
+       call sub_1eb8h\r
+       jr nc,l1c47h\r
+       add a,b\r
+       ld b,a\r
+       call skip_to_nextarg\r
+       jr z,l1c49h\r
+       pop de\r
+       push de\r
+l1c47h:\r
+       ld b,0cdh\r
+l1c49h:\r
+       pop af\r
+       call tst_EXPR\r
+       jp l199ah\r
+l1c50h:\r
+       call sub_1eb8h\r
+       jr nc,l1c59h\r
+       add a,b\r
+       ld b,a\r
+       jr l1c5bh\r
+l1c59h:\r
+       ld b,0c9h\r
+l1c5bh:\r
+       jp l1b36h\r
+l1c5eh:\r
+       push de\r
+       call sub_1eb8h\r
+       jr c,l1c71h\r
+l1c64h:\r
+       pop de\r
+       ld hl,b_0x1C97_start\r
+       call sub_0a15h\r
+       jr c,l1c7fh\r
+       ld b,0c3h\r
+       jr l1c79h\r
+l1c71h:\r
+       add a,b\r
+       ld b,a\r
+       call skip_to_nextarg\r
+       jr nz,l1c64h\r
+       pop af\r
+l1c79h:\r
+       call tst_EXPR\r
+       jp l199ah\r
+l1c7fh:\r
+       call assert_eol\r
+       ld a,b\r
+       and a\r
+       jr nz,l1c8bh\r
+       ld b,0e9h\r
+       jp l1b36h\r
+l1c8bh:\r
+       ld b,0ddh\r
+       dec a\r
+       jr z,l1c92h\r
+       ld b,0fdh\r
+l1c92h:\r
+       ld l,0e9h\r
+       jp l1a2fh\r
+\r
+b_0x1C97_start:\r
+       DC      '(HL)'\r
+       DC      '(IX)'\r
+       DC      '(IY)'\r
+       DB      0\r
+\r
+l1ca4h:\r
+       call skip_to_nextarg\r
+       ld b,010h\r
+       jr l1cb9h\r
+l1cabh:\r
+       call sub_1ebfh\r
+       jr c,l1cb4h\r
+       ld b,018h\r
+       jr l1cb9h\r
+l1cb4h:\r
+       add a,b\r
+       ld b,a\r
+       call sub_1ed1h\r
+l1cb9h:\r
+       call sub_1defh\r
+       jp l1a2fh\r
+l1cbfh:\r
+       call sub_1e12h\r
+       ld a,l\r
+       cp 003h\r
+       jr nc,l1d23h\r
+       and a\r
+       jr z,l1cd2h\r
+       ld b,056h\r
+       cp 001h\r
+       jr z,l1cd2h\r
+       ld b,05eh\r
+l1cd2h:\r
+       jp gen.opc.ED2\r
+l1cd5h:\r
+       call sub_1e12h\r
+       ld a,l\r
+       push af\r
+       add a,b\r
+       ld b,a\r
+       pop af\r
+       and 0c7h\r
+       jr nz,l1d23h\r
+       jp l1b36h\r
+l1ce4h:\r
+       call sub_1e50h\r
+       jr c,l1cf2h\r
+       call sub_1e25h\r
+       jr nc,l1d23h\r
+       add a,b\r
+       jp l19d7h\r
+l1cf2h:\r
+       ld a,b\r
+       add a,020h\r
+       jp l1b99h\r
+l1cf8h:\r
+       call sub_1e41h\r
+       jr nc,l1d23h\r
+       cp 006h\r
+       jr z,l1d23h\r
+       rlca\r
+       rlca\r
+       rlca\r
+       add a,b\r
+       ld b,a\r
+       cp 078h\r
+       jr nz,l1d1ah\r
+       call sub_1ed1h\r
+       call sub_1d26h\r
+       jr c,l1d20h\r
+       call sub_1e06h\r
+       ld b,0dbh\r
+       jp l1a2fh\r
+l1d1ah:\r
+       call sub_1ed1h\r
+       call sub_1d26h\r
+l1d20h:\r
+       jp c,gen.opc.ED2\r
+l1d23h:\r
+       jp ERROR\r
+sub_1d26h:\r
+       ld hl,t__C_\r
+       jp sub_0a23h\r
+l1d2ch:\r
+       call sub_1d26h\r
+       jr nc,l1d44h\r
+       call sub_1ed1h\r
+       call sub_1e41h\r
+       jr nc,l1d23h\r
+       cp 006h\r
+       jr z,l1d23h\r
+       rlca\r
+       rlca\r
+       rlca\r
+       add a,b\r
+       jp l1b71h\r
+l1d44h:\r
+       call sub_1e06h\r
+       call sub_1ed1h\r
+       cp 041h\r
+       jr nz,l1d23h\r
+       inc de\r
+       ld b,0d3h\r
+       jp l1a2fh\r
+l1d54h:\r
+       ld hl,b_0x1D80_start\r
+       call sub_0a15h\r
+       jp nc,ERROR\r
+       ld c,b\r
+       call assert_eol\r
+       ld b,000h\r
+       ld hl,b_0x1DA1_start\r
+       add hl,bc\r
+       add hl,bc\r
+       ld a,(hl)\r
+       comst\r
+       ld (iy+000h),a\r
+       comend\r
+       ld c,001h\r
+       inc hl\r
+       ld a,(hl)\r
+       and a\r
+       ret z\r
+       comst\r
+       ld (iy+001h),a\r
+       comend\r
+       ld c,002h\r
+       ret\r
+\r
+b_0x1D80_start:\r
+       DC      'AF,AF'''\r
+l1d86h:\r
+       DC      'DE,HL'\r
+       DC      '(SP),HL'\r
+       DC      '(SP),IX'\r
+       DC      '(SP),IY'\r
+       db      000h\r
+\r
+b_0x1DA1_start:\r
+       db      008h\r
+       db      000h\r
+       db      0ebh\r
+       db      000h\r
+       db      0e3h\r
+       db      000h\r
+       db      0ddh\r
+       db      0e3h\r
+       db      0fdh\r
+       db      0e3h\r
+l1dabh:\r
+       call sub_1e50h\r
+       jr c,l1dc6h\r
+       call sub_1e2eh\r
+       jr c,l1dd2h\r
+       call sub_1e41h\r
+       jr c,l1ddfh\r
+       call sub_1e68h\r
+       jp nc,ERROR\r
+       ld a,b\r
+       add a,030h\r
+       jp l19ebh\r
+l1dc6h:\r
+       ld a,b\r
+       ld b,023h\r
+       cp 004h\r
+       jr z,l1dcfh\r
+       ld b,02bh\r
+l1dcfh:\r
+       jp l1aabh\r
+l1dd2h:\r
+       push af\r
+       ld a,b\r
+       ld b,003h\r
+       cp 004h\r
+       jr z,l1ddch\r
+       ld b,00bh\r
+l1ddch:\r
+       pop af\r
+       jr l1de2h\r
+l1ddfh:\r
+       rlca\r
+       rlca\r
+       rlca\r
+l1de2h:\r
+       add a,b\r
+       jp l19d7h\r
+sub_1de6h:\r
+       call sub_1e12h\r
+       ld a,l\r
+       cp 008h\r
+       jr nc,error1\r
+       ret\r
+sub_1defh:\r
+       call tst_EXPR\r
+       push bc\r
+       push iy\r
+       pop bc\r
+       and a\r
+       sbc hl,bc\r
+       dec hl\r
+       dec hl\r
+       pop bc\r
+       call sub_1e15h\r
+       ld a,h\r
+       xor l\r
+       bit 7,a\r
+       jr nz,error1\r
+       ret\r
+sub_1e06h:\r
+       ld a,(de)\r
+       cp 028h\r
+       jr nz,sub_1e12h\r
+       inc de\r
+       call sub_1e12h\r
+       jp sub_1ed8h\r
+\r
+sub_1e12h:\r
+       call tst_EXPR\r
+sub_1e15h:\r
+       ld a,h\r
+       and a\r
+       ret z\r
+       inc a\r
+       ret z\r
+       jr error1\r
+\r
+tst_EXPR:\r
+       push bc\r
+       call EXPR\r
+       pop bc\r
+       ret nc\r
+error1:\r
+       jp ERROR\r
+sub_1e25h:\r
+       push hl\r
+       ld hl,t_BC.DE.HL.AF\r
+       jr l1e32h\r
+sub_1e2bh:\r
+       push hl\r
+       jr l1e32h\r
+sub_1e2eh:\r
+       push hl\r
+       ld hl,t_BC.DE.HL.SP\r
+l1e32h:\r
+       push bc\r
+       call sub_0a15h\r
+       jr nc,l1e3eh\r
+       ld a,b\r
+       rlca\r
+       rlca\r
+       rlca\r
+       rlca\r
+       scf\r
+l1e3eh:\r
+       pop bc\r
+       pop hl\r
+       ret\r
+sub_1e41h:\r
+       call SKIPBL\r
+       push bc\r
+       push hl\r
+       ld hl,t_BCDEHL_HL_A\r
+       call sub_0a15h\r
+       ld a,b\r
+       pop hl\r
+       pop bc\r
+       ret\r
+sub_1e50h:\r
+       push hl\r
+       push bc\r
+       ld hl,t_IX.IY\r
+       call sub_0a15h\r
+       jr nc,l1e65h\r
+       ld a,0ddh\r
+       dec b\r
+       jr nz,l1e61h\r
+       ld a,0fdh\r
+l1e61h:\r
+       ld (pfx.IXY),a\r
+       scf\r
+l1e65h:\r
+       pop bc\r
+       pop hl\r
+       ret\r
+sub_1e68h:\r
+       push hl\r
+       push bc\r
+       ld a,(de)\r
+       cp '('\r
+       jr nz,l1eb4h\r
+       push de\r
+       inc de\r
+       ld hl,t_IX.IY\r
+       call sub_0a15h\r
+       jr nc,l1eb3h\r
+       pop af\r
+       ld a,0ddh\r
+       dec b\r
+       jr nz,l1e81h\r
+       ld a,0fdh\r
+l1e81h:\r
+       ld (pfx.IXY),a\r
+       ld a,(de)\r
+       cp '+'\r
+       jr z,l1e95h\r
+       cp ')'\r
+       ld hl,0\r
+       jr z,l1eadh\r
+       cp '-'\r
+       jp nz,ERROR\r
+l1e95h:\r
+       push af\r
+       inc de\r
+       call sub_1e12h          ;1e97   get displacement\r
+       pop af\r
+       cp '+'\r
+       jr z,l1ea7h\r
+       ld b,h\r
+       ld c,l\r
+       ld hl,0\r
+       and a\r
+       sbc hl,bc\r
+l1ea7h:\r
+       ld a,(de)\r
+       cp ')'\r
+       jp nz,ERROR\r
+l1eadh:\r
+       inc de\r
+       pop bc\r
+       ld c,l\r
+       pop hl\r
+       scf\r
+       ret\r
+l1eb3h:\r
+       pop de\r
+l1eb4h:\r
+       pop bc\r
+       pop hl\r
+       and a\r
+       ret\r
+sub_1eb8h:\r
+       ld hl,t_tstfl_ZCPS\r
+       ld c,007h\r
+       jr l1ec4h\r
+sub_1ebfh:\r
+       ld hl,t_tstfl_ZC\r
+       ld c,003h\r
+l1ec4h:\r
+       push bc\r
+       call sub_0a15h\r
+       ld a,b\r
+       pop bc\r
+       ret nc\r
+       and c\r
+       rlca\r
+       rlca\r
+       rlca\r
+       scf\r
+       ret\r
+sub_1ed1h:\r
+       call skip_to_nextarg\r
+       ret z\r
+l1ed5h:\r
+       jp ERROR\r
+sub_1ed8h:\r
+       ld a,(de)\r
+       cp 029h\r
+       jr nz,l1ed5h\r
+       inc de\r
+       ret\r
+CMD.L:\r
+       ld hl,CMD.L\r
+       ld (CMD_RPT),hl\r
+       call EXPR\r
+       jr nc,l1eedh\r
+       ld hl,(lst.L)\r
+l1eedh:\r
+       push hl\r
+       pop iy\r
+       call skip_to_nextarg\r
+       call sub_0aa5h\r
+       jr nc,l1f17h\r
+       call assert_eol\r
+       ld b,010h\r
+l1efdh:\r
+       push bc\r
+       push iy\r
+       pop hl\r
+       push hl\r
+       call sub_1f3fh\r
+       call CRLF\r
+       pop iy\r
+       ld c,b\r
+       ld b,000h\r
+       add iy,bc\r
+       ld (lst.L),iy\r
+       pop bc\r
+       djnz l1efdh\r
+       ret\r
+l1f17h:\r
+       call assert_eol\r
+       ld h,b\r
+       ld l,c\r
+       ld a,b\r
+       or c\r
+       jr nz,l1f21h\r
+       dec hl\r
+l1f21h:\r
+       push hl\r
+       push iy\r
+       pop hl\r
+       push hl\r
+       call sub_1f3fh\r
+       call CRLF\r
+       pop iy\r
+       ld e,b\r
+       ld d,000h\r
+       add iy,de\r
+       ld (lst.L),iy\r
+       pop hl\r
+       and a\r
+       sbc hl,de\r
+       ret z\r
+       ret c\r
+       jr l1f21h\r
+sub_1f3fh:\r
+       call out.hl.@\r
+       call z,OUTBL\r
+       call OUTBL\r
+       sub a\r
+       ld (CON.COL),a\r
+       call sub_1f77h\r
+       and a\r
+       ret z\r
+l1f51h:\r
+       call OUTBL\r
+       ld a,(CON.COL)\r
+       cp 010h\r
+       jr c,l1f51h\r
+sub_1f5bh:\r
+       ld de,(offs.@)\r
+       ld a,d\r
+       or e\r
+       ret z\r
+       ld a,'('\r
+       call OUTCHAR\r
+       ld a,'@'\r
+       call OUTCHAR\r
+       and a\r
+       sbc hl,de\r
+       call out.hl\r
+       ld a,')'\r
+       jp OUTCHAR\r
+sub_1f77h:\r
+       sub a\r
+       ld (XBE03),a\r
+       call sub_1f9eh\r
+       jr nc,l1f91h\r
+       push bc\r
+       call sub_2581h\r
+       ex de,hl\r
+       call sub_1fdbh\r
+       pop bc\r
+       ld a,(XBE03)\r
+       ld hl,(XBE01)\r
+       scf\r
+       ret\r
+l1f91h:\r
+       ld hl,b_0x1F9B_start\r
+       call PSTR\r
+       ld b,001h\r
+       sub a\r
+       ret\r
+\r
+b_0x1F9B_start:\r
+       DC      '???'\r
+\r
+sub_1f9eh:\r
+       sub a\r
+       ld (is.pfx.IXY),a\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+       cp 0edh\r
+       jp z,disas_pfx.ED\r
+       cp 0ddh\r
+       jr z,l1fc5h\r
+       cp 0fdh\r
+       jr z,l1fc9h\r
+sub_1fb6h:\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+       cp 0cbh\r
+       jp z,l2061h\r
+       jp l2078h\r
+l1fc5h:\r
+       ld a,001h\r
+       jr l1fcbh\r
+l1fc9h:\r
+       ld a,002h\r
+l1fcbh:\r
+       ld (is.pfx.IXY),a\r
+       call sub_1fdch\r
+       ret nc\r
+       push bc\r
+       call sub_1fb6h\r
+       pop af\r
+       add a,b\r
+       ld b,a\r
+       scf\r
+       ret\r
+\r
+sub_1fdbh:\r
+       jp (hl)\r
+\r
+sub_1fdch:\r
+       inc iy\r
+       ld hl,b_0x2011_start\r
+       call sub_20bbh\r
+       ld b,002h\r
+       ret c\r
+       ld hl,l202ch\r
+       call sub_20bbh\r
+       ld b,001h\r
+       ret c\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+       cp 0cbh\r
+       jr nz,l200fh\r
+       comst\r
+       ld a,(iy+002h)\r
+       comend\r
+       cp 036h\r
+       ret z\r
+       and 007h\r
+       cp 006h\r
+       jr nz,l200fh\r
+       ld b,002h\r
+       scf\r
+       ret\r
+l200fh:\r
+       and a\r
+       ret\r
+\r
+b_0x2011_start:\r
+       db      034h\r
+       db      035h\r
+       db      036h\r
+       db      046h\r
+       db      04eh\r
+       db      056h\r
+       db      05eh\r
+       db      066h\r
+       db      06eh\r
+       db      070h\r
+       db      071h\r
+       db      072h\r
+       db      073h\r
+       db      074h\r
+       db      075h\r
+       db      076h\r
+       db      077h\r
+       db      07eh\r
+       db      086h\r
+       db      08eh\r
+       db      096h\r
+       db      09eh\r
+       db      0a6h\r
+       db      0aeh\r
+       db      0b6h\r
+       db      0beh\r
+       db      000h\r
+l202ch:\r
+       db      009h\r
+       db      019h\r
+       db      021h\r
+       db      022h\r
+       db      023h\r
+       db      029h\r
+       db      02ah\r
+       db      02bh\r
+       db      039h\r
+       db      0e1h\r
+       db      0e3h\r
+       db      0e5h\r
+       db      0e9h\r
+       db      0f9h\r
+       db      000h\r
+\r
+disas_pfx.ED:\r
+       inc iy\r
+       ld hl,b_0x2200_start\r
+       call sub_209dh\r
+       ld b,002h\r
+       ret c\r
+       ld hl,l2235h\r
+       call lookup_opc\r
+       ld b,002h\r
+       ret c\r
+       ld hl,l228bh\r
+       call lookup_opc\r
+       ld b,003h\r
+       ret c\r
+       ld hl,l22b4h\r
+       call lookup_opc\r
+       ld b,004h\r
+       ret\r
+l2061h:\r
+       push iy\r
+       inc iy\r
+       ld a,(is.pfx.IXY)\r
+       and a\r
+       jr z,l206dh\r
+       inc iy\r
+l206dh:\r
+       ld hl,l22c9h\r
+       call lookup_opc\r
+       pop iy\r
+       ld b,002h\r
+       ret\r
+l2078h:\r
+       ld hl,b_0x218B_start\r
+       call lookup_opc\r
+       ld b,002h\r
+       ret c\r
+       ld hl,b_0x20ED_start\r
+       call sub_209dh\r
+       ld b,001h\r
+       ret c\r
+       ld hl,b_0x2108_start\r
+       call lookup_opc\r
+       ld b,001h\r
+       ret c\r
+       ld hl,b_0x21D2_start\r
+       call lookup_opc\r
+       ret nc\r
+       ld b,003h\r
+       ret\r
+\r
+sub_209dh:\r
+       ld a,(hl)\r
+       cp 0ffh\r
+       ret z\r
+       comst\r
+       cp (iy+000h)\r
+       comend\r
+       jr z,l20aeh\r
+       inc hl\r
+       inc hl\r
+       jr sub_209dh\r
+l20aeh:\r
+       inc hl\r
+       ld c,(hl)\r
+       ld hl,t_MNEMONICS\r
+       ld b,000h\r
+       add hl,bc\r
+       ld de,l230bh\r
+       scf\r
+       ret\r
+sub_20bbh:\r
+       ld a,(hl)\r
+       and a\r
+       ret z\r
+       inc hl\r
+       comst\r
+       cp (iy+000h)\r
+       comend\r
+       jr nz,sub_20bbh\r
+       scf\r
+       ret\r
+\r
+lookup_opc:\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+       and (hl)\r
+       inc hl\r
+       cp (hl)\r
+       jr z,l20dfh\r
+       inc hl\r
+       inc hl\r
+       inc hl\r
+       inc hl\r
+       ld a,(hl)\r
+       and a\r
+       jr nz,lookup_opc\r
+       ret\r
+l20dfh:\r
+       inc hl\r
+       ld c,(hl)\r
+       inc hl\r
+       ld e,(hl)\r
+       inc hl\r
+       ld d,(hl)\r
+       ld hl,t_MNEMONICS\r
+       ld b,000h\r
+       add hl,bc\r
+       scf\r
+       ret\r
+\r
+b_0x20ED_start:                        ;       1 byte opcodes (no parameters)\r
+       db      076h            ;20ed   halt\r
+       db      039h            ;20ee\r
+       db      0d9h            ;20ef   exx\r
+       db      036h\r
+       db      0f3h            ;20f1   di\r
+       db      02ch\r
+       db      0fbh            ;20f3   ei\r
+       db      032h\r
+       db      000h            ;20f5   nop\r
+       db      069h\r
+       db      007h            ;20f7   rlca\r
+       db      09eh\r
+       db      00fh            ;20f9   rrca\r
+       db      0adh\r
+       db      017h            ;20fb   rla\r
+       db      098h\r
+       db      01fh            ;20fd   rra\r
+       db      0a7h\r
+       db      027h            ;20ff   daa\r
+       db      026h\r
+       db      02fh            ;2101   cpl\r
+       db      023h\r
+       db      037h            ;2103   scf\r
+       db      0bah\r
+       db      03fh            ;2105   ccf\r
+       db      010h\r
+       db      0ffh            ;2107   EOT\r
+\r
+b_0x2108_start:                        ;       1 byte opcodes\r
+       defb 0c0h               ;2108   ld r,r\r
+       defb 040h\r
+       defb 056h\r
+       defw l22fch\r
+\r
+       defb 0f8h               ;210d   add a,r\r
+       defb 080h\r
+       defb 003h\r
+       defw l2305h\r
+\r
+       defb 0f8h               ;2112   adc a,r\r
+       defb 088h\r
+       defb 000h\r
+       defw l2305h\r
+\r
+       defb 0f8h\r
+       defb 090h\r
+       defb 0c9h\r
+       defw l24ebh\r
+\r
+       defb 0f8h\r
+       defb 098h\r
+       defb 0b7h\r
+       defw l2305h\r
+\r
+       defb 0f8h\r
+       defb 0a0h\r
+       defb 006h\r
+       defw l24ebh\r
+\r
+       defb 0f8h\r
+       defb 0a8h\r
+       defb 0cch\r
+       defw l24ebh\r
+\r
+       defb 0f8h\r
+       defb 0b0h\r
+       defb 06ch\r
+       defw l24ebh\r
+\r
+       defb 0f8h\r
+       defb 0b8h\r
+       defb 013h\r
+       defw l24ebh\r
+\r
+       defb 0c7h\r
+       defb 0c0h               ;2136   ret cc\r
+       defb 08bh\r
+       defw l2561h\r
+\r
+       defb 0c7h               ;213a   rst\r
+       defb 0c7h\r
+       defb 0b4h\r
+       defw l231eh\r
+\r
+       defb 0ffh               ;213f   ret\r
+       defb 0c9h\r
+       defb 08bh\r
+       defw l230bh\r
+\r
+       defb 0cfh               ;2144   pop rr\r
+       defb 0c1h\r
+       defb 081h\r
+       defw l2546h\r
+\r
+       defb 0cfh               ;2149   push rr\r
+       defb 0c5h\r
+       defb 084h\r
+       defw l2546h\r
+\r
+       defb 0ffh               ;214e   ex (sp),hl\r
+       defb 0e3h\r
+       defb 034h\r
+       defw l232ah\r
+\r
+       defb 0ffh               ;2153   jp (hl)\r
+       defb 0e9h\r
+       defb 052h\r
+       defw l2338h\r
+\r
+       defb 0ffh               ;2158   ex de,hl\r
+       defb 0ebh\r
+       defb 034h\r
+       defw l2345h\r
+\r
+       defb 0ffh               ;215d   ld sp,hl\r
+       defb 0f9h\r
+       defb 056h\r
+       defw l234bh\r
+\r
+       defb 0cfh               ;2162   inc rr\r
+       defb 003h\r
+       defb 041h\r
+       defw l254bh\r
+\r
+       defb 0cfh               ;2167   dec rr\r
+       defb 00bh\r
+       defb 029h\r
+       defw l254bh\r
+\r
+\r
+       defb 0c7h               ;216c   inc r\r
+       defb 004h\r
+       defb 041h\r
+       defw l24dfh\r
+\r
+       defb 0c7h               ;2171   dec r\r
+       defb 005h\r
+       defb 029h\r
+       defw l24dfh\r
+\r
+       defb 0ffh               ;2176   ex af,af'\r
+       defb 008h\r
+       defb 034h\r
+       defw l2357h\r
+\r
+       defb 0cfh               ;217b   add hl,rr\r
+       defb 009h\r
+       defb 003h\r
+       defw l235dh\r
+\r
+       defb 0efh               ;2180   ld (rr),a ;rr=bc,de\r
+       defb 002h\r
+       defb 056h\r
+       defw l2366h\r
+\r
+       defb 0efh               ;2185   ld a,(rr) ;rr=bc,de\r
+       defb 00ah\r
+       defb 056h\r
+       defw l236fh\r
+\r
+       defb 000h               ;218a   EOT\r
+\r
+b_0x218B_start:                        ;       2 byte opdodes\r
+       defb 0c7h               ;218b   ld r,nn\r
+       defb 006h\r
+       defb 056h\r
+       defw l2384h\r
+\r
+       defb 0ffh               ;2190   add a,nn\r
+       defb 0c6h\r
+       defb 003h\r
+       defw l237fh\r
+\r
+       defb 0ffh               ;2195   adc a,nn\r
+       defb 0ceh\r
+       defb 000h\r
+       defw l237fh\r
+\r
+       defb 0ffh               ;219a   sub a,nn\r
+       defb 0d6h\r
+       defb 0c9h\r
+       defw l2397h\r
+\r
+       defb 0ffh\r
+       defb 0deh\r
+       defb 0b7h\r
+       defw l237fh\r
+\r
+       defb 0ffh               ;21a4   and a,nn\r
+       defb 0e6h\r
+       defb 006h\r
+       defw l2397h\r
+\r
+       defb 0ffh\r
+       defb 0eeh\r
+       defb 0cch\r
+       defw l2397h\r
+\r
+       defb 0ffh\r
+       defb 0f6h\r
+       defb 06ch\r
+       defw l2397h\r
+\r
+       defb 0ffh               ;21b3   cp a,nn\r
+       defb 0feh\r
+       defb 013h\r
+       defw l2397h\r
+\r
+       defb 0ffh               ;21b8   djnz\r
+       defb 010h\r
+       defb 02eh\r
+       defw l23b0h\r
+\r
+       defb 0ffh               ;21bd   jr\r
+       defb 018h\r
+       defb 054h\r
+       defw l23b0h\r
+\r
+       defb 0e7h               ;21c2   jr,cc\r
+       defb 020h\r
+       defb 054h\r
+       defw l23a1h\r
+\r
+       defb 0ffh\r
+       defb 0d3h               ;21c8   out (nn),a\r
+       defb 076h\r
+       defw l23d5h\r
+\r
+       defb 0ffh               ;21cc   in a,(nn)\r
+       defb 0dbh\r
+       defb 03fh\r
+       defw l23c3h\r
+\r
+       defb 000h               ;21d1   EOT\r
+\r
+b_0x21D2_start:                        ;       3 byte opcodes\r
+       defb 0c7h\r
+       defb 0c2h\r
+       defb 052h\r
+       defw l23e0h\r
+\r
+       defb 0c7h\r
+       defb 0c4h\r
+       defb 00ch\r
+       defw l23e0h\r
+\r
+       defb 0cfh\r
+       defb 001h\r
+       defb 056h\r
+       defw l23fch\r
+\r
+       defb 0ffh\r
+       defb 0c3h\r
+       defb 052h\r
+       defw l23e6h\r
+\r
+       defb 0ffh\r
+       defb 0cdh\r
+       defb 00ch\r
+       defw l23e6h\r
+\r
+       defb 0ffh\r
+       defb 022h\r
+       defb 056h\r
+       defw l2404h\r
+\r
+       defb 0ffh\r
+       defb 02ah\r
+       defb 056h\r
+       defw l240dh\r
+\r
+       defb 0ffh\r
+       defb 032h\r
+       defb 056h\r
+       defw l2416h\r
+\r
+       defb 0ffh\r
+       defb 03ah\r
+       defb 056h\r
+       defw l2421h\r
+\r
+       defb 000h\r
+\r
+b_0x2200_start:                        ;       prefix ED + 1 byte opcode\r
+       defb 044h               ;2200   neg\r
+       defb 066h\r
+       defb 045h               ;2202   retn\r
+       defb 092h\r
+       defb 04dh               ;2204   reti\r
+       defb 08eh\r
+       defb 067h               ;2206   rrd\r
+       defb 0b1h\r
+       defb 06fh               ;2208   rld\r
+       defb 0a2h\r
+       defb 0a0h               ;220a   ldi\r
+       defb 05fh\r
+       defb 0a1h\r
+       defb 01ch\r
+       defb 0a2h\r
+       defb 04bh\r
+       defb 0a3h\r
+       defb 07dh\r
+       defb 0a8h               ;2212   ldd\r
+       defb 058h\r
+       defb 0a9h\r
+       defb 015h\r
+       defb 0aah\r
+       defb 044h\r
+       defb 0abh\r
+       defb 079h\r
+       defb 0b0h               ;221a   ldir\r
+       defb 062h\r
+       defb 0b1h\r
+       defb 01fh\r
+       defb 0b2h\r
+       defb 04eh\r
+       defb 0b3h\r
+       defb 072h\r
+       defb 0b8h               ;2222   lddr\r
+       defb 05bh\r
+       defb 0b9h\r
+       defb 018h\r
+       defb 0bah\r
+       defb 047h\r
+       defb 0bbh\r
+       defb 06eh\r
+       defb 08bh               ;222a   otdm\r
+       defb 0d5h\r
+       defb 09bh               ;222c   otdmr\r
+       defb 0d9h\r
+       defb 083h               ;222e   otim\r
+       defb 0deh\r
+       defb 093h               ;2230   otimr\r
+       defb 0e2h\r
+       defb 076h               ;2232   slp\r
+       defb 0ebh\r
+       defb 0ffh               ;2234   EOT\r
+\r
+l2235h:\r
+       defb 0e7h               ;2235   in r,(c) ;r=bcde\r
+       defb 040h\r
+       defb 03fh\r
+       defw l2455h\r
+\r
+       defb 0f7h               ;223a   in r,(c) ;r=hl\r
+       defb 060h\r
+       defb 03fh\r
+       defw l2455h\r
+\r
+       defb 0ffh               ;223f   in r,(c) ;r=a\r
+       defb 078h\r
+       defb 03fh\r
+       defw l2455h\r
+\r
+       defb 0e7h\r
+       defb 041h\r
+       defb 076h\r
+       defw l2461h\r
+\r
+       defb 0f7h\r
+       defb 061h\r
+       defb 076h\r
+       defw l2461h\r
+\r
+       defb 0ffh               ;224e   out (c),r ;r=a\r
+       defb 079h\r
+       defb 076h\r
+       defw l2461h\r
+\r
+       defb 0cfh               ;2253   sbc hl,rr\r
+       defb 042h\r
+       defb 0b7h\r
+       defw l246dh\r
+\r
+       defb 0cfh               ;2258   adc hl,rr\r
+       defb 04ah\r
+       defb 000h\r
+       defw l246dh\r
+\r
+       defb 0ffh               ;225d   im 0\r
+       defb 046h\r
+       defb 03dh\r
+       defw l2427h\r
+\r
+       defb 0ffh               ;2262   im 1\r
+       defb 056h\r
+       defb 03dh\r
+       defw l242bh\r
+\r
+       defb 0ffh               ;2267   im 2\r
+       defb 05eh\r
+       defb 03dh\r
+       defw l242fh\r
+\r
+       defb 0ffh               ;226c   ld i,a\r
+       defb 047h\r
+       defb 056h\r
+       defw l2434h\r
+\r
+       defb 0ffh\r
+       defb 057h\r
+       defb 056h\r
+       defw l2439h\r
+\r
+       defb 0ffh\r
+       defb 04fh\r
+       defb 056h\r
+       defw l243eh\r
+\r
+       defb 0ffh\r
+       defb 05fh\r
+       defb 056h\r
+       defw l2443h\r
+\r
+       defb 0cfh               ;2280   mlt rr\r
+       defb 04ch\r
+       defb 0d2h\r
+       defw l254bh\r
+\r
+       defb 0c7h               ;2285   tst r\r
+       defb 004h\r
+       defb 0eeh\r
+       defw l24dfh\r
+\r
+       defb 000h\r
+\r
+l228bh:\r
+       defb 0e7h\r
+       defb 000h\r
+       defb 0cfh\r
+       defw l230ch\r
+\r
+       defb 0f7h\r
+       defb 020h\r
+       defb 0cfh\r
+       defw l230ch\r
+\r
+       defb 0ffh\r
+       defb 038h\r
+       defb 0cfh\r
+       defw l230ch\r
+\r
+       defb 0e7h\r
+       defb 001h\r
+       defb 0e7h\r
+       defw l2315h\r
+\r
+       defb 0f7h\r
+       defb 021h\r
+       defb 0e7h\r
+       defw l2315h\r
+\r
+       defb 0ffh\r
+       defb 039h\r
+       defb 0e7h\r
+       defw l2315h\r
+\r
+       defb 0ffh\r
+       defb 064h\r
+       defb 0eeh\r
+       defw l2397h\r
+\r
+       defb 0ffh\r
+       defb 074h\r
+       defb 0f1h\r
+       defw l2397h\r
+       defb 000h\r
+\r
+l22b4h:\r
+       defb 0efh\r
+       defb 043h\r
+       defb 056h\r
+\r
+b_0x22B7_start:\r
+       defw l2476h\r
+\r
+b_0x22B9_start:\r
+       defb 0ffh\r
+       defb 073h\r
+       defb 056h\r
+\r
+b_0x22BC_start:\r
+       defw l2476h\r
+\r
+b_0x22BE_start:\r
+       defb 0efh\r
+       defb 04bh\r
+       defb 056h\r
+\r
+b_0x22C1_start:\r
+       defw l247fh\r
+\r
+b_0x22C3_start:\r
+       defb 0ffh\r
+       defb 07bh\r
+       defb 056h\r
+\r
+b_0x22C6_start:\r
+       defw l247fh\r
+\r
+b_0x22C8_start:\r
+       defb 000h\r
+l22c9h:\r
+       defb 0f8h\r
+       defb 000h\r
+       defb 09bh\r
+\r
+b_0x22CC_start:\r
+       defw l24aeh\r
+\r
+b_0x22CE_start:\r
+       defb 0f8h\r
+       defb 008h\r
+       defb 0aah\r
+\r
+b_0x22D1_start:\r
+       defw l24aeh\r
+\r
+b_0x22D3_start:\r
+       defb 0f8h\r
+       defb 010h\r
+       defb 096h\r
+\r
+b_0x22D6_start:\r
+       defw l24aeh\r
+\r
+b_0x22D8_start:\r
+       defb 0f8h\r
+       defb 018h\r
+       defb 0a5h\r
+\r
+b_0x22DB_start:\r
+       defw l24aeh\r
+\r
+b_0x22DD_start:\r
+       defb 0f8h\r
+       defb 020h\r
+       defb 0c0h\r
+\r
+b_0x22E0_start:\r
+       defw l24aeh\r
+\r
+b_0x22E2_start:\r
+       defb 0f8h\r
+       defb 028h\r
+       defb 0c3h\r
+\r
+b_0x22E5_start:\r
+       defw l24aeh\r
+\r
+b_0x22E7_start:\r
+       defb 0f8h\r
+       defb 038h\r
+       defb 0c6h\r
+\r
+b_0x22EA_start:\r
+       defw l24aeh\r
+\r
+b_0x22EC_start:\r
+       defb 0c0h\r
+       defb 040h\r
+       defb 009h\r
+\r
+b_0x22EF_start:\r
+       defw l2487h\r
+\r
+b_0x22F1_start:\r
+       defb 0c0h\r
+       defb 080h\r
+       defb 088h\r
+\r
+b_0x22F4_start:\r
+       defw l2487h\r
+\r
+b_0x22F6_start:\r
+       defb 0c0h\r
+       defb 0c0h\r
+       defb 0bdh\r
+\r
+b_0x22F9_start:\r
+       defw l2487h\r
+\r
+b_0x22FB_start:\r
+       defb 000h\r
+l22fch:\r
+       call l24dfh\r
+       call sub_257ch\r
+       jp l24ebh\r
+l2305h:\r
+       call sub_2579h\r
+       jp l24ebh\r
+l230bh:\r
+       ret\r
+l230ch:\r
+       call l24dfh\r
+       call sub_257ch\r
+       jp l23c6h\r
+l2315h:\r
+       call l23c6h\r
+       call sub_257ch\r
+       jp l24dfh\r
+l231eh:\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+       and 038h\r
+       jp out.hex\r
+l232ah:\r
+       ld hl,b_0x2333_start\r
+       call PSTR\r
+       jp l253eh\r
+\r
+b_0x2333_start:\r
+       DC      '(SP),'\r
+\r
+l2338h:\r
+       ld a,'('\r
+       call OUTCHAR\r
+       call l253eh\r
+       ld a,')'\r
+       jp OUTCHAR\r
+l2345h:\r
+       ld hl,l1d86h\r
+       jp PSTR\r
+l234bh:\r
+       ld hl,b_0x2354_start\r
+       call PSTR\r
+       jp l253eh\r
+\r
+b_0x2354_start:\r
+       DC      'SP,'\r
+\r
+l2357h:\r
+       ld hl,b_0x1D80_start\r
+       jp PSTR\r
+l235dh:\r
+       call l253eh\r
+       call sub_257ch\r
+       jp l254bh\r
+l2366h:\r
+       call sub_2372h\r
+       call sub_257ch\r
+       jp l23dbh\r
+l236fh:\r
+       call sub_2579h\r
+sub_2372h:\r
+       ld a,'('\r
+       call OUTCHAR\r
+       call l254bh\r
+       ld a,')'\r
+       jp OUTCHAR\r
+l237fh:\r
+       call sub_2579h\r
+       jr l2397h\r
+l2384h:\r
+       call l24dfh\r
+       call sub_257ch\r
+       ld a,(is.pfx.IXY)\r
+       and a\r
+       comst\r
+       ld a,(iy+002h)\r
+       comend\r
+       jr nz,l239eh\r
+l2397h:\r
+       comst\r
+       ld a,(iy+001h)\r
+       comend\r
+l239eh:\r
+       jp out.hex\r
+l23a1h:\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+       and 018h\r
+       call sub_2568h\r
+       call sub_257ch\r
+l23b0h:\r
+       comst\r
+       ld c,(iy+001h)\r
+       comend\r
+       ld a,c\r
+       rla\r
+       sbc a,a\r
+       ld b,a\r
+       push iy\r
+       pop hl\r
+       add hl,bc\r
+       inc hl\r
+       inc hl\r
+       jr l23f0h\r
+l23c3h:\r
+       call sub_2579h\r
+l23c6h:\r
+       ld a,028h\r
+       call OUTCHAR\r
+       comst\r
+       ld a,(iy+001h)\r
+       comend\r
+       jp l252bh\r
+l23d5h:\r
+       call l23c6h\r
+       call sub_257ch\r
+l23dbh:\r
+       ld a,041h\r
+       jp OUTCHAR\r
+l23e0h:\r
+       call l2561h\r
+       call sub_257ch\r
+l23e6h:\r
+       comst\r
+       ld l,(iy+001h)\r
+       ld h,(iy+002h)\r
+       comend\r
+l23f0h:\r
+       ld a,002h\r
+sub_23f2h:\r
+       ld (XBE03),a\r
+       ld (XBE01),hl\r
+       call out.hl\r
+       ret\r
+l23fch:\r
+       call l254bh\r
+       call sub_257ch\r
+       jr l23e6h\r
+l2404h:\r
+       call sub_24c6h\r
+       call sub_257ch\r
+       jp l253eh\r
+l240dh:\r
+       call l253eh\r
+       call sub_257ch\r
+       jp sub_24c6h\r
+l2416h:\r
+       call sub_24c6h\r
+       call sub_257ch\r
+       ld a,041h\r
+       jp OUTCHAR\r
+l2421h:\r
+       call sub_2579h\r
+       jp sub_24c6h\r
+l2427h:\r
+       ld a,030h\r
+       jr l2431h\r
+l242bh:\r
+       ld a,031h\r
+       jr l2431h\r
+l242fh:\r
+       ld a,032h\r
+l2431h:\r
+       jp OUTCHAR\r
+l2434h:\r
+       ld hl,b_0x2449_start\r
+       jr l2446h\r
+l2439h:\r
+       ld hl,l244ch\r
+       jr l2446h\r
+l243eh:\r
+       ld hl,l244fh\r
+       jr l2446h\r
+l2443h:\r
+       ld hl,l2452h\r
+l2446h:\r
+       jp PSTR\r
+\r
+b_0x2449_start:\r
+       DC      'I,A'\r
+l244ch:\r
+       DC      'A,I'\r
+l244fh:\r
+       DC      'R,A'\r
+l2452h:\r
+       DC      'A,R'\r
+\r
+l2455h:\r
+       call l24dfh\r
+       call sub_257ch\r
+       ld hl,t__C_\r
+       jp PSTR\r
+l2461h:\r
+       ld hl,t__C_\r
+       call PSTR\r
+       call sub_257ch\r
+       jp l24dfh\r
+l246dh:\r
+       call l253eh\r
+       call sub_257ch\r
+       jp l254bh\r
+l2476h:\r
+       call sub_24c6h\r
+       call sub_257ch\r
+       jp l254bh\r
+l247fh:\r
+       call l254bh\r
+       call sub_257ch\r
+       jr sub_24c6h\r
+l2487h:\r
+       ld a,(is.pfx.IXY)\r
+       and a\r
+       jr nz,l2496h\r
+       comst\r
+       ld a,(iy+001h)\r
+       comend\r
+       jr l249dh\r
+l2496h:\r
+       comst\r
+       ld a,(iy+002h)\r
+       comend\r
+l249dh:\r
+       push af\r
+       rra\r
+       rra\r
+       rra\r
+       and 007h\r
+       add a,'0'\r
+       call OUTCHAR\r
+       call sub_257ch\r
+       pop af\r
+       jr l24f2h\r
+l24aeh:\r
+       ld a,(is.pfx.IXY)\r
+       and a\r
+       jr nz,l24bdh\r
+       comst\r
+       ld a,(iy+001h)\r
+       comend\r
+       jr l24c4h\r
+l24bdh:\r
+       comst\r
+       ld a,(iy+002h)\r
+       comend\r
+l24c4h:\r
+       jr l24f2h\r
+sub_24c6h:\r
+       ld a,'('\r
+       call OUTCHAR\r
+       comst\r
+       ld l,(iy+001h)\r
+       ld h,(iy+002h)\r
+       comend\r
+       ld a,001h\r
+       call sub_23f2h\r
+       ld a,')'\r
+       jp OUTCHAR\r
+l24dfh:\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+       rra\r
+       rra\r
+       rra\r
+       jr l24f2h\r
+l24ebh:\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+l24f2h:\r
+       and 007h\r
+       cp 006h\r
+       jr nz,l2533h\r
+       ld a,(is.pfx.IXY)\r
+       and a\r
+       ld a,006h\r
+       jr z,l2533h\r
+       ld hl,b_0x2538_start\r
+       ld a,(is.pfx.IXY)\r
+       dec a\r
+       jr z,l250ch\r
+       ld hl,b_0x253B_start\r
+l250ch:\r
+       call PSTR\r
+       comst\r
+       ld a,(iy+001h)\r
+       comend\r
+       and a\r
+       push af\r
+       jp m,l2523h\r
+       ld a,'+'\r
+       call OUTCHAR\r
+       pop af\r
+       jr l252bh\r
+l2523h:\r
+       ld a,'-'\r
+       call OUTCHAR\r
+       pop af\r
+       neg\r
+l252bh:\r
+       call out.hex\r
+       ld a,')'\r
+       jp OUTCHAR\r
+l2533h:\r
+       ld hl,t_BCDEHL_HL_A\r
+       jr l2572h\r
+\r
+b_0x2538_start:\r
+       DC      '(IX'\r
+b_0x253B_start:\r
+       DC      '(IY'\r
+\r
+l253eh:\r
+       ld a,(is.pfx.IXY)\r
+       ld hl,t_HL.IX.IY\r
+       jr l2572h\r
+l2546h:\r
+       ld hl,t_BC.DE.HL.AF\r
+       jr l254eh\r
+l254bh:\r
+       ld hl,t_BC.DE.HL.SP\r
+l254eh:\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+       rra\r
+       rra\r
+       rra\r
+       rra\r
+       and 003h\r
+       cp 002h\r
+       jr z,l253eh\r
+       jr l2572h\r
+l2561h:\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+sub_2568h:\r
+       rra\r
+       rra\r
+       rra\r
+       and 007h\r
+       ld hl,t_tstfl_ZCPS\r
+       jr l2572h\r
+l2572h:\r
+       ld b,a\r
+       call sub_0a48h\r
+       jp PSTR\r
+sub_2579h:\r
+       call l23dbh\r
+sub_257ch:\r
+       ld a,','\r
+       jp OUTCHAR\r
+sub_2581h:\r
+       call PSTR\r
+l2584h:\r
+       call OUTBL\r
+       inc c\r
+       ld a,c\r
+       cp 006h\r
+       jr nz,l2584h\r
+       ret\r
+\r
+t_MNEMONICS:\r
+       DC      'ADC'\r
+       DC      'ADD'\r
+       DC      'AND'\r
+       DC      'BIT'\r
+       DC      'CALL'\r
+       DC      'CCF'\r
+       DC      'CP'\r
+       DC      'CPD'\r
+       DC      'CPDR'\r
+       DC      'CPI'\r
+       DC      'CPIR'\r
+       DC      'CPL'\r
+       DC      'DAA'\r
+       DC      'DEC'\r
+       DC      'DI'\r
+       DC      'DJNZ'\r
+       DC      'EI'\r
+       DC      'EX'\r
+       DC      'EXX'\r
+       DC      'HALT'\r
+       DC      'IM'\r
+       DC      'IN'\r
+       DC      'INC'\r
+       DC      'IND'\r
+       DC      'INDR'\r
+       DC      'INI'\r
+       DC      'INIR'\r
+       DC      'JP'\r
+       DC      'JR'\r
+       DC      'LD'\r
+       DC      'LDD'\r
+       DC      'LDDR'\r
+       DC      'LDI'\r
+       DC      'LDIR'\r
+       DC      'NEG'\r
+       DC      'NOP'\r
+       DC      'OR'\r
+       DC      'OTDR'\r
+       DC      'OTIR'\r
+       DC      'OUT'\r
+       DC      'OUTD'\r
+       DC      'OUTI'\r
+       DC      'POP'\r
+       DC      'PUSH'\r
+       DC      'RES'\r
+       DC      'RET'\r
+       DC      'RETI'\r
+       DC      'RETN'\r
+       DC      'RL'\r
+       DC      'RLA'\r
+       DC      'RLC'\r
+       DC      'RLCA'\r
+       DC      'RLD'\r
+       DC      'RR'\r
+       DC      'RRA'\r
+       DC      'RRC'\r
+       DC      'RRCA'\r
+       DC      'RRD'\r
+       DC      'RST'\r
+       DC      'SBC'\r
+       DC      'SCF'\r
+       DC      'SET'\r
+       DC      'SLA'\r
+       DC      'SRA'\r
+       DC      'SRL'\r
+       DC      'SUB'\r
+       DC      'XOR'\r
+       DC      'IN0'\r
+       DC      'MLT'\r
+       DC      'OTDM'\r
+       DC      'OTDMR'\r
+       DC      'OTIM'\r
+       DC      'OTIMR'\r
+       DC      'OUT0'\r
+       DC      'SLP'\r
+       DC      'TST'\r
+       DC      'TSTIO'\r
+       DB      0\r
+\r
+t_BCDEHL_HL_A:\r
+       DC      'B'\r
+       DC      'C'\r
+       DC      'D'\r
+       DC      'E'\r
+       DC      'H'\r
+       DC      'L'\r
+       DC      '(HL)'\r
+       DC      'A'\r
+       DB      0\r
+t_BC.DE.HL.SP:\r
+       DC      'BC'\r
+       DC      'DE'\r
+       DC      'HL'\r
+       DC      'SP'\r
+       DB      0\r
+t_BC.DE.HL.AF:\r
+       DC      'BC'\r
+       DC      'DE'\r
+t_HL.AF:\r
+       DC      'HL'\r
+       DC      'AF'\r
+       DB      0\r
+t_BC.DE.IY.SP:\r
+       DC      'BC'\r
+       DC      'DE'\r
+       DC      'IY'\r
+       DC      'SP'\r
+       DB      0\r
+t_BC.DE.IX.SP:\r
+       DC      'BC'\r
+       DC      'DE'\r
+       DC      'IX'\r
+       DC      'SP'\r
+       DB      0\r
+t_HL.IX.IY:\r
+       DC      'HL'\r
+t_IX.IY:\r
+       DC      'IX'\r
+       DC      'IY'\r
+       DB      0\r
+t_tstfl_ZC:\r
+       DC      'NZ'\r
+       DC      'Z'\r
+       DC      'NC'\r
+       DC      'C'\r
+       DC      'NE'\r
+       DC      'EQ'\r
+       DC      'GE'\r
+       DC      'LT'\r
+       DB      0\r
+t_tstfl_ZCPS:\r
+       DC      'NZ'\r
+       DC      'Z'\r
+       DC      'NC'\r
+       DC      'C'\r
+       DC      'PO'\r
+       DC      'PE'\r
+       DC      'P'\r
+       DC      'M'\r
+       DC      'NE'\r
+       DC      'EQ'\r
+       DC      'GE'\r
+       DC      'LT'\r
+       DC      'NV'\r
+       DC      'V'\r
+       DB      0\r
+t__C_:\r
+       DC      '(C)'\r
+       DB      0\r
+\r
+sub_26e7h:\r
+       ld hl,(REG.PC)\r
+       ld a,h\r
+       or l\r
+       jr z,l2715h\r
+       ld iy,(REG.PC)\r
+       call sub_1f9eh\r
+       jp nc,ERROR\r
+       ld c,b\r
+       ld b,000h\r
+       ld hl,(REG.PC)\r
+       add hl,bc\r
+       call sub_1117h\r
+       ld iy,(REG.PC)\r
+       ld hl,b_0x2717_start\r
+       call lookup_opc\r
+       ccf\r
+       ret c\r
+       ex de,hl\r
+       call CALL.HL\r
+       call c,sub_1117h\r
+l2715h:\r
+       scf\r
+       ret\r
+\r
+b_0x2717_start:\r
+       db      0ffh\r
+       db      0ddh\r
+       db      000h\r
+       dw      x278d\r
+\r
+       db      0ffh\r
+       db      0fdh\r
+       db      000h\r
+       dw      x2792\r
+\r
+       db      0ffh\r
+       db      0edh\r
+       db      000h\r
+       dw      x27a2\r
+\r
+l2726h:\r
+       db      0ffh\r
+       db      0cdh\r
+       db      000h\r
+       dw      x275e\r
+\r
+       db      0ffh\r
+       db      0c3h\r
+       db      000h\r
+       dw      x2769\r
+\r
+       db      0ffh\r
+       db      0e9h\r
+       db      000h\r
+       dw      x2788\r
+\r
+       db      0ffh\r
+       db      0c9h\r
+       db      000h\r
+       dw      x27c9\r
+\r
+       db      0ffh\r
+       db      0cfh\r
+       db      000h\r
+       dw      x280e\r
+\r
+       db      0c7h\r
+       db      0c7h\r
+       db      000h\r
+       dw      x27ea\r
+\r
+       db      0c7h\r
+       db      0c4h\r
+       db      000h\r
+       dw      x275e\r
+\r
+       db      0f7h\r
+       db      010h\r
+       db      000h\r
+       dw      x2775\r
+\r
+       db      0e7h\r
+       db      020h\r
+       db      000h\r
+       dw      x2775\r
+\r
+       db      0c7h\r
+       db      0c2h\r
+       db      000h\r
+       dw      x2769\r
+\r
+       db      0c7h\r
+       db      0c0h\r
+       db      000h\r
+       dw      x27b3\r
+\r
+       db      000h\r
+\r
+x275e:\r
+       ld a,(XBFE8)\r
+       and a\r
+       jr nz,x2769\r
+       ld a,(TCFLG)\r
+       and a\r
+       ret nz\r
+\r
+x2769:\r
+       comst\r
+       ld l,(iy+001h)\r
+       ld h,(iy+002h)\r
+       comend\r
+       scf\r
+       ret\r
+\r
+x2775:\r
+       comst\r
+       ld c,(iy+001h)\r
+       comend\r
+       ld a,c\r
+       rla\r
+       sbc a,a\r
+       ld b,a\r
+       ld hl,(REG.PC)\r
+       add hl,bc\r
+       inc hl\r
+       inc hl\r
+       scf\r
+       ret\r
+\r
+x2788:\r
+       ld hl,(REG.L)\r
+       scf\r
+       ret\r
+\r
+x278d:\r
+       ld hl,(reg.ix)\r
+       jr l2795h\r
+\r
+x2792:\r
+       ld hl,(reg.iy)\r
+l2795h:\r
+       comst\r
+       ld a,(iy+001h)\r
+       comend\r
+       cp 0e9h\r
+       scf\r
+       ret z\r
+       and a\r
+       ret\r
+\r
+x27a2:\r
+       comst\r
+       ld a,(iy+001h)\r
+       comend\r
+       cp 04dh\r
+       jr z,x27c9\r
+       cp 045h\r
+       jr z,x27c9\r
+       and a\r
+       ret\r
+\r
+x27b3:\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+       ld (XBEDD),a\r
+       ld hl,(REG.F)\r
+       push hl\r
+       pop af\r
+       call XBEDD\r
+       scf\r
+       jr c,x27c9\r
+       ret\r
+\r
+x27c9:\r
+       ld a,(XBFE8)\r
+       and a\r
+       jr nz,l27dah\r
+       ld a,(TCFLG)\r
+       and a\r
+       jr z,l27dah\r
+       call l27dah\r
+       pop hl\r
+       ret\r
+l27dah:\r
+       ld hl,(REG.SP)\r
+       comst\r
+       ld e,(hl)\r
+       inc hl\r
+       ld d,(hl)\r
+       comend\r
+       ex de,hl\r
+       call sub_1117h\r
+       and a\r
+       ret\r
+\r
+x27ea:\r
+       ld a,(ddtzrst)\r
+       comst\r
+       cp (iy+000h)\r
+       comend\r
+       ret z\r
+       comst\r
+       ld a,(iy+000h)\r
+       comend\r
+       and 038h\r
+       ld l,a\r
+       ld h,000h\r
+       ld a,(XBFE8)\r
+       and a\r
+       jr nz,l280ch\r
+       ld a,(TCFLG)\r
+       and a\r
+       ret nz\r
+l280ch:\r
+       scf\r
+       ret\r
+\r
+x280e:\r
+       and a\r
+       ret\r
+\r
+CMD.C:\r
+       ld hl,CMD.C\r
+       ld a,001h\r
+       jr l281bh\r
+\r
+CMD.T:\r
+       xor a\r
+       ld hl,CMD.T\r
+l281bh:\r
+       ld (CMD_RPT),hl\r
+       ld (TCFLG),a\r
+       ld a,(de)\r
+       sub 'N'\r
+       jr nz,l2827h\r
+       inc de\r
+l2827h:\r
+       ld (TCNFLG),a\r
+       ld a,(de)\r
+       sub 'J'\r
+       jr nz,l2830h\r
+       inc de\r
+l2830h:\r
+       ld (TRJFLG),a\r
+       call sub_289fh\r
+       jr z,l283eh\r
+       ld hl,1\r
+       call get_lastarg_def\r
+l283eh:\r
+       ld (TCCSTR),hl\r
+       sub a\r
+       ld (XA747),a\r
+l2845h:\r
+       call sub_26e7h\r
+       jr l289ch\r
+l284ah:\r
+       call sub_0e68h\r
+       ld a,(TRJFLG)\r
+       and a\r
+       jr nz,l2864h\r
+       ld iy,(REG.PC)\r
+       call sub_28c1h\r
+       jr z,l2864h\r
+       ld hl,l2726h\r
+       call lookup_opc\r
+       jr nc,l2845h\r
+l2864h:\r
+       ld a,(XBFEA)\r
+       and a\r
+       jr z,l2881h\r
+       ld de,(TCCSTR)\r
+       call EXPR\r
+       ld a,h\r
+       or l\r
+       add a,0ffh\r
+       sbc a,a\r
+       ld hl,XBFEA\r
+       xor (hl)\r
+       bit 1,a\r
+       jr z,l288ch\r
+l287eh:\r
+       jp l102eh\r
+l2881h:\r
+       ld hl,(TCCSTR)\r
+       dec hl\r
+       ld (TCCSTR),hl\r
+       ld a,h\r
+       or l\r
+       jr z,l287eh\r
+l288ch:\r
+       call sub_26e7h\r
+       jr nc,l287eh\r
+       ld a,(TCNFLG)\r
+       ld b,a\r
+       ld a,(XA747)\r
+       or b\r
+       ld (XA747),a\r
+l289ch:\r
+       jp l1183h\r
+\r
+sub_289fh:\r
+       call SKIPBL\r
+       xor a\r
+       ld (XBFEA),a\r
+       ld a,(de)\r
+       cp 'U'\r
+       jr z,l28aeh\r
+       cp 'W'\r
+       ret nz\r
+\r
+l28aeh:\r
+       inc de\r
+       push af\r
+       push de\r
+       call EXPR\r
+       jp c,ERROR\r
+       call assert_eol\r
+       pop hl\r
+       pop af\r
+       ld (XBFEA),a\r
+       sub a\r
+       ret\r
+\r
+sub_28c1h:\r
+       comst\r
+       ld a,(iy+000h)\r
+       ld b,(iy+0001)\r
+       comend\r
+       cp 0edh\r
+       jr z,l28dbh\r
+       and 0dfh\r
+       cp 0ddh\r
+       ret nz\r
+       ld a,b\r
+       cp 0e9h\r
+       ret\r
+l28dbh:\r
+       ld a,b\r
+       and 0f7h\r
+       cp 045h\r
+       ret\r
+\r
+?excom:\r
+       ex (sp),hl\r
+       push af\r
+       push bc\r
+       push de\r
+       ld c,(hl)\r
+       ld b,000h\r
+       inc hl\r
+       ld a,?lcmax\r
+       sub c\r
+       ld de,?exeit\r
+       ldir\r
+       ex de,hl\r
+       ld (hl),018h\r
+       inc hl\r
+       ld (hl),a\r
+       ex de,hl\r
+       pop de\r
+       pop bc\r
+       pop af\r
+       ex (sp),hl\r
+       if CPU_Z180\r
+       push hl\r
+       ld hl,(ubbr)\r
+\r
+       else\r
+        push af\r
+        ld a,(ubnk)\r
+       endif\r
+       if ROMSYS\r
+        push af\r
+        ld a,(uromen)\r
+       endif\r
+       jp ?comcod\r
+\r
+;------------------------------------------\r
+;      ddtram\r
+;------------------------------------------\r
+\r
+vartab:\r
+;      dseg\r
+       cseg\r
+ddtram:\r
+;todo:\r
+; The following 2 params are changeable by user.\r
+; Should these moved to top ram?\r
+;\r
+ddtzrst:\r
+       rst     DDTZRSTVEC      ;rst used by ddtz\r
+ddtei: ei                      ;ints enabled/disabled while ddtz is running\r
+       ret                     ;\r
+offs.pc:\r
+       dw      TPA\r
+offs.@:\r
+       dw      0\r
+CMD_ERR:\r
+       dw      0\r
+CMD_RPT:\r
+       dw      DDTZML\r
+ci.buf:\r
+       db      80\r
+       rept    83\r
+       db      0\r
+       endm\r
+CON.COL:\r
+       db      0\r
+XA747:\r
+       db      0\r
+bp_tab:\r
+       rept    BP_CNT\r
+       db      0,0\r
+       dw      0,0,0\r
+       endm\r
+BP_SIZE        equ     8\r
+sexp1:\r
+       dw      sexpbuf\r
+sexp2:\r
+       dw      sexpbuf\r
+sexpbuf:\r
+       rept    128\r
+       db      0\r
+       endm\r
+sexpbufe:\r
+\r
+msg.Y:\r
+       dc      'Y0'\r
+reg.Y:\r
+       rept    10\r
+       dw      0\r
+       endm\r
+lst.S:\r
+       dw      0\r
+lst.IP:\r
+       dw      0\r
+lst.OP:\r
+       dw      0\r
+lst.OD:\r
+       db      0\r
+lst.Qj:\r
+       db      0\r
+lst.D:\r
+       dw      0\r
+HILOD:\r
+       dw      0\r
+MAXLOD:\r
+       dw      0\r
+XB068:\r
+       dw      0\r
+lst.A:\r
+       dw      0\r
+XB06C:\r
+       dw      0\r
+pfx.IXY:\r
+       db      000h\r
+is.pfx.IXY:\r
+       db      000h\r
+lst.L:\r
+       dw      0\r
+XBE01:\r
+       dw      0\r
+XBE03:\r
+       db      000h\r
+XBEDD:\r
+       ret             ;ret cc\r
+       and a\r
+       pop hl\r
+       inc hl\r
+       jp (hl)\r
+XBFE8:\r
+       db      0\r
+TCFLG:\r
+       db      0\r
+XBFEA:\r
+       db      0\r
+TCCSTR:\r
+       dw      0\r
+TCNFLG:\r
+       db      0\r
+TRJFLG:\r
+       db      0\r
+wstrtflg:\r
+       db      1\r
+\r
+       cseg\r
+vartabe:\r
+\r
+;------------------------------------------\r
+\r
+       .phase  sysram_start+bs$stack$size\r
+$stack:\r
+$stcka equ     $ - bs$stack$size\r
+\r
+curphse        defl    $\r
+       .dephase\r
+sysramc:\r
+       .phase curphse\r
+topcodbeg:\r
+\r
+reg.l2:        db      0               ; 0fe50h\r
+reg.h2:        db      0               ; 0fe51h\r
+reg.e2:        db      0               ; 0fe52h\r
+reg.d2:        db      0               ; 0fe53h\r
+reg.c2:        db      0               ; 0fe54h\r
+reg.b2:        db      0               ; 0fe55h\r
+reg.f2:        db      0               ; 0fe56h\r
+reg.a2:        db      0               ; 0fe57h\r
+       db      0\r
+reg.i: db      high ivtab\r
+reg.iy:        dw      0               ; 0fe5ah\r
+reg.ix:        dw      0               ; 0fe5ch\r
+reg.e: db      0               ; 0fe5eh\r
+reg.d: db      0               ; 0fe5fh\r
+reg.c: db      0               ; 0fe60h\r
+reg.b: db      0               ; 0fe61h\r
+       if      ROMSYS\r
+udcntl:         db     CWAITIO         ; 0fe62h        (mem-, io- wait)\r
+uromen:         db     ROM_DIS         ; 0fe63h\r
+       endif\r
+       if CPU_Z180\r
+ubbr:  db      0               ; 0fe64h\r
+ucbar: db      USR$CBAR        ; 0fe65h\r
+       else\r
+        db     0               ; 0fe64h\r
+ubnk:   db     0               ; 0fe65h\r
+       endif\r
+reg.f: db      0               ; 0fe66h\r
+reg.a: db      0               ; 0fe67h\r
+reg.l: db      0               ; 0fe68h\r
+reg.h: db      0               ; 0fe69h\r
+reg.sp:        dw      TOPRAM          ; 0fe6ah\r
+\r
+$go:\r
+       if      ROMSYS\r
+        out (000h),a           ;064c fe6c\r
+        out0 (dcntl),l\r
+        pop hl\r
+       endif\r
+       if CPU_Z180\r
+       out0 (cbar),h\r
+       out0 (bbr),l\r
+       else\r
+        ld a,h\r
+        call selbnk\r
+       endif\r
+       pop af\r
+       pop hl\r
+       ld sp,(reg.sp)\r
+reg.iff:\r
+       ei\r
+       db      0C3h            ;jp TPA ;065f feff ($+1): reg.pc\r
+reg.pc:\r
+       dw      TPA\r
+\r
+bpent:\r
+       ld (reg.l),hl           ;0662 fe82: bpent:\r
+       pop hl\r
+       dec hl\r
+       ld (reg.pc),hl\r
+       ld (reg.sp),sp\r
+       ld sp,reg.l\r
+       push af\r
+       if CPU_Z180\r
+;;;     TODO: cbar on trap?\r
+       in0 h,(cbar)\r
+       in0 l,(bbr)\r
+       ld a,SYS$CBAR\r
+       out0 (cbar),a\r
+       else\r
+        ld a,(@cbnk)\r
+        ld h,a\r
+        xor a\r
+        ld l,a\r
+        call selbnk\r
+       endif\r
+        push hl\r
+\r
+       if ROMSYS\r
+        in0 l,(dcntl)\r
+        ld a,CWAITROM+CWAITIO\r
+        out0 (dcntl),a\r
+        ld a,($crom)\r
+        cp c$rom\r
+        ld a,ROM_EN\r
+        out (000h),a\r
+       endif\r
+\r
+       jp bpddtz\r
+\r
+?comcod:\r
+       if ROMSYS\r
+        out (000h),a           ;0692 feb2\r
+        pop af\r
+       endif\r
+\r
+       if CPU_Z180\r
+       out0 (cbar),h\r
+       out0 (bbr),l\r
+       pop hl\r
+       else\r
+        call selbnk\r
+        pop af\r
+       endif\r
+?exeit:\r
+       ds ?lcmax+2\r
+       push af\r
+       if CPU_Z180\r
+       ld a,SYS$CBAR\r
+       out0 (cbar),a\r
+\r
+;;;     TODO: bbr?\r
+       else\r
+        xor a\r
+        call selbnk\r
+       endif\r
+       if ROMSYS\r
+        ld a,ROM_EN\r
+        out (000h),a\r
+       endif\r
+\r
+       pop af\r
+       ret\r
+\r
+topcodend:\r
+curph  defl    $\r
+       .dephase\r
+sysrame:\r
+\r
+       end\r
diff --git a/z180/fifoio.180 b/z180/fifoio.180
new file mode 100644 (file)
index 0000000..cbcece9
--- /dev/null
@@ -0,0 +1,128 @@
+       page    255\r
+       .z80\r
+\r
+;\r
+; FIFO channels for communication with stm32\r
+;\r
+       global  f.init,f.in,f.out,f.i.st\r
+\r
+       extrn   buf.init\r
+\r
+       include config.inc\r
+       include z180reg.inc\r
+\r
+\r
+;--------------------------------------------------------------\r
+\r
+       dseg\r
+\r
+\r
+       mkbuf   ci.fifo_id, rx.buf,rx.buf_len\r
+       mkbuf   co.fifo_id, tx.buf,tx.buf_len\r
+\r
+\r
+;--------------------------------------------------------------\r
+\r
+       cseg\r
+\r
+; Init Serial I/O for console input and output\r
+;\r
+\r
+f.init:\r
+       ld      ix,rx.buf\r
+       ld      a,rx.buf.mask\r
+       call    buf.init\r
+       ld      ix,tx.buf\r
+       ld      a,tx.buf.mask\r
+       jp      buf.init\r
+\r
+\r
+f.i.st:\r
+       push    ix\r
+       ld      ix,rx.buf               ;\r
+\r
+buf.empty:\r
+       ld      a,(ix+o.in_idx)         ;\r
+       sub     (ix+o.out_idx)          ;\r
+       pop     ix\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+\r
+f.in:\r
+       push    ix\r
+       ld      ix,rx.buf               ;\r
+\r
+buf.get:\r
+       ld      a,(ix+o.out_idx)        ;\r
+bg.wait:\r
+       cp      (ix+o.in_idx)           ;\r
+       jr      z,bg.wait\r
+\r
+       push    hl                      ;\r
+       push    ix\r
+       pop     hl\r
+       add     a,l\r
+       ld      l,a\r
+       jr      nc,bg.nc\r
+       inc     h\r
+bg.nc:\r
+       ld      l,(hl)\r
+\r
+       ld      a,(ix+o.out_idx)        ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       ld      (ix+o.out_idx),a\r
+\r
+       ld      a,l\r
+       pop     hl\r
+       pop     ix\r
+       ret\r
+\r
+\r
+f.o.st:\r
+       push    ix\r
+       ld      ix,tx.buf               ;\r
+\r
+buf.full:\r
+       ld      a,(ix+o.in_idx)         ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       sub     (ix+o.out_idx)          ;\r
+       pop     ix\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+\r
+f.out:\r
+       push    ix\r
+       ld      ix,tx.buf               ;\r
+\r
+buf.put:\r
+       push    hl                      ;\r
+       push    bc\r
+       push    ix\r
+       pop     hl\r
+       ld      c,(ix+o.in_idx)         ;\r
+       ld      b,0\r
+       add     hl,bc\r
+       ld      b,a\r
+\r
+       ld      a,c                     ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+bp.wait:\r
+       cp      (ix+o.out_idx)          ;\r
+       jr      z,bp.wait\r
+       ld      (hl),b\r
+       ld      (ix+o.in_idx),a\r
+\r
+       ld      a,b\r
+       pop     bc\r
+       pop     hl\r
+       pop     ix\r
+       ret\r
+\r
+       end\r
diff --git a/z180/init-80.180 b/z180/init-80.180
new file mode 100644 (file)
index 0000000..8b71993
--- /dev/null
@@ -0,0 +1,591 @@
+       page    255\r
+       .z80\r
+\r
+       extrn ddtz,bpent\r
+       extrn $stack\r
+       extrn charini,?const,?conin\r
+       extrn ?cono,?conos\r
+\r
+       extrn romend\r
+\r
+       global  iobyte\r
+       global  isv_sw\r
+\r
+       include config.inc\r
+\r
+\r
+\r
+\r
+;----------------------------------------------------------------------\r
+\r
+       cseg\r
+romstart equ   $\r
+\r
+       org     romstart+0\r
+       jp      start\r
+\r
+iobyte:        db      0\r
+\r
+; restart vectors\r
+\r
+rsti   defl    1\r
+       rept    7\r
+\r
+       org     8*rsti + romstart\r
+        jp bpent\r
+rsti    defl rsti+1\r
+       endm\r
+\r
+;----------------------------------------------------------------------\r
+       \r
+       org     romstart+40h\r
+\r
+       dw      0\r
+       db      0\r
+\r
+       cseg\r
+\r
+       if ROMSYS\r
+$crom:  defb c$rom             ;\r
+       else\r
+        db     0               ;\r
+       endif\r
+\r
+\r
+hwini0:\r
+       db      0               ;count\r
+;      db      rcr,CREFSH      ;configure DRAM refresh\r
+;      db      dcntl,INIWAITS  ;wait states\r
+;      db      cbar,SYS$CBAR\r
+\r
+\r
+;----------------------------------------------------------------------\r
+\r
+       org     romstart+50h\r
+\r
+start:\r
+       jp      cstart\r
+       jp      wstart\r
+       jp      ?const\r
+       jp      ?conin\r
+       jp      ?cono\r
+       jp      ?conos\r
+       jp      charini\r
+\r
+cstart:\r
+       di\r
+\r
+       xor     a\r
+       ld      (@cbnk),a\r
+\r
+; search warm start mark\r
+\r
+       ld ix,mark_55AA         ; top of common area\r
+       ld a,0aah               ;\r
+       cp (ix+000h)            ;\r
+       jr nz,kstart            ;\r
+       cp (ix+002h)            ;\r
+       jr nz,kstart            ;\r
+       cpl                     ;\r
+       cp (ix+001h)            ;\r
+       jr nz,kstart            ;\r
+       cp (ix+003h)            ;\r
+       jr nz,kstart            ;\r
+       ld sp,$stack            ; mark found, check\r
+;      call checkcrc_alv       ;\r
+       jp z,wstart             ; check ok,\r
+\r
+;\r
+; ram not ok, initialize    --  kstart --\r
+\r
+kstart:\r
+       ld      sp,$stack       ;01e1\r
+\r
+; Clear RAM \r
+\r
+; Init bank manager\r
+\r
+;----------------------------------------------------------------------\r
+;\r
+\r
+       ld      hl,055AAh       ;set warm start mark\r
+       ld      (mark_55AA),hl  ;\r
+       ld      (mark_55AA+2),hl;\r
+\r
+;\r
+;       --  wstart  --\r
+;\r
+wstart:\r
+       call    sysram_init     ;027f\r
+       call    ivtab_init\r
+\r
+       call    charini\r
+       call    bufferinit\r
+\r
+       ld      c,0\r
+       call    selbnk\r
+\r
+\r
+       im 2                    ;?030e\r
+       ei                      ;0282\r
+\r
+       call ?const             ;0284\r
+       call ?const             ;0287\r
+       or a                    ;028a\r
+       call nz,?conin          ;028d\r
+\r
+;;;    ld a,(banktab)          ;\r
+;;;    ld e,a                  ;\r
+       jp ddtz                 ;0290\r
+\r
+\r
+;----------------------------------------------------------------------\r
+;\r
+\r
+;TODO: Make a ringbuffer module.\r
+\r
+       global  buf.init\r
+\r
+buf.init:\r
+       ld      (ix+o.in_idx),0\r
+       ld      (ix+o.out_idx),0\r
+       ld      (ix+o.mask),a\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+\r
+       extrn   msginit,msg.sout\r
+       extrn   mtx.fifo,mrx.fifo\r
+       extrn   co.fifo,ci.fifo\r
+\r
+\r
+bufferinit:\r
+       call     msginit\r
+\r
+       ld      hl,buffers\r
+       ld      b,buftablen\r
+bfi_1:\r
+       ld      a,(hl)\r
+       inc     hl\r
+       ld      (bufdat+0),a\r
+       ld      e,(hl)\r
+       inc     hl\r
+       ld      d,(hl)\r
+       inc     hl\r
+       ex      de,hl\r
+\r
+       or      a\r
+       jr      nz,bfi_2\r
+\r
+       ld      a,(@cbnk)\r
+       call    bnk2phys\r
+\r
+       ld      (40h+0),hl\r
+       ld      (40h+2),a\r
+       out     (AVRINT5),a\r
+       jr      bfi_3\r
+bfi_2:\r
+\r
+       ld      a,(@cbnk)\r
+       call    bnk2phys\r
+\r
+       ld      (bufdat+1),hl\r
+       ld      (bufdat+3),a\r
+       ld      hl,inimsg\r
+       call    msg.sout\r
+bfi_3:\r
+       ex      de,hl\r
+       djnz    bfi_1\r
+       ret\r
+\r
+\r
+buffers:\r
+       db      0\r
+       dw      mtx.fifo\r
+       db      1\r
+       dw      mrx.fifo\r
+       db      2\r
+       dw      co.fifo\r
+       db      3\r
+       dw      ci.fifo\r
+buftablen equ  ($ - buffers)/3\r
+\r
+inimsg:\r
+       db      inimsg_e - $ -1\r
+       db      0AEh\r
+       db      inimsg_e - $ -1\r
+       db      0\r
+bufdat:\r
+       db      0\r
+       dw      0\r
+       db      0\r
+inimsg_e:\r
+\r
+\r
+;\r
+;----------------------------------------------------------------------\r
+;\r
+\r
+bnk2phys:\r
+       sla     h\r
+       jr      nc,b2p_1                ;A15=1 --> common\r
+       ld      a,3\r
+b2p_1:\r
+       srl     a\r
+       rr      h\r
+       ret\r
+\r
+;\r
+;----------------------------------------------------------------------\r
+;\r
+\r
+sysram_init:\r
+       ld hl,sysramw\r
+       ld de,topcodsys\r
+       ld bc,sysrame-sysramw\r
+       ldir\r
+\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+ivtab_init:\r
+       ld      hl,ivtab        ;\r
+       ld      a,h             ;\r
+       ld      i,a             ;\r
+;      out0    (il),l          ;\r
+\r
+; Let all vectors point to spurious int routines.\r
+\r
+       ld      d,high sp.int0\r
+       ld      a,low  sp.int0\r
+       ld      b,9\r
+ivt_i1:\r
+       ld      (hl),a\r
+       inc     l\r
+       ld      (hl),d\r
+       inc     l\r
+       add     a,sp.int.len\r
+       djnz    ivt_i1\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+;\r
+\r
+       global io.ini\r
+       \r
+io.ini:\r
+       push    bc\r
+\r
+       if CPU_Z180\r
+\r
+       ld      b,0             ;high byte port adress\r
+       ld      a,(hl)          ;count\r
+       inc     hl\r
+       or      a\r
+       jr      z,ioi_e\r
+ioi_1:\r
+       ld      c,(hl)          ;port address\r
+       inc     hl\r
+       outi\r
+       inc     b               ;outi decrements b\r
+       dec     a\r
+       jr      nz,ioi_1\r
+\r
+       else\r
+       jr      ioi_nxt\r
+ioi_l:\r
+       ld      c,(hl)          ;port address\r
+       inc     hl\r
+       otir\r
+ioi_nxt:\r
+       ld      b,(hl)          ;count\r
+       inc     hl\r
+       inc     b\r
+       djnz    ioi_l\r
+       endif\r
+ioi_e: \r
+       pop     bc\r
+       ret\r
+\r
+       if CPU_Z180\r
+io.ini.m:\r
+       push    bc\r
+       ld      b,(hl)\r
+       inc     hl\r
+       ld      c,(hl)\r
+       inc     hl\r
+       otimr\r
+       pop     bc\r
+       ret\r
+       endif\r
+\r
+io.ini.l:\r
+;\r
+\r
+\r
+;----------------------------------------------------------------------\r
+;\r
+;return:\r
+; hl = hl + a\r
+; Flags undefined\r
+;\r
+\r
+add_hl_a:\r
+       add a,l\r
+       ld l,a\r
+       ret nc\r
+       inc h\r
+       ret\r
+\r
+; ---------------------------------------------------------\r
+\r
+sysramw:\r
+\r
+       .phase isvsw_loc\r
+topcodsys:\r
+\r
+; Trampoline for interrupt routines in banked ram.\r
+; Switch stack pointer to "system" stack in top ram\r
+\r
+; todo: z80 bank switch\r
+\r
+isv_sw:                                ;\r
+       ex (sp),hl              ; save hl, return adr in hl\r
+       push de                 ;\r
+       push af                 ;\r
+       ex de,hl                ;\r
+       ld hl,0                 ;\r
+       add hl,sp               ;\r
+       ld a,h                  ;\r
+       cp 0f8h                 ;\r
+       jr nc,isw_1             ;\r
+       ld sp,$stack            ;\r
+isw_1:\r
+       push hl                 ;\r
+                               ; save current bank\r
+;      in0 h,(cbar)            ;\r
+       push hl                 ;\r
+                               ; switch to system bank\r
+;      ld a,SYS$CBAR           ;\r
+;      out0 (cbar),a           ; \r
+       ex de,hl                ;\r
+       ld e,(hl)               ;\r
+       inc hl                  ;\r
+       ld d,(hl)               ;\r
+       ex de,hl                ;\r
+       push bc                 ;\r
+       call jphl               ;\r
+\r
+       pop bc                  ;\r
+       pop hl                  ; restore bank\r
+;      out0 (cbar),h           ;\r
+       pop hl                  ;\r
+       ld sp,hl                ;\r
+       pop af                  ;\r
+       pop de                  ;\r
+       pop hl                  ;\r
+       ei                      ;\r
+       ret                     ;\r
+jphl:\r
+       jp (hl)                 ;\r
+\r
+; ---------------------------------------------------------\r
+\r
+sp.int0:\r
+       ld      a,0d0h\r
+       jr      sp.i.1\r
+sp.int.len equ $-sp.int0\r
+       ld      a,0d1h\r
+       jr      sp.i.1\r
+       ld      a,0d2h\r
+       jr      sp.i.1\r
+       ld      a,0d3h\r
+       jr      sp.i.1\r
+       ld      a,0d4h\r
+       jr      sp.i.1\r
+       ld      a,0d5h\r
+       jr      sp.i.1\r
+       ld      a,0d6h\r
+       jr      sp.i.1\r
+       ld      a,0d7h\r
+       jr      sp.i.1\r
+       ld      a,0d8h\r
+sp.i.1:\r
+;      out     (80h),a\r
+       halt\r
+\r
+; ---------------------------------------------------------\r
+\r
+; Get IFF2\r
+; This routine may not be loaded in page zero\r
+;\r
+; return Carry clear, if INTs are enabled.\r
+;\r
+       global getiff\r
+getiff:\r
+       xor     a               ;clear accu and carry\r
+       push    af              ;stack bottom := 00xxh\r
+       pop     af\r
+       ld      a,i             ;P flag := IFF2\r
+       ret     pe              ;exit carry clear, if enabled\r
+       dec     sp\r
+       dec     sp              ;has stack bottom been overwritten?\r
+       pop     af\r
+       and     a               ;if not 00xxh, INTs were\r
+       ret     nz              ;actually enabled\r
+       scf                     ;Otherwise, they really are disabled\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+       global  selbnk\r
+\r
+; a: bank (0..2)\r
+\r
+selbnk:\r
+       push    bc\r
+       ld      c,a\r
+       call    getiff\r
+       push    af\r
+\r
+       ld      a,c\r
+       di\r
+       ld      (@cbnk),a\r
+       ld      a,5\r
+       out     (SIOAC),a\r
+       ld      a,(mm_sio0)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOAC),a\r
+       ld      (mm_sio0),a\r
+\r
+       ld      a,5\r
+       out     (SIOBC),a\r
+       ld      a,(mm_sio1)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOBC),a\r
+       ld      (mm_sio1),a\r
+       pop     af\r
+       pop     bc\r
+       ret     c                       ;INTs were disabled\r
+       ei\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+; c: bank (0..2)\r
+\r
+       if 0\r
+\r
+selbnk:\r
+       ld      a,(@cbnk)\r
+       xor     c\r
+       and     3\r
+       ret     z               ;no change\r
+\r
+       call    getiff\r
+       push    af\r
+       ld      a,c\r
+       di\r
+       ld      (@cbnk),a\r
+       ld      a,5\r
+       out     (SIOAC),a\r
+       ld      a,(mm_sio0)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOAC),a\r
+       ld      (mm_sio0),a\r
+\r
+       ld      a,5\r
+       out     (SIOBC),a\r
+       ld      a,(mm_sio1)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOBC),a\r
+       ld      (mm_sio1),a\r
+       pop     af\r
+       ret     nc                      ;INTs were disabled\r
+       ei\r
+       ret\r
+\r
+       endif\r
+\r
+;----------------------------------------------------------------------\r
+\r
+       if 0\r
+       ex      af,af'\r
+       push    af\r
+       ex      af,af'\r
+\r
+       rra\r
+       jr      nc,stbk1\r
+       ex      af,af'\r
+       ld      a,5\r
+       out     (SIOAC),a\r
+       ld      a,(mm_sio0)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOAC),a\r
+       ld      (mm_sio1),a\r
+       ex      af,af'\r
+\r
+stbk1:\r
+       rra\r
+       jr      nc,stbk2\r
+       ex      af,af'\r
+       ld      a,5\r
+       out     (SIOBC),a\r
+       ld      a,(mm_sio1)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOBC),a\r
+       ld      (mm_sio1),a\r
+       ex      af,af'\r
+\r
+stbk2:\r
+       endif\r
+\r
+       global  @cbnk\r
+       global  mm_sio0, mm_sio1\r
+\r
+@cbnk: db      0               ; current bank (0..2)\r
+mm_sio0:\r
+       ds      1\r
+mm_sio1:\r
+       ds      1\r
+\r
+;----------------------------------------------------------------------\r
+\r
+curph  defl    $\r
+       .dephase\r
+sysrame:\r
+       .phase curph\r
+tim_ms:        db      0\r
+tim_s: dw      0\r
+       .dephase\r
+\r
+;-----------------------------------------------------\r
+\r
+       cseg\r
+\r
+       ;.phase 0ffc0h\r
+;ivtab equ     0ffc0h          ; 0ffc0h        ;int vector table\r
+       ;.dephase\r
+\r
+       ;.phase 0fffch\r
+mark_55AA equ 0fffch\r
+       ;ds     4               ; 0fffch\r
+       ;.dephase\r
+\r
+\r
+       end\r
+\r
diff --git a/z180/init.180 b/z180/init.180
new file mode 100644 (file)
index 0000000..05c24ff
--- /dev/null
@@ -0,0 +1,913 @@
+       page    255\r
+       .z80\r
+\r
+       extrn ddtz,bpent\r
+       extrn $stack\r
+       extrn charini,?const,?conin\r
+       extrn ?cono,?conos\r
+       extrn romend\r
+\r
+\r
+       global  iobyte\r
+       global  isv_sw\r
+\r
+       include config.inc\r
+    if CPU_Z180\r
+       include z180reg.inc\r
+       include z180.lib\r
+    endif\r
+\r
+\r
+\r
+\r
+;----------------------------------------------------------------------\r
+\r
+       cseg\r
+romstart equ   $\r
+\r
+       org     romstart+0\r
+       jp start\r
+\r
+iobyte:        db      2\r
+\r
+; restart vectors\r
+\r
+rsti   defl    1\r
+       rept    7\r
+       org     8*rsti + romstart\r
+       jp bpent\r
+rsti   defl rsti+1\r
+       endm\r
+\r
+;----------------------------------------------------------------------\r
+; Config space\r
+;\r
+\r
+       org     romstart+40h\r
+\r
+       dw      0\r
+       db      0\r
+\r
+\r
+    if ROMSYS\r
+$crom: defb c$rom              ;\r
+    else\r
+       db      0               ;\r
+    endif\r
+\r
+INIWAITS defl  CWAITIO\r
+    if ROMSYS\r
+INIWAITS defl  INIWAITS+CWAITROM\r
+    endif\r
+\r
+;----------------------------------------------------------------------\r
+\r
+       org     romstart+50h\r
+start:\r
+       jp      cstart\r
+       jp      wstart\r
+       jp      ?const\r
+       jp      ?conin\r
+       jp      ?cono\r
+       jp      ?conos\r
+       jp      charini\r
+\r
+;----------------------------------------------------------------------\r
+\r
+hwini0:\r
+    if CPU_Z180\r
+       db                      ;count\r
+       db      rcr,CREFSH      ;configure DRAM refresh\r
+       db      dcntl,INIWAITS  ;wait states\r
+       db      cbr,SYS$CBR\r
+       db      cbar,SYS$CBAR\r
+    endif\r
+       db     0\r
+\r
+    if CPU_Z180\r
+dmclrt:                                ;clear ram per dma\r
+       db      dmct_e-dmclrt-2 ;\r
+       db      sar0l           ;first port\r
+       dw      nullbyte        ;src (fixed)\r
+nullbyte:\r
+       db      000h            ;src\r
+       dw      romend          ;dst (inc), start after "rom" code\r
+       db      00h             ;dst\r
+       dw      0-romend        ;count (64k)\r
+dmct_e:\r
+       db      0\r
+    endif\r
+\r
+\r
+cstart:\r
+    if CPU_Z180\r
+\r
+       push af\r
+       in0 a,(itc)             ;Illegal opcode trap?\r
+       jp m,??st01\r
+       ld a,i                  ;I register == 0 ?\r
+       jr z,hw_reset           ;    yes, harware reset\r
+\r
+??st01:\r
+       ; TODO: SYS$CBR\r
+       ld      a,(syscbr)\r
+       out0    (cbr),a\r
+       pop af                  ;restore registers\r
+       jp bpent                ;\r
+\r
+hw_reset:\r
+       di                      ;0058\r
+       ld      a,CREFSH\r
+       out0    (rcr),a         ;       configure DRAM refresh\r
+       ld      a,CWAITIO\r
+       out0    (dcntl),a       ;       wait states\r
+\r
+       ld      a,M_NCD         ;No Clock Divide\r
+       out0    (ccr),a\r
+;      ld      a,M_X2CM        ;X2 Clock Multiplier\r
+;      out0    (cmr),a\r
+    else\r
+       di\r
+       xor     a\r
+       ld      (@cbnk),a\r
+    endif\r
+\r
+; check warm start mark\r
+\r
+       ld ix,mark_55AA         ; top of common area\r
+       ld a,0aah               ;\r
+       cp (ix+000h)            ;\r
+       jr nz,kstart            ;\r
+       cp (ix+002h)            ;\r
+       jr nz,kstart            ;\r
+       cpl                     ;\r
+       cp (ix+001h)            ;\r
+       jr nz,kstart            ;\r
+       cp (ix+003h)            ;\r
+       jr nz,kstart            ;\r
+       ld sp,$stack            ; mark found, check\r
+       jp z,wstart             ; check ok,\r
+\r
+; ram not ok, initialize    --  kstart --\r
+\r
+kstart:\r
+    if CPU_Z180\r
+       ld      a,SYS$CBR       ;TODO:\r
+       out0    (cbr),a\r
+       ld      a,SYS$CBAR\r
+       out0    (cbar),a\r
+    endif\r
+\r
+       ld      sp,$stack       ;01e1\r
+\r
+; Clear RAM using DMA0\r
+\r
+    if CPU_Z180\r
+     if 0\r
+\r
+       ld      hl,dmclrt       ;load DMA registers\r
+       call    ioiniml\r
+       ld      a,0cbh          ;01ef   dst +1, src fixed, burst\r
+       out0    (dmode),a       ;01f1\r
+\r
+       ld      b,512/64\r
+       ld      a,062h          ;01f4   enable dma0,\r
+??cl_1:\r
+       out0    (dstat),a       ;01f9   clear (up to) 64k\r
+       djnz    ??cl_1          ;       end of RAM?\r
+\r
+     endif\r
+    endif\r
+\r
+       ld      hl,055AAh       ;set warm start mark\r
+       ld      (mark_55AA),hl\r
+       ld      (mark_55AA+2),hl\r
+\r
+;      --  wstart  --\r
+\r
+wstart:\r
+       call    sysram_init\r
+       call    ivtab_init\r
+    if CPU_Z180\r
+;      call    prt0_init\r
+    endif\r
+\r
+       call    msginit\r
+       call    charini\r
+\r
+    if CPU_Z80\r
+       ld      a,0\r
+       call    selbnk\r
+    endif\r
+\r
+       ld      a,INIDONEVAL    ;tell others (CP/M) that hardware and fifos\r
+       ld      (INIDONE),a     ;    are allready initialized\r
+\r
+       im 2\r
+       ei\r
+\r
+       call ?const\r
+       call ?const\r
+       or a\r
+       call nz,?conin\r
+\r
+    if CPU_Z180\r
+       ld e,0                  ;Sys$Bank\r
+    else\r
+; TODO:\r
+    endif\r
+       jp ddtz\r
+\r
+\r
+    if CPU_Z180\r
+; TODO: SYS$CBR\r
+syscbr:        db      0\r
+    endif\r
+\r
+;\r
+;----------------------------------------------------------------------\r
+;\r
+\r
+       global  bufinit\r
+\r
+bufinit:\r
+       ld      (ix+o.in_idx),0         ;reset pointers (empty fifo)\r
+       ld      (ix+o.out_idx),0\r
+       ld      a,(ix+o.id)\r
+       ld      hl,fifolst\r
+       ld      e,a\r
+       ld      d,0\r
+       add     hl,de\r
+       add     hl,de\r
+       push    ix\r
+       pop     de\r
+       cp      4\r
+       jr      nc,bfi_skip\r
+\r
+       ld      (hl),e\r
+       inc     hl\r
+       ld      (hl),d\r
+\r
+bfi_skip:\r
+       ex      de,hl\r
+       call    hwl2phy                 ;get phys. address of fifo\r
+       ld      c,a\r
+       ld      a,(ix+o.id)             ;fifo id\r
+       or      a                       ;test if fifo 0\r
+       ret     z\r
+\r
+       ld      b,a\r
+       push    bc                      ;c: bank-addr, b: ignored\r
+       push    hl                      ;address\r
+       ld      c,0\r
+       push    bc                      ;c: function, b:subf\r
+       ld      b,5\r
+       ld      h,c\r
+       ld      l,c\r
+       add     hl,sp\r
+       call    msg.sm\r
+       pop     hl\r
+       pop     hl\r
+       pop     hl\r
+       ret\r
+\r
+       public  fifolst\r
+fifolst :\r
+       rept 4\r
+        dw     0\r
+       endm\r
+\r
+;----------------------------------------------------------------------\r
+\r
+       extrn   msg.sm\r
+       extrn   msginit,msg.sout\r
+       extrn   mtx.fifo,mrx.fifo\r
+       extrn   ff.init,co.fifo,ci.fifo\r
+\r
+\r
+fifoinit:\r
+    if CPU_Z180\r
+\r
+       ret\r
+\r
+    else ;CPU_Z180\r
+\r
+       call    msginit\r
+\r
+       ld      hl,buffers\r
+       ld      b,buftablen\r
+bfi_1:\r
+       ld      a,(hl)\r
+       inc     hl\r
+       ld      (bufdat+0),a\r
+       ld      e,(hl)\r
+       inc     hl\r
+       ld      d,(hl)\r
+       inc     hl\r
+       ex      de,hl\r
+\r
+       or      a\r
+       jr      nz,bfi_2\r
+\r
+       ld      a,(@cbnk)\r
+       call    bnk2phy\r
+\r
+       ld      (40h+0),hl\r
+       ld      (40h+2),a\r
+       out     (AVRINT5),a\r
+       jr      bfi_3\r
+bfi_2:\r
+\r
+       ld      a,(@cbnk)\r
+       call    bnk2phy\r
+\r
+       ld      (bufdat+1),hl\r
+       ld      (bufdat+3),a\r
+       ld      hl,inimsg\r
+       call    msg.sout\r
+bfi_3:\r
+       ex      de,hl\r
+       djnz    bfi_1\r
+       ret\r
+    endif\r
+\r
+\r
+\r
+\r
+;\r
+;----------------------------------------------------------------------\r
+;\r
+\r
+sysram_init:\r
+       ld hl,sysramw\r
+       ld de,topcodsys\r
+       ld bc,sysrame-sysramw\r
+       ldir\r
+\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+ivtab_init:\r
+       ld      hl,ivtab        ;\r
+       ld      a,h             ;\r
+       ld      i,a             ;\r
+    if CPU_Z180\r
+       out0    (il),l          ;\r
+    endif\r
+\r
+; Let all vectors point to spurious int routines.\r
+\r
+       ld      d,high sp.int0\r
+       ld      a,low  sp.int0\r
+       ld      b,9\r
+ivt_i1:\r
+       ld      (hl),a\r
+       inc     l\r
+       ld      (hl),d\r
+       inc     l\r
+       add     a,sp.int.len\r
+       djnz    ivt_i1\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+; Reload value for 10 ms Int. (0.1KHz):\r
+; tc10ms = phi/prescale/0.1KHz  = phi / (prescale/10)\r
+\r
+PRT_TC10MS     equ     18432 / (PRT_PRE/10)\r
+\r
+\r
+    if CPU_Z180\r
+prt0_init:\r
+       ld      a,i\r
+       ld      h,a\r
+       in0     a,(il)\r
+       and     0E0h\r
+       or      IV$PRT0\r
+       ld      l,a\r
+       ld      (hl),low  iprt0\r
+       inc     hl\r
+       ld      (hl),high iprt0\r
+       ld      hl,prt0itab\r
+       call    ioiniml\r
+       ret\r
+\r
+prt0itab:\r
+       db      prt0it_e-prt0itab-2\r
+       db      tmdr0l\r
+       dw      PRT_TC10MS\r
+       dw      PRT_TC10MS\r
+       db      M_TIE0+M_TDE0   ;enable timer 0 interrupt and down count.\r
+prt0it_e:\r
+       db      0\r
+    endif\r
+\r
+\r
+;\r
+;----------------------------------------------------------------------\r
+;\r
+\r
+    if CPU_Z180\r
+io.ini:\r
+     if 0\r
+       push    bc\r
+       ld      b,0             ;high byte port adress\r
+ioi_nxt:\r
+       ld      a,(hl)          ;count\r
+       inc     hl\r
+       or      a\r
+       jr      z,ioi_e\r
+\r
+       ld      c,(hl)          ;port address\r
+       inc     hl\r
+ioi_r:\r
+       outi\r
+       inc     b               ;outi decrements b\r
+       dec     a\r
+       jr      nz,ioi_r\r
+       jr      ioi_nxt\r
+ioi_e:\r
+       pop     bc\r
+       ret\r
+\r
+     else ;(if 1/0)\r
+\r
+       push    bc\r
+       jr      ioi_nxt\r
+ioi_l:\r
+       ld      c,(hl)          ;port address\r
+       inc     hl\r
+       inc     c\r
+ioi_r:\r
+       dec     c               ;otim increments c\r
+       otim\r
+       jr      z,ioi_r\r
+ioi_nxt:\r
+       ld      b,(hl)          ;count\r
+       inc     hl\r
+       inc     b               ;stop if count == 0\r
+       djnz    ioi_l\r
+       pop     bc\r
+       ret\r
+\r
+     endif ;(1/0)\r
+\r
+    else\r
+\r
+io.ini:\r
+       push    bc\r
+       jr      ioi_nxt\r
+ioi_l:\r
+       ld      c,(hl)          ;port address\r
+       inc     hl\r
+       otir\r
+ioi_nxt:\r
+       ld      b,(hl)          ;count\r
+       inc     hl\r
+       inc     b\r
+       djnz    ioi_l\r
+    endif\r
+       pop     bc\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+    if CPU_Z180\r
+\r
+       global ioiniml\r
+\r
+ioiniml:\r
+       push    bc\r
+       xor     a\r
+ioml_lp:\r
+       ld      b,(hl)\r
+       inc     hl\r
+       cp      b\r
+       jr      z,ioml_e\r
+\r
+       ld      c,(hl)\r
+       inc     hl\r
+       otimr\r
+       jr      ioml_lp\r
+ioml_e:\r
+       pop     bc\r
+       ret     z\r
+    endif\r
+\r
+io.ini.l:\r
+;\r
+\r
+\r
+\r
+;----------------------------------------------------------------------\r
+;\r
+    if CPU_Z180\r
+\r
+;--------------------------------------------------------------------\r
+; Return the BBR value for the given bank number\r
+;\r
+; in  a: Bank number\r
+; out a: bbr value\r
+\r
+bnk2log:\r
+       or      a               ;\r
+       ret     z               ; Bank 0 is at physical address 0\r
+\r
+       push    bc              ;\r
+       ld      b,a             ;\r
+       ld      c,CA            ;\r
+       mlt     bc              ;\r
+       ld      a,c             ;\r
+       add     a,10h           ;\r
+       pop     bc              ;\r
+       ret                     ;\r
+\r
+;--------------------------------------------------------------\r
+\r
+;in  hl: Log. Address\r
+;     a: Bank number\r
+;\r
+;out ahl: Phys. (linear) Address\r
+\r
+\r
+bnk2phy:\r
+       call    bnk2log\r
+       ; fall thru\r
+\r
+;--------------------------------------------------------------\r
+;\r
+; hl: Log. Address\r
+;  a: Bank base (bbr)\r
+;\r
+;           2           0       0\r
+;           0   6       8       0\r
+; hl             hhhhhhhhllllllll\r
+;  a   +     bbbbbbbb\r
+;\r
+; OP: ahl = (a<<12) + (h<<8) + l\r
+;\r
+;out ahl: Phys. (linear) Address\r
+\r
+log2phy:\r
+       push    bc              ;\r
+l2p_i:\r
+       ld      c,a             ;\r
+       ld      b,16            ;\r
+       mlt     bc              ; bc = a<<4\r
+       ld      a,c             ;\r
+       add     a,h             ;\r
+       ld      h,a             ;\r
+       ld      a,b             ;\r
+       adc     a,0             ;\r
+       pop     bc              ;\r
+       ret                     ;\r
+\r
+;--------------------------------------------------------------\r
+;\r
+; hl: Log. Address\r
+;\r
+;\r
+; OP: ahl = (bankbase<<12) + (d<<8) + e\r
+;\r
+;out ahl: Phys. (linear) Address\r
+\r
+       public  hwl2phy\r
+\r
+hwl2phy:\r
+       push    bc              ;\r
+       in0     c,(cbar)        ;\r
+       ld      a,h             ;\r
+       or      00fh            ; log. addr in common1?\r
+       cp      c\r
+       jr      c,hlp_1\r
+\r
+       in0     a,(cbr)         ; yes, cbr is address base\r
+       jr      hl2p_x\r
+hlp_1:\r
+       ld      b,16            ; log. address in baked area?\r
+       mlt     bc\r
+       ld      a,h\r
+       cp      c\r
+       jr      c,hlp_2\r
+       in0     a,(bbr)         ; yes, bbr is address base\r
+       jr      hl2p_x\r
+hlp_2:\r
+       xor     a               ; common1\r
+hl2p_x:\r
+       jr      nz,l2p_i\r
+\r
+       pop     bc              ; bank part is 0, no translation\r
+       ret                     ;\r
+\r
+\r
+\r
+    else       ;CPU_Z180\r
+\r
+;----------------------------------------------------------------------\r
+;\r
+\r
+bnk2phy:\r
+       sla     h\r
+       jr      nc,b2p_1                ;A15=1 --> common\r
+       ld      a,3\r
+b2p_1:\r
+       srl     a\r
+       rr      h\r
+       ret\r
+\r
+    endif\r
+\r
+;--------------------------------------------------------------\r
+;\r
+;return:\r
+; hl = hl + a\r
+; Flags undefined\r
+;\r
+\r
+add_hl_a:\r
+       add a,l\r
+       ld l,a\r
+       ret nc\r
+       inc h\r
+       ret\r
+\r
+; ---------------------------------------------------------\r
+\r
+sysramw:\r
+\r
+       .phase isvsw_loc\r
+topcodsys:\r
+\r
+; Trampoline for interrupt routines in banked ram.\r
+; Switch stack pointer to "system" stack in top ram\r
+; Save cbar\r
+\r
+isv_sw:                                ;\r
+       ex (sp),hl              ;save hl, 'return adr' in hl\r
+       push de                 ;\r
+       push af                 ;\r
+       ex de,hl                ;'return address' in de\r
+       ld hl,0                 ;\r
+       add hl,sp               ;\r
+       ld a,h                  ;\r
+       cp 0f8h                 ;\r
+       jr nc,isw_1             ;stack allready in top ram\r
+       ld sp,$stack            ;\r
+isw_1:\r
+       push hl                 ;save user stack pointer\r
+       in0 h,(cbar)            ;\r
+       push hl                 ;\r
+       ld a,SYS$CBAR           ;\r
+       out0 (cbar),a           ;\r
+       ex de,hl                ;\r
+       ld e,(hl)               ;\r
+       inc hl                  ;\r
+       ld d,(hl)               ;\r
+       ex de,hl                ;\r
+       push bc                 ;\r
+       call jphl               ;\r
+\r
+       pop bc                  ;\r
+       pop hl                  ;\r
+       out0 (cbar),h           ;\r
+       pop hl                  ;\r
+       ld sp,hl                ;\r
+       pop af                  ;\r
+       pop de                  ;\r
+       pop hl                  ;\r
+       ei                      ;\r
+       ret                     ;\r
+jphl:\r
+       jp (hl)                 ;\r
+\r
+; ---------------------------------------------------------\r
+\r
+    if CPU_Z180\r
+\r
+iprt0:\r
+       push    af\r
+       push    hl\r
+       in0     a,(tcr)\r
+       in0     a,(tmdr0l)\r
+       in0     a,(tmdr0h)\r
+       ld      a,(tim_ms)\r
+       inc     a\r
+       cp      100\r
+       jr      nz,iprt_1\r
+       xor     a\r
+       ld      hl,(tim_s)\r
+       inc     hl\r
+       ld      (tim_s),hl\r
+iprt_1:\r
+       ld      (tim_ms),a\r
+       pop     hl\r
+       pop     af\r
+       ei\r
+       ret\r
+\r
+    endif\r
+\r
+; ---------------------------------------------------------\r
+\r
+sp.int0:\r
+       ld      a,0d0h\r
+       jr      sp.i.1\r
+sp.int.len equ $-sp.int0\r
+       ld      a,0d1h\r
+       jr      sp.i.1\r
+       ld      a,0d2h\r
+       jr      sp.i.1\r
+       ld      a,0d3h\r
+       jr      sp.i.1\r
+       ld      a,0d4h\r
+       jr      sp.i.1\r
+       ld      a,0d5h\r
+       jr      sp.i.1\r
+       ld      a,0d6h\r
+       jr      sp.i.1\r
+       ld      a,0d7h\r
+       jr      sp.i.1\r
+       ld      a,0d8h\r
+sp.i.1:\r
+;      out     (80h),a\r
+       halt\r
+\r
+; ---------------------------------------------------------\r
+\r
+    if CPU_Z80\r
+\r
+; Get IFF2\r
+; This routine may not be loaded in page zero\r
+;\r
+; return Carry clear, if INTs are enabled.\r
+;\r
+       global getiff\r
+getiff:\r
+       xor     a               ;clear accu and carry\r
+       push    af              ;stack bottom := 00xxh\r
+       pop     af\r
+       ld      a,i             ;P flag := IFF2\r
+       ret     pe              ;exit carry clear, if enabled\r
+       dec     sp\r
+       dec     sp              ;has stack bottom been overwritten?\r
+       pop     af\r
+       and     a               ;if not 00xxh, INTs were\r
+       ret     nz              ;actually enabled\r
+       scf                     ;Otherwise, they really are disabled\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+       global  selbnk\r
+\r
+; a: bank (0..2)\r
+\r
+selbnk:\r
+       push    bc\r
+       ld      c,a\r
+       call    getiff\r
+       push    af\r
+\r
+       ld      a,c\r
+       di\r
+       ld      (@cbnk),a\r
+       ld      a,5\r
+       out     (SIOAC),a\r
+       ld      a,(mm_sio0)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOAC),a\r
+       ld      (mm_sio0),a\r
+\r
+       ld      a,5\r
+       out     (SIOBC),a\r
+       ld      a,(mm_sio1)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOBC),a\r
+       ld      (mm_sio1),a\r
+       pop     af\r
+       pop     bc\r
+       ret     c                       ;INTs were disabled\r
+       ei\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+; c: bank (0..2)\r
+\r
+    if 0\r
+\r
+selbnk:\r
+       ld      a,(@cbnk)\r
+       xor     c\r
+       and     3\r
+       ret     z               ;no change\r
+\r
+       call    getiff\r
+       push    af\r
+       ld      a,c\r
+       di\r
+       ld      (@cbnk),a\r
+       ld      a,5\r
+       out     (SIOAC),a\r
+       ld      a,(mm_sio0)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOAC),a\r
+       ld      (mm_sio0),a\r
+\r
+       ld      a,5\r
+       out     (SIOBC),a\r
+       ld      a,(mm_sio1)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOBC),a\r
+       ld      (mm_sio1),a\r
+       pop     af\r
+       ret     nc                      ;INTs were disabled\r
+       ei\r
+       ret\r
+\r
+    endif\r
+\r
+;----------------------------------------------------------------------\r
+\r
+    if 0\r
+       ex      af,af'\r
+       push    af\r
+       ex      af,af'\r
+\r
+       rra\r
+       jr      nc,stbk1\r
+       ex      af,af'\r
+       ld      a,5\r
+       out     (SIOAC),a\r
+       ld      a,(mm_sio0)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOAC),a\r
+       ld      (mm_sio1),a\r
+       ex      af,af'\r
+\r
+stbk1:\r
+       rra\r
+       jr      nc,stbk2\r
+       ex      af,af'\r
+       ld      a,5\r
+       out     (SIOBC),a\r
+       ld      a,(mm_sio1)\r
+       rla\r
+       srl     c\r
+       rra\r
+       out     (SIOBC),a\r
+       ld      (mm_sio1),a\r
+       ex      af,af'\r
+\r
+stbk2:\r
+    endif\r
+\r
+       global  @cbnk\r
+       global  mm_sio0, mm_sio1\r
+\r
+@cbnk: db      0               ; current bank (0..2)\r
+mm_sio0:\r
+       ds      1\r
+mm_sio1:\r
+       ds      1\r
+\r
+\r
+    endif\r
+\r
+;----------------------------------------------------------------------\r
+\r
+curph  defl    $\r
+       .dephase\r
+sysrame:\r
+       .phase curph\r
+tim_ms:        db      0\r
+tim_s: dw      0\r
+       .dephase\r
+\r
+;-----------------------------------------------------\r
+\r
+\r
+       cseg\r
+\r
+       ;.phase 0ffc0h\r
+;ivtab equ     0ffc0h          ; 0ffc0h        ;int vector table\r
+       ;.dephase\r
+\r
+       ;.phase 0fffah\r
+mark_55AA equ 0 - 2 - 4                ;2 byte for trap stack\r
+       ;ds     4\r
+       ;.dephase\r
+\r
+\r
+       end\r
diff --git a/z180/modebaud.inc b/z180/modebaud.inc
new file mode 100644 (file)
index 0000000..2e60e44
--- /dev/null
@@ -0,0 +1,31 @@
+       ; equates for mode byte bit fields\r
+\r
+mb$input               equ 00000001b   ; device may do input\r
+mb$output              equ 00000010b   ; device may do output\r
+mb$in$out              equ mb$input+mb$output\r
+\r
+mb$soft$baud           equ 00000100b   ; software selectable\r
+                                       ; baud rates\r
+\r
+mb$serial              equ 00001000b   ; device may use protocol\r
+mb$xon$xoff            equ 00010000b   ; XON/XOFF protocol\r
+                                       ; enabled\r
+\r
+baud$none              equ 0           ; no baud rate associated\r
+                                       ; with this device\r
+baud$50                        equ 1           ; 50 baud\r
+baud$75                        equ 2           ; 75 baud\r
+baud$110               equ 3           ; 110 baud\r
+baud$134               equ 4           ; 134.5 baud\r
+baud$150               equ 5           ; 150 baud\r
+baud$300               equ 6           ; 300 baud\r
+baud$600               equ 7           ; 600 baud\r
+baud$1200              equ 8           ; 1200 baud\r
+baud$1800              equ 9           ; 1800 baud\r
+baud$2400              equ 10          ; 2400 baud\r
+baud$3600              equ 11          ; 3600 baud\r
+baud$4800              equ 12          ; 4800 baud\r
+baud$7200              equ 13          ; 7200 baud\r
+baud$9600              equ 14          ; 9600 baud\r
+baud$19200             equ 15          ; 19.2k baud\r
+\r
diff --git a/z180/msgbuf-a.180 b/z180/msgbuf-a.180
new file mode 100644 (file)
index 0000000..3575569
--- /dev/null
@@ -0,0 +1,374 @@
+       page    255\r
+       .z80\r
+\r
+       public  mrx.fifo,mtx.fifo\r
+\r
+       public  msginit,msgi.st,msg.in,msgo.st\r
+       public  msg.sm,msg.sout\r
+\r
+       extrn   bufinit,hwl2phy\r
+       extrn   fifolst\r
+\r
+       include config.inc\r
+       if CPU_Z180\r
+       include z180reg.inc\r
+       endif\r
+\r
+;--------------------------------------------------------------\r
+\r
+       dseg\r
+\r
+       mkbuf   mtx.fifo_id, mtx.fifo, mtx.fifo_len\r
+       mkbuf   mrx.fifo_id, mrx.fifo, mrx.fifo_len\r
+\r
+;--------------------------------------------------------------\r
+\r
+       cseg\r
+\r
+;\r
+; Init buffer\r
+;\r
+\r
+msginit:\r
+       ld      a,(043h)\r
+;TODO: value should be 0\r
+       ld      ix,mtx.fifo\r
+       call    bufinit\r
+       push    ix\r
+       pop     hl\r
+       call    hwl2phy\r
+       ld      (040h),hl\r
+       ld      (040h+2),a\r
+       ld      a,0ffh\r
+       ld      (043h),a\r
+       out     (AVRINT5),a\r
+wait:\r
+       ld      a,(043h)\r
+       or      a\r
+       jr      nz,wait\r
+\r
+       ld      ix,mrx.fifo\r
+       jp      bufinit\r
+\r
+;--------------------------------------------------------------\r
+\r
+msgi.st:\r
+       push    ix\r
+       ld      ix,mrx.fifo             ;\r
+\r
+buf.empty:\r
+       ld      a,(ix+o.in_idx)         ;\r
+       sub     (ix+o.out_idx)          ;\r
+       pop     ix\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+;--------------------------------------------------------------\r
+\r
+msg.in:\r
+       push    ix\r
+       ld      ix,mrx.fifo             ;\r
+\r
+buf.get:\r
+       ld      a,(ix+o.out_idx)        ;\r
+bg.wait:\r
+       cp      (ix+o.in_idx)           ;\r
+       jr      z,bg.wait\r
+\r
+       push    hl                      ;\r
+       push    ix\r
+       pop     hl\r
+       add     a,l\r
+       ld      l,a\r
+       jr      nc,bg.nc\r
+       inc     h\r
+bg.nc:\r
+       ld      l,(hl)\r
+\r
+       ld      a,(ix+o.out_idx)        ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       ld      (ix+o.out_idx),a\r
+\r
+       ld      a,l\r
+       pop     hl\r
+       pop     ix\r
+       ret\r
+\r
+;--------------------------------------------------------------\r
+\r
+msgo.st:\r
+       push    ix\r
+       ld      ix,mtx.fifo             ;\r
+\r
+buf.full:\r
+       ld      a,(ix+o.in_idx)         ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       sub     (ix+o.out_idx)          ;\r
+       pop     ix\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+;--------------------------------------------------------------\r
+\r
+    if 0\r
+\r
+msg.out:\r
+       push    ix\r
+       ld      ix,mtx.fifo             ;\r
+\r
+buf.put:\r
+       push    hl                      ;\r
+       push    bc\r
+       push    ix\r
+       pop     hl\r
+       ld      c,(ix+o.in_idx)         ;\r
+       ld      b,0\r
+       add     hl,bc\r
+       ld      b,a\r
+\r
+       ld      a,c                     ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+bp.wait:\r
+       cp      (ix+o.out_idx)          ;\r
+       jr      z,bp.wait\r
+       ld      (hl),b\r
+       ld      (ix+o.in_idx),a\r
+\r
+       ld      a,b\r
+       out     (AVRINT5),a\r
+       pop     bc\r
+       pop     hl\r
+       pop     ix\r
+       ret\r
+\r
+    endif\r
+\r
+;--------------------------------------------------------------\r
+\r
+   if 0\r
+\r
+msg.out:\r
+       push    ix\r
+       ld      ix,mtx.fifo             ;\r
+\r
+buf.put:\r
+       push    bc\r
+       ld      c,(ix+o.in_idx)         ;\r
+       ld      b,0\r
+       push    ix                      ;14\r
+       add     ix,bc                   ;10\r
+       ld      (ix+0),a                ;15\r
+       pop     ix                      ;12 / 51\r
+       ld      b,a                     ; 4\r
+       ld      a,c                     ;\r
+       inc     a                       ;\r
+       and     (ix+o.mask)             ;\r
+bp.wait:\r
+       cp      (ix+o.out_idx)          ;\r
+       jr      z,bp.wait               ;\r
+       ld      (ix+o.in_idx),a         ;\r
+\r
+       ld      a,b\r
+       out     (AVRINT5),a\r
+       pop     bc\r
+       pop     ix\r
+       ret\r
+\r
+   endif\r
+\r
+;----------------------------------------------------------------------\r
+;\r
+; Put char in message buffer:\r
+;     ix: buffer to put into\r
+;     c:  char\r
+\r
+buf.put:\r
+       push    ix                      ;15\r
+       push    bc                      ;11\r
+       ld      a,(ix+o.in_idx)         ;19\r
+       ld      c,a                     ;4\r
+       ld      b,0                     ;7\r
+       add     ix,bc                   ;11\r
+       pop     bc                      ;10\r
+       ld      (ix),c                  ;7\r
+       pop     ix                      ;14\r
+\r
+       inc     a                       ;4\r
+       and     (ix+o.mask)             ;19     =121\r
+bufp.wait:\r
+       cp      (ix+o.out_idx)          ;19\r
+       jr      z,bufp.wait             ;12/7\r
+       ld      (ix+o.in_idx),a         ;19\r
+\r
+       out     (AVRINT5),a             ;11\r
+       ld      a,c                     ;4\r
+       ret                             ;10     =191\r
+\r
+\r
+;--------------------------------------------------------------\r
+\r
+    if 0\r
+       ; Works only, if buffer size < (128 - 3)\r
+       ;       --> mask must be 03fh or less\r
+\r
+msg.out:\r
+       push    ix\r
+       ld      ix,mtx.fifo             ;\r
+\r
+buf.put:\r
+       push    bc\r
+       ld      b,a                     ; 4\r
+       ld      a,(ix+o.in_idx)         ;14\r
+       ld      ($ + 3 + 2),a           ;15\r
+       ld      (ix+0),b                ;15\r
+       inc     a                       ;\r
+       and     (ix+o.mask)             ;\r
+bp.wait:\r
+       cp      (ix+o.out_idx)          ;\r
+       jr      z,bp.wait               ;\r
+       ld      (ix+o.in_idx),a         ;\r
+\r
+       ld      a,b\r
+       out     (AVRINT5),a\r
+       pop     bc\r
+       pop     ix\r
+       ret\r
+\r
+    endif\r
+\r
+;--------------------------------------------------------------\r
+;\r
+; (hl): data\r
+\r
+msg.sout:\r
+       push    ix                      ;14\r
+       ld      ix,mtx.fifo             ;12\r
+       push    bc                      ;11\r
+       push    de                      ;11\r
+       ld      c,(hl)                  ; 6\r
+       ld      b,0                     ; 6\r
+       inc     hl                      ; 7\r
+ms.ol:                                 ;       \\r
+       ld      a,low mtx.fifo          ; 6\r
+       add     a,(ix+o.in_idx)         ;14\r
+       ld      e,a                     ; 4\r
+       ld      a,high mtx.fifo         ; 6\r
+       adc     a,b                     ; 4\r
+       ld      d,a                     ; 4\r
+\r
+       ld      a,(ix+o.in_idx)         ;14\r
+       inc     a                       ; 4\r
+       and     (ix+o.mask)             ;14\r
+ms.wait:\r
+       cp      (ix+o.out_idx)          ;14\r
+       jr      z,ms.wait               ; 6/8\r
+\r
+       ldi                             ;12\r
+       ld      (ix+o.in_idx),a         ;15\r
+       jp      pe,ms.ol                ; 6/9    -- 126\r
+\r
+       out     (AVRINT5),a             ;10\r
+       pop     de                      ; 9\r
+       pop     bc                      ; 9\r
+       pop     ix                      ;12\r
+       ret                             ; 9\r
+\r
+;--------------------------------------------------------------\r
+;\r
+; (hl): data\r
+\r
+    if 0\r
+\r
+msg.sout:\r
+       push    ix                      ;14\r
+       ld      ix,mtx.fifo             ;12\r
+       push    bc                      ;11\r
+       push    de                      ;11\r
+       ld      b,(hl)                  ; 6\r
+       inc     hl                      ; 4\r
+       ex      de,hl                   ; 3\r
+ms.ol:                                 ;       \\r
+       push    ix                      ;14\r
+       pop     hl                      ; 9\r
+       ld      c,(ix+o.in_idx)         ;14\r
+       ld      a,c                     ; 4\r
+       add     l                       ; 4\r
+       ld      l,a                     ; 4\r
+       jr      nc,ms.on                ; 6/8\r
+       inc     h                       ; 4\r
+ms.on:\r
+       ld      a,c                     ; 4\r
+       inc     a                       ; 4\r
+       and     (ix+o.mask)             ;14\r
+ms.wait:\r
+       cp      (ix+o.out_idx)          ;14\r
+       jr      z,ms.wait               ; 6/8\r
+       ld      c,a                     ; 4\r
+       ld      a,(de)                  ; 6\r
+       inc     de                      ; 4\r
+       ld      (hl),a                  ; 7\r
+       ld      (ix+o.in_idx),c         ;15\r
+       djnz    ms.ol                   ; 7/9   -- 130\r
+\r
+       out     (AVRINT5),a             ;10\r
+       ex      de,hl                   ; 3\r
+       pop     de                      ; 9\r
+       pop     bc                      ; 9\r
+       pop     ix                      ;12\r
+       ret                             ; 9\r
+\r
+    endif\r
+\r
+;--------------------------------------------------------------\r
+\r
+msg.co:\r
+       push    af\r
+       push    hl\r
+       ld      (buf_char),a\r
+       ld      hl,buf\r
+       call    msg.sout\r
+       pop     hl\r
+       pop     af\r
+       ret\r
+\r
+\r
+buf:\r
+       db      buf_end - $ - 1         ;output string length\r
+       db      0AEh                    ; message start token\r
+       db      buf_end - $ - 1         ; message length\r
+       db      1                       ; command\r
+       db      1                       ; subcommand\r
+buf_char:\r
+       db      0                       ; pay load\r
+buf_end:\r
+\r
+;----------------------------------------------------------------------\r
+\r
+;----------------------------------------------------------------------\r
+; Send message MEMORY\r
+;\r
+;     hl: pointer to message (netto)\r
+;     b: msg length\r
+\r
+msg.sm:\r
+       push    ix\r
+       ld      ix,mtx.fifo\r
+       ld      c,0AEh\r
+       call    buf.put\r
+       ld      c,b\r
+       call    buf.put\r
+msm_l:\r
+       ld      c,(hl)\r
+       inc     hl\r
+       call    buf.put\r
+       djnz    msm_l\r
+       pop     ix\r
+       ret\r
+\r
+\r
+       end\r
diff --git a/z180/msgbuf-s.180 b/z180/msgbuf-s.180
new file mode 100644 (file)
index 0000000..6bfd709
--- /dev/null
@@ -0,0 +1,129 @@
+       page    255\r
+       .z80\r
+       \r
+       global  msg_fifo\r
+       global  msginit\r
+       global  msg.out,msg.sout,msg.co\r
+       \r
+       extrn   buf.init\r
+\r
+       include config.inc\r
+       include z180reg.inc\r
+\r
+;--------------------------------------------------------------\r
+\r
+       dseg\r
+\r
+       mkbuf   msg_fifo, 0\r
+\r
+\r
+;--------------------------------------------------------------\r
+\r
+       cseg\r
+\r
+;\r
+; Init buffer\r
+;\r
+       \r
+msginit:\r
+       ld      ix,msg_fifo\r
+       ld      a,msg_fb_len-1\r
+       jp      buf.init\r
+\r
+\r
+;--------------------------------------------------------------\r
+\r
+msg.sts:\r
+       push    ix\r
+       ld      ix,msg_fifo             ;\r
+\r
+       ld      a,(ix+o.in_idx)         ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       sub     (ix+o.out_idx)          ;\r
+       pop     ix\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+;--------------------------------------------------------------\r
+\r
+msg.out:\r
+       push    ix\r
+       ld      ix,msg_fifo             ;\r
+\r
+       push    bc\r
+       ld      b,a                     ;save char\r
+       ld      a,(ix+o.in_idx)         ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+bp.wait:\r
+       cp      (ix+o.out_idx)          ;\r
+       jr      z,bp.wait\r
+       ld      c,a\r
+       ld      a,b\r
+       out     (PMSG),a\r
+       ld      (ix+o.in_idx),c\r
+       \r
+       pop     bc\r
+       pop     ix\r
+       ret\r
+\r
+;--------------------------------------------------------------\r
+;\r
+; (hl): data\r
+  \r
+msg.sout:\r
+       push    ix\r
+       ld      ix,msg_fifo             ;\r
+       push    bc\r
+\r
+       ld      b,(hl)                  ;count\r
+       inc     hl\r
+obs_1:\r
+       ld      a,(ix+o.out_idx)        ;\r
+       sub     (ix+o.in_idx)           ;\r
+       dec     a\r
+       and     (ix+o.mask)\r
+       cp      b\r
+       jr      c,obs_1\r
+\r
+       ld      c,(hl)                  ;port address\r
+       inc     hl\r
+       ld      a,b\r
+       otir\r
+       add     (ix+o.in_idx)\r
+       and     (ix+o.mask)\r
+       ld      (ix+o.in_idx),a\r
+       pop     bc\r
+       pop     ix\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+\r
+msg.co:\r
+       push    af\r
+       push    hl\r
+       ld      (buf_char),a\r
+       ld      hl,buf\r
+       call    msg.sout\r
+       pop     hl\r
+       pop     af\r
+       ret\r
+       \r
+       \r
+buf:\r
+       db      buf_end - $ - 2         ;output string length\r
+       db      PMSG                    ;output port\r
+       db      0AEh                    ; message start token\r
+       db      buf_end - $ - 1         ; message length\r
+       db      1                       ; command\r
+       db      1                       ; subcommand\r
+buf_char:\r
+       db      0                       ; pay load\r
+buf_end:\r
+\r
+;----------------------------------------------------------------------\r
+\r
+       end\r
+\r
diff --git a/z180/msgfifo.180 b/z180/msgfifo.180
new file mode 100644 (file)
index 0000000..cf1ae2a
--- /dev/null
@@ -0,0 +1,259 @@
+       page    255\r
+       .z80\r
+\r
+       global  msg_rx_fifo,msg_tx_fifo\r
+\r
+       global  msginit,msgi.st,msg.in,msgo.st,msg.out\r
+       global  msg.sout,msg.co\r
+\r
+       extrn   buf.init\r
+\r
+       include config.inc\r
+       include z180reg.inc\r
+\r
+;--------------------------------------------------------------\r
+\r
+       dseg\r
+\r
+       mkbuf   mtx.fifo_id, msg_tx_fifo, msg_tx_fifo_len\r
+       mkbuf   mrx.fifo_id, msg_rx_fifo, msg_rx_fifo_len\r
+\r
+\r
+\r
+;--------------------------------------------------------------\r
+\r
+       cseg\r
+\r
+;\r
+; Init buffer\r
+;\r
+\r
+msginit:\r
+       ld      ix,msg_rx_fifo\r
+       ld      a,msg_rx_fifo.mask\r
+       call    buf.init\r
+       ld      ix,msg_tx_fifo\r
+       ld      a,msg_tx_fifo.mask\r
+       jp      buf.init\r
+\r
+;--------------------------------------------------------------\r
+\r
+msgi.st:\r
+       push    ix\r
+       ld      ix,msg_rx_fifo          ;\r
+\r
+buf.empty:\r
+       ld      a,(ix+o.in_idx)         ;\r
+       sub     (ix+o.out_idx)          ;\r
+       pop     ix\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+;--------------------------------------------------------------\r
+\r
+msg.in:\r
+       push    ix\r
+       ld      ix,msg_rx_fifo          ;\r
+\r
+buf.get:\r
+       ld      a,(ix+o.out_idx)        ;\r
+bg.wait:\r
+       cp      (ix+o.in_idx)           ;\r
+       jr      z,bg.wait\r
+\r
+       push    hl                      ;\r
+       push    ix\r
+       pop     hl\r
+       add     a,l\r
+       ld      l,a\r
+       jr      nc,bg.nc\r
+       inc     h\r
+bg.nc:\r
+       ld      l,(hl)\r
+\r
+       ld      a,(ix+o.out_idx)        ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       ld      (ix+o.out_idx),a\r
+\r
+       ld      a,l\r
+       pop     hl\r
+       pop     ix\r
+       ret\r
+\r
+;--------------------------------------------------------------\r
+\r
+msgo.st:\r
+       push    ix\r
+       ld      ix,msg_tx_fifo          ;\r
+\r
+buf.full:\r
+       ld      a,(ix+o.in_idx)         ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+       sub     (ix+o.out_idx)          ;\r
+       pop     ix\r
+       ret     z\r
+       or      0ffh\r
+       ret\r
+\r
+;--------------------------------------------------------------\r
+\r
+msg.out:\r
+       push    ix\r
+       ld      ix,msg_tx_fifo          ;\r
+\r
+buf.put:\r
+       push    hl                      ;\r
+       push    bc\r
+       push    ix\r
+       pop     hl\r
+       ld      c,(ix+o.in_idx)         ;\r
+       ld      b,0\r
+       add     hl,bc\r
+       ld      b,a\r
+\r
+       ld      a,c                     ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+bp.wait:\r
+       cp      (ix+o.out_idx)          ;\r
+       jr      z,bp.wait\r
+       ld      (hl),b\r
+       ld      (ix+o.in_idx),a\r
+\r
+       ld      a,b\r
+       out0    (AVRINT5),a\r
+       pop     bc\r
+       pop     hl\r
+       pop     ix\r
+       ret\r
+\r
+\r
+;--------------------------------------------------------------\r
+;--------------------------------------------------------------\r
+;--------------------------------------------------------------\r
+\r
+if 0\r
+msg.out:\r
+       push    ix\r
+       ld      ix,msg_fifo             ;\r
+\r
+       push    bc\r
+       ld      b,a                     ;save char\r
+       ld      a,(ix+o.in_idx)         ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+bp.wait:\r
+       cp      (ix+o.out_idx)          ;\r
+       jr      z,bp.wait\r
+       ld      c,a\r
+       ld      a,b\r
+       out     (PMSG),a\r
+       ld      (ix+o.in_idx),c\r
+\r
+       pop     bc\r
+       pop     ix\r
+       ret\r
+endif\r
+\r
+;--------------------------------------------------------------\r
+;\r
+; (hl): data\r
+\r
+msg.sout:\r
+       push    ix\r
+       ld      ix,msg_tx_fifo          ;\r
+\r
+       push    bc\r
+       push    de\r
+       ld      b,(hl)                  ;\r
+       inc     hl\r
+       ex      de,hl\r
+\r
+ms.ol:\r
+       push    ix\r
+       pop     hl\r
+       ld      c,(ix+o.in_idx)         ;\r
+       ld      a,c\r
+       add     l\r
+       ld      l,a\r
+       jr      nc,ms.on\r
+       inc     h\r
+ms.on:\r
+       ld      a,c                     ;\r
+       inc     a\r
+       and     (ix+o.mask)\r
+ms.wait:\r
+       cp      (ix+o.out_idx)          ;\r
+       jr      z,ms.wait\r
+       ld      c,a\r
+       ld      a,(de)\r
+       inc     de\r
+       ld      (hl),a\r
+       ld      (ix+o.in_idx),c\r
+       djnz    ms.ol\r
+       out0    (AVRINT5),a\r
+       ex      de,hl\r
+       pop     de\r
+       pop     bc\r
+       pop     ix\r
+       ret\r
+\r
+;--------------------------------------------------------------\r
+\r
+if 0\r
+msg.sout:\r
+       push    ix\r
+       ld      ix,msg_fifo             ;\r
+       push    bc\r
+\r
+       ld      b,(hl)                  ;count\r
+       inc     hl\r
+obs_1:\r
+       ld      a,(ix+o.out_idx)        ;\r
+       sub     (ix+o.in_idx)           ;\r
+       dec     a\r
+       and     (ix+o.mask)\r
+       cp      b\r
+       jr      c,obs_1\r
+\r
+       ld      c,(hl)                  ;port address\r
+       inc     hl\r
+       ld      a,b\r
+       otir\r
+       add     (ix+o.in_idx)\r
+       and     (ix+o.mask)\r
+       ld      (ix+o.in_idx),a\r
+       pop     bc\r
+       pop     ix\r
+       ret\r
+\r
+;----------------------------------------------------------------------\r
+endif\r
+\r
+msg.co:\r
+       push    af\r
+       push    hl\r
+       ld      (buf_char),a\r
+       ld      hl,buf\r
+       call    msg.sout\r
+       pop     hl\r
+       pop     af\r
+       ret\r
+\r
+\r
+buf:\r
+       db      buf_end - $ - 1         ;output string length\r
+       db      081h                    ; message start token\r
+       db      buf_end - $ - 1         ; message length\r
+       db      1                       ; command\r
+       db      1                       ; subcommand\r
+buf_char:\r
+       db      0                       ; pay load\r
+buf_end:\r
+\r
+;----------------------------------------------------------------------\r
+\r
+       end\r
diff --git a/z180/romend.180 b/z180/romend.180
new file mode 100644 (file)
index 0000000..2a63342
--- /dev/null
@@ -0,0 +1,9 @@
+\r
+       global  romend\r
+\r
+       cseg\r
+\r
+romend equ     $\r
+       \r
+       end\r
+\r
diff --git a/z180/z180.lib b/z180/z180.lib
new file mode 100644 (file)
index 0000000..ffe0ab7
--- /dev/null
@@ -0,0 +1,120 @@
+       .xlist\r
+;;\r
+;; Z180 / HD64180 MACRO LIBRARY\r
+;;\r
+\r
+IFNDEF SLP\r
+\r
+;;\r
+;;\r
+;;     HD64180 instructions:\r
+;;\r
+;;     SLP                     ; Enter SLEEP mode\r
+;;     MLT     RR              ; 8 bit multiply with 16 bit result\r
+;;     IN0     R,P             ; Input from internal port\r
+;;     OUT0    P,R             ; Output to internal port\r
+;;     OTIM                    ; Block output, increment\r
+;;     OTIMR                   ; Block output, increment and repeat\r
+;;     OTDM                    ; Block output, decrement\r
+;;     OTDMR                   ; Block output, decrement and repeat\r
+;;     TSTIO   P               ; Non destructive AND, I/O port and A\r
+;;     TST     R               ; Non destructive AND, reg and A\r
+;;     TST     ID              ; Non destructive AND, immediate data and A\r
+;;     TST     (HL)            ; Non destructive AND, (HL) and A\r
+;;\r
+;;\r
+\r
+??BC   EQU     0       ; Double-register definitions\r
+??DE   EQU     1\r
+??HL   EQU     2\r
+??SP   EQU     3\r
+\r
+??A    EQU     7       ; Single-register defintions\r
+??B    EQU     0\r
+??C    EQU     1\r
+??D    EQU     2\r
+??E    EQU     3\r
+??H    EQU     4\r
+??L    EQU     5\r
+\r
+SLP    MACRO\r
+       DEFB    0EDH,76H\r
+       ENDM\r
+\r
+MLT    MACRO   ?R\r
+       DB      0EDH,4CH+(??&?R AND 3) SHL 4\r
+       ENDM\r
+\r
+IN0    MACRO   ?R,?P\r
+       DB      0EDH,(??&?R AND 7) SHL 3, ?P\r
+       ENDM\r
+\r
+OUT0   MACRO   ?P,?R\r
+       DB      0EDH,1+(??&?R AND 7) SHL 3,?P\r
+       ENDM\r
+\r
+OTIM   MACRO\r
+       DB      0EDH,83H\r
+       ENDM\r
+\r
+OTIMR  MACRO\r
+       DB      0EDH,93H\r
+       ENDM\r
+\r
+OTDM   MACRO\r
+       DB      0EDH,8BH\r
+       ENDM\r
+\r
+OTDMR  MACRO\r
+       DB      0EDH,9BH\r
+       ENDM\r
+\r
+TSTIO  MACRO   ?P\r
+       DB      0EDH,74H,?P\r
+       ENDM\r
+\r
+TSTR   MACRO   ?R\r
+       DB      0EDH,4+(??&?R AND 7) SHL 3\r
+       ENDM\r
+\r
+TSTD   MACRO   ?P\r
+       DB      0EDH,64H,?P\r
+       ENDM\r
+\r
+TSTP   MACRO\r
+       DB      0EDH,34H\r
+       ENDM\r
+\r
+TST    MACRO   ?R\r
+         ?D: SET 0\r
+         IRPC  ?X,?R\r
+         ?D: SET ?D+1          ; Count # chars in "?R"\r
+         ENDM\r
+           IF ?D EQ 1          ; IF # chars = 1\r
+            IRPC ?X,ABCDEHL    ; Look up the character\r
+              IF ??&?X EQ ??&?R\r
+              DB       0EDH,4+(??&?R AND 7) SHL 3\r
+              EXITM\r
+              ENDIF\r
+            ENDM\r
+            DB     0EDh,64h,?R\r
+            EXITM\r
+           ENDIF\r
+       IF      (?R = 2) & (?D = 4)\r
+          ?D: SET 0\r
+          IRPC ?X,?R\r
+               IFIDN <?X>,<(>\r
+                   DB 0EDh,34h\r
+                   EXITM\r
+               ENDIF\r
+          ?D: SET ?D + 1\r
+          ENDM\r
+       ENDIF\r
+       IF ?D NE 0\r
+          DB   0EDH,64H,?R\r
+       ENDIF\r
+       ENDM\r
+\r
+ENDIF ;/* IFNDEF SLP /\r
+       .list\r
+\r
diff --git a/z180/z180reg.inc b/z180/z180reg.inc
new file mode 100644 (file)
index 0000000..a1a90c2
--- /dev/null
@@ -0,0 +1,197 @@
+       .xlist\r
+\r
+;;\r
+;; HD64180/Z180 Register Definitions\r
+;;\r
+\r
+\r
+b2m    macro   name,nr\r
+name   equ     nr\r
+M_&name        equ     1 shl nr\r
+       endm\r
+\r
+;      ifndef  IOBASE\r
+IOBASE equ     0\r
+;      endif\r
+\r
+cntla0 equ     IOBASE+00h      ;ASCI Control Register A Channel 0\r
+cntla1 equ     IOBASE+01h      ;ASCI Control Register A Channel 1\r
+       b2m MPE, 7              ;Multi-Processor Mode Enable\r
+       b2m RE, 6               ;Receiver Enable\r
+       b2m TE, 5               ;Transmitter Enable\r
+       b2m RTS0, 4             ;Request to Send Channel 0\r
+       b2m CKA1D, 4            ;\r
+       b2m MPBR, 3             ;Multiprocessor Bit Receive (Read)\r
+       b2m EFR, 3              ;Error Flag Reset (Write)\r
+       b2m MOD2, 2             ;Data Format Mode 1 = 8-Bit data\r
+       b2m MOD1, 1             ;1 = Parity enabled\r
+       b2m MOD0, 0             ;1 = 2 stop bits\r
+\r
+cntlb0 equ     IOBASE+02h      ;ASCI Control Register B Channel 0\r
+cntlb1 equ     IOBASE+03h      ;ASCI Control Register B Channel 1\r
+       b2m MPBT,7              ;Multiprocessor Bit Transmit\r
+       b2m MP,6                ;Multiprocessor Mode\r
+       b2m CTS,5               ;Clear to Send\r
+       b2m PS,5                ;Prescale\r
+       b2m PEO,4               ;Parity Even Odd\r
+       b2m DR,3                ;Divede Ratio\r
+       b2m SS2,2               ;Source/Speed Select 2,1,0\r
+       b2m SS1,1               ;\r
+       b2m SS0,0               ;\r
+\r
+stat0  equ     IOBASE+04h      ;ASCI Status Channel 0\r
+stat1  equ     IOBASE+05h      ;ASCI Status Channel 1\r
+       b2m RDRF,7              ;Receive Data Register Full\r
+       b2m OVRN,6              ;Overrun Error\r
+       b2m PERR,5              ;Parity Error   (M80: PE conflicts with JP/CALL cc)\r
+       b2m FE,4                ;Framing Error\r
+       b2m RIE,3               ;Receive Interrupt Enable\r
+       b2m DCD0,2              ;Data Carrier Detect (Ch 0)\r
+       b2m CTS1E,2             ;Clear To Send Enable (Ch 1)\r
+       b2m TDRE,1              ;Transmit Data Register Empty\r
+       b2m TIE,0               ;Transmit Interrupt Enable\r
+\r
+tdr0   equ     IOBASE+06h      ;ASCI Transmit Data\r
+tdr1   equ     IOBASE+07h      ;ASCI Transmit Data\r
+rdr0   equ     IOBASE+08h      ;ASCI Receive Data\r
+rdr1   equ     IOBASE+09h      ;ASCI Receive Data\r
+\r
+cntr   equ     IOBASE+0Ah      ;CSI/O Control Register\r
+trdr   equ     IOBASE+0Bh      ;CSI/O Transmit/Receive Data Register\r
+\r
+tmdr0l equ     IOBASE+0Ch      ;Timer Data Register Channel 0\r
+tmdr0h equ     IOBASE+0Dh      ;\r
+rldr0l equ     IOBASE+0Eh      ;Timer Reload Register Channel 0\r
+rldr0h equ     IOBASE+0Fh      ;\r
+tcr    equ     IOBASE+10h      ;Timer Control Register\r
+       b2m TIF1,7              ;Timer Interrupt Flag\r
+       b2m TIF0,6              ;\r
+       b2m TIE1,5              ;Timer Interrupt Enable\r
+       b2m TIE0,4              ;\r
+       b2m TOC1,3              ;Timer Output Control\r
+       b2m TOC0,2              ;\r
+       b2m TDE1,1              ;Timer Down Count Enable\r
+       b2m TDE0,0              ;\r
+\r
+\r
+asext0 equ     IOBASE+12h      ;ASCI Extension Control Register\r
+asext1 equ     IOBASE+13h      ;ASCI Extension Control Register\r
+       b2m DCD0DIS,6           ;DCD0 Disable\r
+       b2m CTS0DIS,5           ;CTS0 Disable\r
+       b2m X1,4                ;CKA * 1 Clock/Samle Rate Divider\r
+       b2m BRGMOD,3            ;BRG Mode (Baud rate generator)\r
+       b2m BREAKEN,2           ;Break Enable\r
+       b2m BREAK,1             ;Break detected\r
+       b2m SENDBREAK,0         ;Send Break\r
+\r
+tmdr1l equ     IOBASE+14h      ;Timer Data Register Channel 1\r
+tmdr1h equ     IOBASE+15h      ;\r
+rldr1l equ     IOBASE+16h      ;Timer Reload Register Channel 1\r
+rldr1h equ     IOBASE+17h      ;\r
+\r
+frc    equ     IOBASE+18h      ;Free Running Counter\r
+\r
+astc0l equ     IOBASE+1Ah      ;ASCI Time Constant Register 0\r
+astc0h equ     IOBASE+1Bh      ;\r
+astc1l equ     IOBASE+1Ch      ;ASCI Time Constant Register 1\r
+astc1h equ     IOBASE+1Dh      ;\r
+\r
+cmr    equ     IOBASE+1Eh      ;Clock Mutiplier Register\r
+       b2m X2CM,7              ;X2 Clock Multiplier\r
+       b2m LNC,6               ;Low Noise Crystal\r
+\r
+ccr    equ     IOBASE+1Fh      ;CPU Control Register\r
+       b2m NCD 7               ;No Clock Divide\r
+\r
+sar0l  equ     IOBASE+20h      ;DMA Src Adr Register Channel 0\r
+sar0h  equ     IOBASE+21h      ;\r
+sar0b  equ     IOBASE+22h      ;\r
+dar0l  equ     IOBASE+23h      ;DMA Dst Adr Register Channel 0\r
+dar0h  equ     IOBASE+24h      ;\r
+dar0b  equ     IOBASE+25h      ;\r
+bcr0l  equ     IOBASE+26h      ;DMA Byte Count Register Channel 0\r
+bcr0h  equ     IOBASE+27h      ;\r
+\r
+mar1l  equ     IOBASE+28h      ;DMA Memory Address Register Channel 1\r
+mar1h  equ     IOBASE+29h      ;\r
+mar1b  equ     IOBASE+2Ah      ;\r
+iar1l  equ     IOBASE+2Bh      ;DMA I/O Address Register Channel 1\r
+iar1h  equ     IOBASE+2Ch      ;\r
+iar1b  equ     IOBASE+2Dh      ;\r
+       b2m ALTE,7              ;Alternating Chnnels\r
+       b2m ALTC,6              ;Currently selected DMA Channel when Bit7=1\r
+       b2m REQ1SEL2,2          ;\r
+       b2m REQ1SEL1,1          ;\r
+       b2m REQ1SEL0,0          ;\r
+\r
+bcr1l  equ     IOBASE+2Eh      ;DMA Byte Count Register Channel 1\r
+bcr1h  equ     IOBASE+2Fh      ;\r
+\r
+dstat  equ     IOBASE+30h      ;DMA Status Register\r
+       b2m DE1,7               ;DMA enable ch 1,0\r
+       b2m DE0,6               ;\r
+       b2m NDWE1,5             ;DMA Enable Bit Write Enable 1,0\r
+       b2m NDWE0,4             ;\r
+       b2m DIE1,3              ;DMA Interrupt Enable 1,0\r
+       b2m DIE0,2              ;\r
+       b2m DME,0               ;DMA Master enable\r
+\r
+dmode  equ     IOBASE+31h      ;DMA Mode Register\r
+       b2m DM1,5               ;Ch 0 Destination Mode 1,0\r
+       b2m DM0,4               ;\r
+       b2m SM1,3               ;Ch 0 Source Mode 1,0\r
+       b2m SM0,2               ;\r
+       b2m MMOD,1              ;Memory MODE select (0=cycle steel/1=burst)\r
+\r
+dcntl  equ     IOBASE+32h      ;DMA/WAIT Control\r
+       b2m MWI1,7              ;Memory Wait Insertion\r
+       b2m MWI0,6              ;\r
+       b2m IWI1,5              ;I/O Wait Insertion\r
+       b2m IWI0,4              ;\r
+       b2m DMS1,3              ;DREQi Select (Edge/Level)\r
+       b2m DMS0,2              ;\r
+       b2m DIMA1,1             ;DMA Ch1 I/O Memory Mode Select\r
+       b2m DIMA0,0\r
+M_MWI  equ M_MWI1 + M_MWI0\r
+M_IWI  equ M_IWI1 + M_IWI0\r
+\r
+il     equ     IOBASE+33h      ;Interrupt Vector Low Register\r
+itc    equ     IOBASE+34h      ;INT/TRAP Control Register\r
+       b2m TRAP,7              ;Trap\r
+       b2m UFO,6               ;Unidentified Fetch Object\r
+       b2m ITE2,2              ;/INT Enable 2,1,0\r
+       b2m ITE1,1              ;\r
+       b2m ITE0,0              ;\r
+\r
+rcr    equ     IOBASE+36h      ;Refresh Control Register\r
+       b2m REFE,7              ;Refresh Enable\r
+       b2m REFW,6              ;Refresh Wait State\r
+       b2m CYC1,1              ;Cycle select\r
+       b2m CYC0,0              ;\r
+\r
+cbr    equ     IOBASE+38h      ;MMU Common Base Register\r
+bbr    equ     IOBASE+39h      ;MMU Bank Base Register\r
+cbar   equ     IOBASE+3Ah      ;MMU Common/Bank Register\r
+\r
+omcr   equ     IOBASE+3Eh      ;Operation Mode Control Register\r
+       b2m M1E,7               ;M1 Enable\r
+       b2m M1TE,6              ;M1 Temporary Enable\r
+       b2m IOC,5               ;I/O Compatibility\r
+\r
+icr    equ     IOBASE+3Fh      ;I/O Control Register\r
+       b2m IOSTP,5             ;I/O Stop\r
+;\r
+; Interrupt Vectors\r
+;\r
+\r
+IV$INT1         equ    0               ;/INT1         (highest priority)\r
+IV$INT2         equ    2               ;/INT2\r
+IV$PRT0         equ    4               ;PRT channel 0\r
+IV$PRT1         equ    6               ;PRT channel 1\r
+IV$DMA0         equ    8               ;DMA channel 0\r
+IV$DMA1         equ    10              ;DMA channel 1\r
+IV$CSIO         equ    12              ;CSI/O\r
+IV$ASCI0 equ   14              ;ASCI channel 0\r
+IV$ASCI1 equ   16              ;ASCI channel 1 (lowest priority)\r
+\r
+       .list\r