From: Leo C Date: Sun, 27 May 2018 22:33:58 +0000 (+0200) Subject: Merge branch 'chan-fatfs' into fatfs-integration X-Git-Tag: hexrel-6.8.3~5 X-Git-Url: http://cloudbase.mooo.com/gitweb/z180-stamp.git/commitdiff_plain/0f3b947bda5f34662a611272b9f12199e0da9aca?hp=dbd0d34e68c73b9d3628cc1a1bda0b883976fc8b Merge branch 'chan-fatfs' into fatfs-integration # 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 --- diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/COPYING b/COPYING new file mode 100644 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. + + + Copyright (C) + + 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. + + , 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 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 ' should return success diff --git a/Tupfile.ini b/Tupfile.ini new file mode 100644 index 0000000..e69de29 diff --git a/Tuprules.tup b/Tuprules.tup new file mode 100644 index 0000000..185c6bf --- /dev/null +++ b/Tuprules.tup @@ -0,0 +1,3 @@ +.gitignore +TOP = $(TUP_CWD) + diff --git a/avr/Tupfile b/avr/Tupfile new file mode 100644 index 0000000..d41de25 --- /dev/null +++ b/avr/Tupfile @@ -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 index 0000000..9c8b5a6 --- /dev/null +++ b/avr/background.c @@ -0,0 +1,60 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..5154852 --- /dev/null +++ b/avr/bcd.c @@ -0,0 +1,21 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..922f9e1 --- /dev/null +++ b/avr/cli.c @@ -0,0 +1,428 @@ +/* + * (C) Copyright 2014-2016 Leo C. + * + * (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, + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include "cli.h" +#include "common.h" + +#include +#include +#include +#include + +#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("\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 index 0000000..2fdc56e --- /dev/null +++ b/avr/cli_readline.c @@ -0,0 +1,681 @@ +/* + * (C) Copyright 2014-2016 Leo C. + * + * (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, + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include "cli_readline.h" +#include "common.h" +#include +#include +#include +#include +#include + +#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 + */ + + +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 index 0000000..e9b5ccd --- /dev/null +++ b/avr/cmd_attach.c @@ -0,0 +1,160 @@ +/* + * (C) Copyright 2016 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +/* + * attach channels to devices + */ + +#include "common.h" +#include +#include + +#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 index 0000000..a83968f --- /dev/null +++ b/avr/cmd_boot.c @@ -0,0 +1,509 @@ +/* + * (C) Copyright 2014-2016 Leo C. + * + * (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 +#include + +#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 index 0000000..3e2e016 --- /dev/null +++ b/avr/cmd_date.c @@ -0,0 +1,180 @@ +/* + * (C) Copyright 2014 Leo C. + * + * (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 +#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, ¢ury) || + 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 index 0000000..fcf5cbc --- /dev/null +++ b/avr/cmd_fat.c @@ -0,0 +1,436 @@ +/* + * (C) Copyright 2014,2016 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +/* + * FAT filesystem commands + */ + +#include "common.h" +#include +#include + +#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 [bytes [pos]] + * write + */ +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 index 0000000..5cc02d0 --- /dev/null +++ b/avr/cmd_gpio.c @@ -0,0 +1,335 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "common.h" +#include +#include +#include + +#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 index 0000000..010339d --- /dev/null +++ b/avr/cmd_help.c @@ -0,0 +1,17 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..e6e2cdc --- /dev/null +++ b/avr/cmd_loadcpm3.c @@ -0,0 +1,195 @@ +/* + * (C) Copyright 2015,2016 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +/* + * See CP/M 3 System Manual, Appendix D: CPM3.SYS File Format + */ + +#include "common.h" +#include +#include +#include + +#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 index 0000000..18d5331 --- /dev/null +++ b/avr/cmd_loadihex.c @@ -0,0 +1,261 @@ +/* + * (C) Copyright 2015 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "common.h" +#include +#include +#include + +#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 index 0000000..315cd71 --- /dev/null +++ b/avr/cmd_mem.c @@ -0,0 +1,797 @@ +/* + * (C) Copyright 2014 Leo C. + * + * (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 +#include + +#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] : ""); + } + 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] == '-')) { + /* 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 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 index 0000000..9061b5a --- /dev/null +++ b/avr/cmd_misc.c @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2014,2016 Leo C. + * + * 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 + +#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 index 0000000..8593ef5 --- /dev/null +++ b/avr/cmd_run.c @@ -0,0 +1,92 @@ +/* + * (C) Copyright 2016 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include "common.h" +#include +#include + +#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 index 0000000..b84c4be --- /dev/null +++ b/avr/cmd_sd.c @@ -0,0 +1,404 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "common.h" +//#include + +#include "command.h" +#include "diskio.h" +#include "ff.h" +#include "eval_arg.h" +#include "print-utils.h" +#include "z80-if.h" + + +/* + * status - 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 - 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 - 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 [ [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 [] - 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 - 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 index 0000000..cd2ee39 --- /dev/null +++ b/avr/command.c @@ -0,0 +1,552 @@ +/* + * (C) Copyright 2014, 2016 Leo C. + * + * (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 +#include +#include +#include + +#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 index 0000000..ed14db9 --- /dev/null +++ b/avr/command_tbl.c @@ -0,0 +1,429 @@ +/* + * (C) Copyright 2014-2016 Leo C. + * + * 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] []\n" + " - print cofiguration and state or frequency of pins\n" + " print all pins, if argument is omitted\n" + "pin h[igh]|l[ow]\n" + " - config pins as output and set to level high or low\n" + "pin ts|i[n]|p[ullup]\n" + " - config pins as input/tristate or input with pullup\n" + "pin 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" + " 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", + " 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", + " [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", + " \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 diskfile\n" + " Attach diskfile to dsk, 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" + " Change options for dsk.\n" + " Options as above.\n" + "\n" + "attach -d -a|dsk\n" + "detach -a|dsk\n" + " Detach diskfile from dsk.\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" + " - alias for 'attach -d dsk'" +), + +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 index 0000000..4a96771 --- /dev/null +++ b/avr/con-utils.c @@ -0,0 +1,127 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "common.h" +#include +#include + +#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 index 0000000..1b4ecc2 --- /dev/null +++ b/avr/debug.c @@ -0,0 +1,255 @@ +/* + * (C) Copyright 2014,2016 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include "debug.h" +#include "common.h" +#include /* __malloc_margin */ +#include +#include +#include + +#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] == '-')) { + /* 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 index 0000000..952c88a --- /dev/null +++ b/avr/env.c @@ -0,0 +1,744 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include "common.h" +#include +#include +#include +#include + +#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 index 0000000..b931509 --- /dev/null +++ b/avr/eval_arg.c @@ -0,0 +1,157 @@ +/* + * (C) Copyright 2016 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include "eval_arg.h" +#include "common.h" +#include +#include +#include +#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 index 0000000..8508f40 --- /dev/null +++ b/avr/getopt-min.c @@ -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 + +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 index 0000000..73e9c39 --- /dev/null +++ b/avr/gpio.c @@ -0,0 +1,375 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "common.h" +#include +#include +#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 index 0000000..ae2f8da --- /dev/null +++ b/avr/i2c.c @@ -0,0 +1,378 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * I2C (TWI) master interface. + */ + +#include "common.h" +#include +#include + +#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< 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<>= 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< 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 index 0000000..86dcc50 --- /dev/null +++ b/avr/main.c @@ -0,0 +1,284 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + + +#include "common.h" +#include +#include +#include + +#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<= 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 : ""); + _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 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 +#include +#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 is the command sequense of CMD55-CMD */ + 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 index 0000000..bdb779f --- /dev/null +++ b/avr/pcf8583.c @@ -0,0 +1,105 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * Date & Time support for Philips PCF8583 RTC + */ + +#include "common.h" +#include +#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 index 0000000..83f86a9 --- /dev/null +++ b/avr/print-utils.c @@ -0,0 +1,98 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "common.h" +#include +#include +#include +#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 index 0000000..adbc3c4 --- /dev/null +++ b/avr/serial.c @@ -0,0 +1,124 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include + +#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 index 0000000..1b15985 --- /dev/null +++ b/avr/timer.c @@ -0,0 +1,61 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include "timer.h" +#include +#include +#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 index 0000000..d42d5c9 --- /dev/null +++ b/avr/xmalloc.c @@ -0,0 +1,32 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#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 index 0000000..d1f52dd --- /dev/null +++ b/avr/z180-serv.c @@ -0,0 +1,828 @@ +/* + * (C) Copyright 2014-2016 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include "z180-serv.h" +#include "common.h" +#include +#include +#include +#include + +#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 index 0000000..e36b369 --- /dev/null +++ b/avr/z80-if.c @@ -0,0 +1,699 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 +#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<> 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 index 0000000..e69de29 diff --git a/configs/gcc.tup b/configs/gcc.tup new file mode 100644 index 0000000..ad2d788 --- /dev/null +++ b/configs/gcc.tup @@ -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 index 0000000..db4eb98 --- /dev/null +++ b/configs/m1281-debug.config @@ -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 index 0000000..2366681 --- /dev/null +++ b/configs/m2561-debug.config @@ -0,0 +1,2 @@ +CONFIG_DEBUG=0 +CONFIG_MCU=atmega2561 diff --git a/fatfs/source/diskio.h b/fatfs/source/diskio.h.dist similarity index 100% rename from fatfs/source/diskio.h rename to fatfs/source/diskio.h.dist diff --git a/fatfs/source/ffconf.h b/fatfs/source/ffconf.h.dist similarity index 100% rename from fatfs/source/ffconf.h rename to fatfs/source/ffconf.h.dist diff --git a/include/avr/ffconf.h b/include/avr/ffconf.h new file mode 100644 index 0000000..51a3c23 --- /dev/null +++ b/include/avr/ffconf.h @@ -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 // O/S definitions */ + + + +/*--- End of configuration options ---*/ diff --git a/include/background.h b/include/background.h new file mode 100644 index 0000000..87e95e5 --- /dev/null +++ b/include/background.h @@ -0,0 +1,17 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..efbebcc --- /dev/null +++ b/include/bcd.h @@ -0,0 +1,13 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..28e92be --- /dev/null +++ b/include/cli.h @@ -0,0 +1,81 @@ +/* + * (C) Copyright 2014-2016 Leo C. + * + * (C) Copyright 2014 Google, Inc + * Simon Glass + * + * 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 index 0000000..f326106 --- /dev/null +++ b/include/cli_readline.h @@ -0,0 +1,34 @@ +/* + * (C) Copyright 2014-2016 Leo C. + * + * (C) Copyright 2014 Google, Inc + * Simon Glass + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef CLI_READLINE_H +#define CLI_READLINE_H + +#include "common.h" +#include + +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 index 0000000..782c10a --- /dev/null +++ b/include/cmd_mem.h @@ -0,0 +1,30 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..9ca460d --- /dev/null +++ b/include/command.h @@ -0,0 +1,167 @@ +/* + * (C) Copyright 2014-2016 Leo C. + * + * (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 + +#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 index 0000000..e22b7a1 --- /dev/null +++ b/include/common.h @@ -0,0 +1,94 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef COMMON_H +#define COMMON_H + +#include +#include + +#define GCC_VERSION (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) + +#ifdef __AVR__ +#include +#include +#include + +#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 index 0000000..86c0df0 --- /dev/null +++ b/include/con-utils.h @@ -0,0 +1,30 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..8d7f348 --- /dev/null +++ b/include/config.h @@ -0,0 +1,79 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..89cde1f --- /dev/null +++ b/include/crc.h @@ -0,0 +1,21 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef CRC_H +#define CRC_H + +#ifdef __AVR__ +#include +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 index 0000000..0ee0129 --- /dev/null +++ b/include/debug.h @@ -0,0 +1,50 @@ +/* + * (C) Copyright 2014 Leo C. + * + * (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 index 0000000..fee87a5 --- /dev/null +++ b/include/diskio.h @@ -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 index 0000000..bc44413 --- /dev/null +++ b/include/env.h @@ -0,0 +1,24 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef ENV_H +#define ENV_H + +#include + +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 index 0000000..a86b0d5 --- /dev/null +++ b/include/eval_arg.h @@ -0,0 +1,19 @@ +/* + * (C) Copyright 2016 Leo C. + * + * 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 index 0000000..7fb6cb1 --- /dev/null +++ b/include/ff.h @@ -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 index 0000000..9841d5b --- /dev/null +++ b/include/ffconf.h @@ -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 index 0000000..e42aa78 --- /dev/null +++ b/include/getopt-min.h @@ -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 index 0000000..1e0346d --- /dev/null +++ b/include/gpio.h @@ -0,0 +1,22 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..f39fa1d --- /dev/null +++ b/include/i2c.h @@ -0,0 +1,65 @@ +/* + * (C) Copyright 2014 Leo C. + * + * Copyright (C) 2009 Sergey Kubushyn + * Copyright (C) 2009 - 2013 Heiko Schocher + * 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 index 0000000..4660ed6 --- /dev/null +++ b/include/integer.h @@ -0,0 +1,38 @@ +/*-------------------------------------------*/ +/* Integer type definitions for FatFs module */ +/*-------------------------------------------*/ + +#ifndef _FF_INTEGER +#define _FF_INTEGER + +#ifdef _WIN32 /* FatFs development platform */ + +#include +#include +typedef unsigned __int64 QWORD; + + +#else /* Embedded platform */ + +/* These types MUST be 16-bit or 32-bit */ +typedef int INT; +typedef unsigned int UINT; + +/* This type MUST be 8-bit */ +typedef unsigned char BYTE; + +/* These types MUST be 16-bit */ +typedef short SHORT; +typedef unsigned short WORD; +typedef unsigned short WCHAR; + +/* These types MUST be 32-bit */ +typedef long LONG; +typedef unsigned long DWORD; + +/* This type MUST be 64-bit (Remove this for C89 compatibility) */ +typedef unsigned long long QWORD; + +#endif + +#endif diff --git a/include/print-utils.h b/include/print-utils.h new file mode 100644 index 0000000..ffff039 --- /dev/null +++ b/include/print-utils.h @@ -0,0 +1,24 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef PRINT_UTILS_H +#define PRINT_UTILS_H + +#include "common.h" +#include + +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 index 0000000..b64f462 --- /dev/null +++ b/include/ring.h @@ -0,0 +1,79 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..ca4c068 --- /dev/null +++ b/include/rtc.h @@ -0,0 +1,13 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..54c7211 --- /dev/null +++ b/include/serial.h @@ -0,0 +1,15 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..4638476 --- /dev/null +++ b/include/spi.h @@ -0,0 +1,54 @@ +/* + * (C) Copyright 2009,2014 Leo C. + * + * 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< + * + * 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 index 0000000..cb0019f --- /dev/null +++ b/include/xmalloc.h @@ -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 index 0000000..3b4a462 --- /dev/null +++ b/include/z180-serv.h @@ -0,0 +1,58 @@ +/* + * (C) Copyright 2014 Leo C. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef Z180_SERV_H +#define Z180_SERV_H + +#include +#include +#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 index 0000000..ef87e5a --- /dev/null +++ b/include/z80-if.h @@ -0,0 +1,56 @@ +/* + * (C) Copyright 2014 Leo C. + * + * 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 index 0000000..26bfc62 --- /dev/null +++ b/time/Files.am @@ -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 index 0000000..ea8d363 --- /dev/null +++ b/time/Makefile @@ -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 index 0000000..c8a121f --- /dev/null +++ b/time/Makefile.am @@ -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 index 0000000..868aa89 --- /dev/null +++ b/time/Makefile.in @@ -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 index 0000000..a2c0929 --- /dev/null +++ b/time/Rules.am @@ -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 index 0000000..1839ec6 --- /dev/null +++ b/time/asc_store.c @@ -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 + +char __store[26]; + +char *__asc_store = __store; diff --git a/time/asctime.c b/time/asctime.c new file mode 100644 index 0000000..38c6ea9 --- /dev/null +++ b/time/asctime.c @@ -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 + +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 index 0000000..f85336d --- /dev/null +++ b/time/asctime_r.c @@ -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 +#include + +#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 index 0000000..f17b873 --- /dev/null +++ b/time/ctime.c @@ -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 + +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 index 0000000..4bb3633 --- /dev/null +++ b/time/ctime_r.c @@ -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 + +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 index 0000000..97df585 --- /dev/null +++ b/time/daylight_seconds.c @@ -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 +#include + +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 index 0000000..95b24e9 --- /dev/null +++ b/time/difftime.c @@ -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 + +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 index 0000000..5eda185 --- /dev/null +++ b/time/dst_pointer.c @@ -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 +#include + +int (*__dst_ptr) (const time_t *, int32_t *); diff --git a/time/ephemera_common.h b/time/ephemera_common.h new file mode 100644 index 0000000..9583f89 --- /dev/null +++ b/time/ephemera_common.h @@ -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 index 0000000..a527c83 --- /dev/null +++ b/time/equation_of_time.c @@ -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 +#include +#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 index 0000000..e38decb --- /dev/null +++ b/time/fatfs_time.c @@ -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 + +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 index 0000000..84bd7a8 --- /dev/null +++ b/time/geo_location.c @@ -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 index 0000000..b0984aa --- /dev/null +++ b/time/gm_sidereal.c @@ -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 +#include + +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 index 0000000..f3d0b2e --- /dev/null +++ b/time/gmtime.c @@ -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 + +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 index 0000000..22658ea --- /dev/null +++ b/time/gmtime_r.c @@ -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 +#include +#include + +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 index 0000000..3c846aa --- /dev/null +++ b/time/isLeap.c @@ -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 + +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 index 0000000..efbf841 --- /dev/null +++ b/time/iso_week_date.c @@ -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 + +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 index 0000000..ac1feb4 --- /dev/null +++ b/time/iso_week_date_r.c @@ -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 + +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 index 0000000..a257815 --- /dev/null +++ b/time/isotime.c @@ -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 + +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 index 0000000..5636a7f --- /dev/null +++ b/time/isotime_r.c @@ -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 +#include + +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 index 0000000..ad34fac --- /dev/null +++ b/time/lm_sidereal.c @@ -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 + +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 index 0000000..0e18967 --- /dev/null +++ b/time/localtime.c @@ -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 + +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 index 0000000..0bd1a02 --- /dev/null +++ b/time/localtime_r.c @@ -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 + +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(<, timeptr); + timeptr->tm_isdst = dst; +} diff --git a/time/mk_gmtime.c b/time/mk_gmtime.c new file mode 100644 index 0000000..7f2b9b9 --- /dev/null +++ b/time/mk_gmtime.c @@ -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_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 index 0000000..1600202 --- /dev/null +++ b/time/mktime.c @@ -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 + +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 index 0000000..0f2f091 --- /dev/null +++ b/time/month_length.c @@ -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 + +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 index 0000000..5fb5826 --- /dev/null +++ b/time/moon_phase.c @@ -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 +#include + +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 index 0000000..95c81bd --- /dev/null +++ b/time/print_lz.c @@ -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 + +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 index 0000000..9ba0964 --- /dev/null +++ b/time/set_dst.c @@ -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 +#include + +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 index 0000000..e268316 --- /dev/null +++ b/time/set_position.c @@ -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 index 0000000..334790e --- /dev/null +++ b/time/set_system_time.c @@ -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 +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 index 0000000..eb0f11b --- /dev/null +++ b/time/set_zone.c @@ -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 index 0000000..dd89028 --- /dev/null +++ b/time/solar_declination.c @@ -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 +#include +#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 index 0000000..65bafcc --- /dev/null +++ b/time/solar_noon.c @@ -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 + +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 index 0000000..4dcfd30 --- /dev/null +++ b/time/strftime.c @@ -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 +#include +#include + +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 index 0000000..b2ff62c --- /dev/null +++ b/time/sun_rise.c @@ -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_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 index 0000000..338e35f --- /dev/null +++ b/time/sun_set.c @@ -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_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 index 0000000..c1f90fd --- /dev/null +++ b/time/system_tick.S @@ -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 + + .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 index 0000000..64bdac7 --- /dev/null +++ b/time/system_time.c @@ -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 + +volatile time_t __system_time; diff --git a/time/time.c b/time/time.c new file mode 100644 index 0000000..e794322 --- /dev/null +++ b/time/time.c @@ -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 +#include + +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 index 0000000..21d86e9 --- /dev/null +++ b/time/time.h @@ -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 + \code #include \endcode +

Introduction to the Time functions

+ 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 +#include + + /** \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 \endcode + for the European Union, and + \code #include \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 index 0000000..af8229b --- /dev/null +++ b/time/tm_store.c @@ -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 + +struct tm __tm_store; diff --git a/time/utc_offset.c b/time/utc_offset.c new file mode 100644 index 0000000..14c8180 --- /dev/null +++ b/time/utc_offset.c @@ -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 index 0000000..6eca94f --- /dev/null +++ b/time/week_of_month.c @@ -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 + +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 index 0000000..ad06f62 --- /dev/null +++ b/time/week_of_year.c @@ -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 + +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 index 0000000..159371f --- /dev/null +++ b/z180/Makefile @@ -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 index 0000000..c7d79fb --- /dev/null +++ b/z180/Tupfile @@ -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 index 0000000..956faf1 --- /dev/null +++ b/z180/asci-p.180 @@ -0,0 +1,133 @@ + page 200 + + extrn ioiniml + + global as0init + global as0ista,as0inp + global as0osta,as0out + global as1init + global as1ista,as1inp + global as1osta,as1out + + include config.inc + include z180reg.inc + + +;----------------------------------------------------- +; +; +; TC = (f PHI /(2*baudrate*Clock_mode)) - 2 +; +; TC = (f PHI / (32 * baudrate)) - 2 +; + + cseg +; +; Init Serial I/O for console input and output (ASCI1) +; + + + +as0init: + ld hl,initab0 + jp ioiniml + +as1init: + ld hl,initab1 + jp ioiniml + + + ld a,M_MPBT + out0 (cntlb1),a + ld a,M_RE + M_TE + M_MOD2 ;Rx/Tx enable + out0 (cntla1),a + ld a,M_RIE + out0 (stat1),a ;Enable rx interrupts + + ret ; + + +initab0: + db 1,stat0,0 ;Disable rx/tx interrupts + ;Enable baud rate generator + db 1,asext0,M_BRGMOD+M_DCD0DIS+M_CTS0DIS + db 2,astc0l,low 28, high 28 + db 1,cntlb0,M_MPBT ;No MP Mode, X16 + db 1,cntla0,M_RE+M_TE+M_MOD2 ;Rx/Tx enable, 8N1 + db 0 + +initab1: + db 1,stat1,0 ;Disable rx/tx ints, disable CTS1 + db 1,asext1,M_BRGMOD ;Enable baud rate generator + db 2,astc1l,low 3, high 3 + db 1,cntlb1,M_MPBT ;No MP Mode, X16 + db 1,cntla1,M_RE+M_TE+M_MOD2 ;Rx/Tx enable, 8N1 + db 0 + + + +as0ista: + in0 a,(stat0) + and M_RDRF + ret z + or 0ffh + ret + +as1ista: + in0 a,(stat1) + and M_RDRF + ret z + or 0ffh + ret + + +as0inp: + in0 a,(stat0) + rlca + jr nc,as0inp + in0 a,rdr0 + ret + +as1inp: + in0 a,(stat1) + rlca + jr nc,as1inp + in0 a,rdr1 + ret + + + +as0osta: + in0 a,(stat0) + and M_TDRE + ret z + or 0ffh + ret + +as1osta: + in0 a,(stat1) + and M_TDRE + ret z + or 0ffh + ret + + +as0out: + in0 a,(stat0) + and M_TDRE + jr z,as0out + out0 (tdr0),c + ld a,c + ret + +as1out: + in0 a,(stat1) + and M_TDRE + jr z,as1out + out0 (tdr1),c + ld a,c + ret + + end + + diff --git a/z180/asci1-i.180 b/z180/asci1-i.180 new file mode 100644 index 0000000..15e121a --- /dev/null +++ b/z180/asci1-i.180 @@ -0,0 +1,256 @@ + page 200 + + + extrn buf.init + extrn isv_sw + + + global ser.init + global ser.ist,ser.in + global ser.ost,ser.out + +;TODO: define a trampoline area somewhere in top ram. +rtxisvjmp equ 0FF60h ;momentan frei... + + include config.inc + include z180reg.inc + + +;----------------------------------------------------- + + dseg + +buf_start: + mkbuf s1.rx_id, ser1.inbuf, s1.rx_len + mkbuf s1.tx_id, ser1.outbuf, s1.tx_len +buf_end: + + + +;----------------------------------------------------- + + cseg +; +; Init Serial I/O for console input and output (ASCI1) +; + + +ser.init: +; ld a,i +; push af ;save IFF +; di + + xor a ; + out0 (stat1),a ;Disable rx/tx interrupts + + ld hl,rxtx_src ;move rx and tx isv to common ram + ld de,rxtx_dst ; + ld bc,rxtx_src_e-rxtx_src ; + ldir ; + + ld hl,rtxisvjmp ;rx/tx int vector + ld (ivtab + IV$ASCI1),hl; + ld a,0cdh ; + ld (rtxisvjmp),a ; + ld hl,isv_sw ; + ld (rtxisvjmp + 1),hl ; + ld hl,rxtxisv ; + ld (rtxisvjmp + 3),hl ; + +; ASCI1: 8N1, highest baudrate (56700), CTS disabled + + ld a,M_MPBT + out0 (cntlb1),a + ld a,M_RE + M_TE + M_MOD2 + out0 (cntla1),a + ld a,M_RIE + out0 (stat1),a ;Enable rx interrupts + + ld ix,ser1.inbuf + ld a,ser1.inbuf.mask + call buf.init + ld ix,ser1.outbuf + ld a,ser1.outbuf.mask + call buf.init + +; pop af +; ret po +; ei + ret ; + +ser.ist: + push ix + ld ix,ser1.inbuf ; + +buf.empty: + ld a,(ix+o.in_idx) ; + sub (ix+o.out_idx) ; + pop ix + ret z + or 0ffh + ret + +ser.in: + push hl ;11 + push de ;11 + ld hl,ser1.inbuf-1 ; 9 hl = &rx.out_idx + ld a,(hl) ; 6 a = rx.out_idx + dec hl ; 4 hl = &rx.in_idx + jr bg.w1 +bg.wait: + halt +bg.w1: + cp (hl) ; 6 while (out_idx==in_idx) + jr z,bg.wait ; 6 (/8) ; + + ld e,a ; 4 + ld d,0 ; 6 + inc de + inc de + + ex de,hl ; 3 + add hl,de ;10 + ld l,(hl) ; 6 + ex de,hl ; 3 + + inc a ; 4 + dec hl ; 4 + and (hl) ; 6 + inc hl ; 4 + inc hl ; 4 + ld (hl),a ; 7 + + ld a,e ; 4 + pop de ; 9 + pop hl ; 9 + ret ; 9 + ; 153 + +ser.ost: + push ix + ld ix,ser1.outbuf ; +buf.full: + ld a,(ix+o.in_idx) ; + inc a + and (ix+o.mask) + sub (ix+o.out_idx) ; + pop ix + ret z + or 0ffh + ret + + +ser.out: + push ix + ld ix,ser1.outbuf ; +buf.put: + push hl ; + push bc + push ix + pop hl + ld a,c + ld c,(ix+o.in_idx) ; + ld b,0 + add hl,bc + ld (hl),a + + ld a,c ; + inc a + and (ix+o.mask) +bp.wait: + cp (ix+o.out_idx) ; + jr z,bp.wait + ld (ix+o.in_idx),a + + di ;036f + in0 a,(stat1) ;0374 + set TIE,a ;0377 + out0 (stat1),a ;0379 + ei ;037c + + ld a,b + pop bc + pop hl + pop ix + ret + + +;------------------------------------------ +; ASCI 1 Transmit/Receive interupt routines +; moved to common ram + +rxtx_src: + dseg +rxtx_dst: ; (0c097h) old + +rxtxisv: + inidat + in0 a,(stat1) ;receive flag set? + jp p,txisv ; + + in0 d,(rdr1) ;todo: break detection + bit FE,a ;framing error? + jr nz,??ri_1 + + push ix + ld ix,ser1.inbuf ; + ld hl,ser1.inbuf ; + ld c,(ix+o.in_idx) ; + ld b,0 + add hl,bc + + ld a,c ; + inc a + and (ix+o.mask) + cp (ix+o.out_idx) ; + jr z,??ri_0 + ld (hl),d + ld (ix+o.in_idx),a +??ri_0: + pop ix +??ri_1: + in0 a,(cntla1) ;0705 c0c0 + res EFR,a ;0708 + out0 (cntla1),a ;070a + ret + + inidate + +txisv: + inidat + push ix + ld ix,ser1.outbuf ; + + ld a,(ix+o.out_idx) ; + cp (ix+o.in_idx) ; + jr z,??ti_2 + + ld hl,ser1.outbuf ; + add a,l + ld l,a + jr nc,??ti_1 + inc h +??ti_1: + ld l,(hl) + out0 (tdr1),l ;071b + + ld a,(ix+o.out_idx) ; + inc a + and (ix+o.mask) + ld (ix+o.out_idx),a + jr ??ti_3 +??ti_2: + in0 a,(stat1) ;0730 disable tx-int + res TIE,a ;0733 + out0 (stat1),a ;0735 +??ti_3: + pop ix + ret + + inidate + + cseg +rxtx_src_e: + + + end diff --git a/z180/bioscio.180 b/z180/bioscio.180 new file mode 100644 index 0000000..2d8e5e0 --- /dev/null +++ b/z180/bioscio.180 @@ -0,0 +1,326 @@ + + .z80 + +; Copyright (C), 1982 +; Digital Research, Inc +; P.O. Box 579 +; Pacific Grove, CA 93950 + +; This is the invariant portion of the modular BIOS and is +; distributed as source for informational purposes only. +; All desired modifications should be performed by +; adding or changing externally defined modules. +; This allows producing "standard" I/O modules that +; can be combined to support a particular system +; configuration. +; +; Modified for faster character I/O by Udo Munk + +cr equ 13 +lf equ 10 +bell equ 7 +ctlQ equ 'Q'-'@' +ctlS equ 'S'-'@' + + cseg ; GENCPM puts CSEG stuff in common memory + + ; variables in system data page + +;; extrn @covec,@civec,@aovec,@aivec,@lovec ; I/O redirection vectors + + ; user defined character I/O routines + + extrn ?ci,?co,?cist,?cost ; each take device in + extrn ?cinit ; (re)initialize device in + extrn @ctbl ; physical character device table + + + include modebaud.inc ; define mode bits + + + public @covec,@civec,@aovec,@aivec,@lovec ; I/O redirection vectors + public ?const,?conin,?cono,?list,?auxo,?auxi + public ?lists,?conos,?auxis,?auxos,?dvtbl,charini + + +@CIVEC: dw 0 ; Console Input Redirection + ; Vector (word, r/w) +@COVEC: dw 0 ; Console Output Redirection + ; Vector (word, r/w) +@AIVEC: dw 0 ; Auxiliary Input Redirection + ; Vector (word, r/w) +@AOVEC: dw 0 ; Auxiliary Output Redirection + ; Vector (word, r/w) +@LOVEC: dw 0 ; List Output Redirection + ; Vector (word, r/w) + + +charini: + + ld c,15 ; initialize all 16 character devices +c$init$loop: + push bc + call ?cinit + pop bc + dec c + jp p,c$init$loop + +; ld hl,1000000000000000b ; assign console to HOST + ld hl,0010000000000000b ; assign console to ASCI1 + ld (@civec),hl + ld (@covec),hl + ld hl,0000000000000000b ; assign auxiliary to nothing + ld (@aivec),hl + ld (@aovec),hl + ld hl,0000000000000000b ; assign printer to nothing + ld (@lovec),hl + ret + + + ; DEVTBL + ; Return address of character device table + +?dvtbl: +devtbl: + ld hl,@ctbl + ret + + + ; CONOUT + ; Console Output. Send character in + ; to all selected devices + +?cono: +conout: + ld hl,(@covec) ; fetch console output bit vector + jr out$scan + + + ; AUXOUT + ; Auxiliary Output. Send character in + ; to all selected devices + +?auxo: +auxout: + ld hl,(@aovec) ; fetch aux output bit vector + jr out$scan + + + ; LIST + ; List Output. Send character in + ; to all selected devices. + +?list: +list: + ld hl,(@lovec) ; fetch list output bit vector + +out$scan: + ld b,0 ; start with device 0 +co$next: + add hl,hl ; shift out next bit + jr nc,not$out$device + push hl ; save the vector + push bc ; save the count and character + call ?co ; if device selected, print it + pop bc ; recover count and character + pop hl ; recover the rest of the vector +not$out$device: + inc b ; next device number + ld a,h + or l ; see if any devices left + jr nz,co$next ; and go find them... + ret + + + ; CONOST + ; Console Output Status. Return true if + ; all selected console output devices + ; are ready. + +?conos: +conost: + ld hl,(@covec) ; get console output bit vector + jr ost$scan + + + ; AUXOST + ; Auxiliary Output Status. Return true if + ; all selected auxiliary output devices + ; are ready. + +?auxos: +auxost: + ld hl,(@aovec) ; get aux output bit vector + jr ost$scan + + + ; LISTST + ; List Output Status. Return true if + ; all selected list output devices + ; are ready. + +?lists: +listst: + ld hl,(@lovec) ; get list output bit vector + +ost$scan: + ld b,0 ; start with device 0 +cos$next: + add hl,hl ; check next bit + push hl ; save the vector + push bc ; save the count + ld a,0FFh ; assume device ready + call c,coster ; check status for this device + pop bc ; recover count + pop hl ; recover bit vector + or a ; see if device ready + ret z ; if any not ready, return false + inc b ; drop device number + ld a,h + or l ; see if any more selected devices + jr nz,cos$next + or 0FFh ; all selected were ready, return true + ret + +coster: ; check for output device ready, including optional + ; xon/xoff support + ; + ;TODO: interrupt driven devices should xon/xoff handle + ; in isv + + ld l,b + ld h,0 ; make device code 16 bits + push hl ; save it in stack + add hl,hl + add hl,hl + add hl,hl ; create offset into device characteristics tbl + ld de,@ctbl+6 + add hl,de ; make address of mode byte + ld a,(hl) + and mb$xon$xoff + pop hl ; recover console number in + jp z,?cost ; not a xon device, go get output status direct + ld de,xofflist + add hl,de ; make pointer to proper xon/xoff flag + call cist1 ; see if this keyboard has character + ld a,(hl) + call nz,ci1 ; get flag or read key if any + cp ctlq + jr nz,not$q ; if its a ctl-Q, + ld a,0FFh ; set the flag ready +not$q: + cp ctls + jr nz,not$s ; if its a ctl-S, + ld a,00h ; clear the flag +not$s: + ld (hl),a ; save the flag + call cost1 ; get the actual output status, + and (hl) ; and mask with ctl-Q/ctl-S flag + ret ; return this as the status + +cist1: ; get input status with and saved + push bc + push hl + call ?cist + pop hl + pop bc + or a + ret + +cost1: ; get output status, saving & + push bc + push hl + call ?cost + pop hl + pop bc + or a + ret + +ci1: ; get input, saving & + push bc + push hl + call ?ci + pop hl + pop bc + ret + + + ; AUXIST + ; Auxiliary Input Status. Return true if + ; any selected auxiliary input device + ; has an available character. +?auxis: +auxist: + ld hl,(@aivec) ; get aux input bit vector + jr ist$scan + + + ; CONST + ; Console Input Status. Return true if + ; any selected console input device + ; has an available character. +?const: +const: + ld hl,(@civec) ; get console input bit vector + + +ist$scan: + ld b,0 ; start with device 0 +cis$next: + add hl,hl ; check next bit + ld a,0 ; assume device not ready + call c,cist1 ; check status for this device + or a + ret nz ; if any ready, return true + inc b ; next device number + ld a,h + or l ; see if any more selected devices + jr nz,cis$next + xor a ; all selected were not ready, return false + ret + + + ; AUXIN + ; Auxiliary Input. Return character from first + ; ready auxiliary input device. +?auxi: +auxin: + ld hl,(@aivec) + jr in$scan + + + ; CONIN + ; Console Input. Return character from first + ; ready console input device. +?conin: +conin: + ld hl,(@civec) + +in$scan: + push hl ; save bit vector + ld b,0 +ci$next: + add hl,hl ; shift out next bit + ld a,0 ; insure zero a (nonexistant device not ready). + call c,cist1 ; see if the device has a character + or a + jr nz,ci$rdy ; this device has a character + inc b ; else, next device + ld a,h + or l ; see if any more devices + jr nz,ci$next ; go look at them + pop hl ; recover bit vector + jr in$scan ; loop til we find a character +ci$rdy: + pop hl ; discard extra stack + jp ?ci + + + +xofflist: + db -1,-1,-1,-1,-1,-1,-1,-1 ; ctl-s clears to zero + db -1,-1,-1,-1,-1,-1,-1,-1 + + + end + diff --git a/z180/cfboot.180 b/z180/cfboot.180 new file mode 100644 index 0000000..083aa4c --- /dev/null +++ b/z180/cfboot.180 @@ -0,0 +1,352 @@ + TITLE 'CF cold boot loader' + + ; Port Address Equates + + include config.inc + include z180reg.inc + + ; IDE Task File Register Definitions + +IDEDat equ IDEBASE+0 ; Data Register +IDEErr equ IDEBASE+1 ; Error Register +IDEFeat equ IDEBASE+1 ; Feature Register +IDESCnt equ IDEBASE+2 ; Sector Count +IDESNum equ IDEBASE+3 ; Sector Number +IDECLo equ IDEBASE+4 ; Cylinder Low +IDECHi equ IDEBASE+5 ; Cylinder High +IDESDH equ IDEBASE+6 ; Drive and Head +IDECmd equ IDEBASE+7 ; Command / Status + + ; IDE Hard disk commands: + +CmdNOP equ 00h ; NOP Command +CmdHome equ 10h ; Recalibrate +CmdRd equ 20h ; Read Sector +CmdWr equ 30h ; Write Sector +CmdId equ 0ECh ; Read ID +CmdSF equ 0EFh ; Set Feature + + ; Partition Table Structures + +PTYPE equ 4 +PSTART equ 8 +PSIZE equ 12 + + ; Partition table id + ; (see http://www.win.tue.nl/~aeb/partitions/partition_types-1.html) + +PARTID1_FAT16 equ 00EH +PARTID2_FAT16 equ 006H +PARTID_CPM equ 052H + + +DEBUG equ false ; not used +DO_WAIT_NBSY equ false +RUN_TPA equ false + + if RUN_TPA +base equ 0100h + else +base equ 0 + endif + +;------------------------------------------------------------------------------- + + aseg + + org base + + jr start + +para: equ $ +loadaddr: dw base+100h +sec_start: db 0 +sec_cnt: db 7 +part_id: db PARTID_CPM +timeout: dw 10000 +stages: db number_of_stages +done: db 0 +result: db 0 +ide_result: db 0,0 + +o_part_id equ part_id - para +o_stages equ stages - para +o_done equ done - para +o_result equ result - para + +;------------------------------------------------------------------------------- + +start: + ld sp,stack + pop ix + pop de +loop: + dec (ix+o_stages) + jp m,stop + + pop hl + push de + push hl + exx + ld hl,(loadaddr) + ret +continue: + exx + ld (ix+o_result),a + or a + jr z,loop +stop: + in a,(Idecmd) ;2 + ld l,a ;1 + in a,(IdeErr) ;2 + ld h,a ;1 + ld (ide_result),hl ;3 9 + dec (ix+o_done) + halt + +;------------------------------------------------------------------------------- + +chk_to: + xor a ; +to_l: + dec a + ex (sp),hl + ex (sp),hl + jr nz,to_l ; + dec hl ; 4 + ld a,h ; 4 + or l ; 4 + ret nz ; 10/5 + ccf ; 3 + ret ; 9 + + if base = 0 + if 044h-$ > 0 + rept 044h-$ + db 0 + endm + endif + endif + +part_start: +; dw 0 +; dw 0 ; part_start is 4 byte long, but stack gets free +stack: + dw para + dw continue +stage_table: + if DO_WAIT_NBSY + dw s_wait_not_bsy + endif + dw s_wait_rdy + dw s_check_io + dw s_set_xfermode8 + dw s_read_parttbl + dw s_check_signature + dw s_find_partition + dw s_read_sectors + dw s_go +number_of_stages equ ($-stage_table)/2 + + if DO_WAIT_NBSY +;------------------------------------------------------------------------------- +; Wait while device is busy with time out +; return: +; a = 0 if ok +; a = ff in timeout +; destroys hl + +s_wait_not_bsy: + ld hl,(timeout) +wnb_l: + in a,(IdeCmd) + rla + jr nc,wnb_e + call chk_to + jr nc,wnb_l +wnb_e: + sbc a,a + ret + endif + +;------------------------------------------------------------------------------- +; Wait for ready signal with time out +; return: +; a = 0 if ok +; a = ff in timeout +; destroys hl + +s_wait_rdy: +wait_rdy_to: + ld hl,(timeout) +wrdy_l: + in a,(IdeCmd) + xor 01000000b + and 11000000b ; clears carry + jr z,wrdy_e + call chk_to + jr nc,wrdy_l +wrdy_e: + sbc a,a + ret + +;------------------------------------------------------------------------------- + +s_check_io: + ld a,0E0h ; unit 0, lba mode + out (IdeSDH),a ; + + xor a ; execute NOP command + call do_ide_cmd ; should return error + ret c + xor 1 + ret nz + ld a,CmdHome ; execute RECALIBRATE command + jr do_ide_cmd + +;------------------------------------------------------------------------------- + +s_set_xfermode8: + ld a,1 ; Enable 8-bit data transfer. + out (IDEFeat),a + ld a,CmdSF ; Set feature command + +; fall thru +; jr do_ide_cmd + +;------------------------------------------------------------------------------- + +do_ide_cmd: + out (IdeCmd),a ; + call wait_rdy_to + ret c + in a,(IdeCmd) + and 10001001b ; + ret + +;------------------------------------------------------------------------------- + +s_check_signature: +; ld hl,(loadaddr) + inc h ; Point to last byte of MBR + inc h + dec hl + ld a,0aah + cp (hl) ; Test, if it has a valid MBR + ret nz + dec hl + cpl ; a=055h + sub (hl) ; + ret ; should be 0 + +;------------------------------------------------------------------------------- +; Read partition table (lbr) + +s_read_parttbl: +; ld hl,(loadaddr) + ld bc,1*256 + 0 ; sector 0 (lba) + ld e,c + ld d,c + jr read_sectors + +;------------------------------------------------------------------------------- +; Find CP/M paartition +; Look for first CP/M partition +; and save partition offset + +s_find_partition: +; ld hl,(loadaddr) + ld de,512-2-64+PTYPE ; Point to partition type of first first partition table entry + add hl,de + ld de,16 + ld b,4 ; Max # of partition table entries +ploop: + ld a,(ix+o_part_id) + sub (HL) ; Test for CP/M Partition + jr nz,pnext + ld bc,4 + add hl,bc ; Point to partition start (lba) + ld de,part_start + ldir + ret ;a=0 +pnext: + add hl,de + djnz ploop + ret + + +;------------------------------------------------------------------------------- +; Read sec_count sectors, beginning at part_start+sec_start + +s_read_sectors: +; ld hl,(loadaddr) + push hl + ld bc,(sec_start) ;b=sec_count, c=sec_start + ld e,c + ld d,0 + ld hl,(part_start) ;add partition offset to sector number + add hl,de + ld a,(part_start+2) + adc a,d ;d=0 + ld c,a + ex de,hl + pop hl + +; fall thru + +;------------------------------------------------------------------------------- +; Read a number of sectors +; hl: memory address +; cde: sector number (24 bit) +; b: sector count + +read_sectors: + ld a,e ; lba 0..7 + out (IdeSNum),a + ld a,d ; lba 0..7 + out (IdeClo),a + ld a,c ; lba 0..7 + out (IdeCHi),a + ld a,b ; number of sectors to read + out (IdeSCnt),a ; set sector count + + ld a,CmdRd + out (IdeCmd),a ; command: read sector data + ld d,b + ld bc,IdeDat ; I/O address +wdrq: + in a,(IdeCmd) ; wait for DRQ to become active + bit 3,a + jr z,wdrq + inir ; read 512 data bytes (2 x 256) + inir +wnb: ; wait while busy + in a,(IdeCmd) ; + rlca + jr c,wnb + rrca ; restore status + bit 0,a + jr nz,err_out + dec d + jr nz,wdrq +err_out: + and 10001001b ; Busy, DRQ, or Error? + ret ; return 0, if everything is ok + +;------------------------------------------------------------------------------- + +s_go: +; ld hl,(loadaddr) + dec (ix+o_done) + jp (hl) + + +;------------------------------------------------------------------------------- + if base = 0 + if $ > 100h + .printx Error: Program to large to fit in page 0! + db "Stop + endif + endif + + end diff --git a/z180/chario.180 b/z180/chario.180 new file mode 100644 index 0000000..4d37b89 --- /dev/null +++ b/z180/chario.180 @@ -0,0 +1,113 @@ + page 255 + .z80 + + +; CP/M 3 compatible character i/o + + public ?cinit,?ci,?co,?cist,?cost + public @ctbl + + extrn ff.init,ff.i.st,ff.in,ff.o.st,ff.out + extrn as0init,as0ista,as0inp,as0osta,as0out + extrn as1init,as1ista,as1inp,as1osta,as1out + + include config.inc + include z180reg.inc + include modebaud.inc ; define mode bits and baud eqautes + + +max$device equ 3 + + cseg + +; c = device + +?cinit: ; init devices + ld b,c + call vector$io + dw ff.init + dw as0init + dw as1init + dw rret + +; b = device, c = output char, a = input char + +?ci: ; character input + call vector$io + dw ff.in + dw as0inp + dw as1inp + dw null$input + +?cist: ; character input status + call vector$io + dw ff.i.st + dw as0ista + dw as1ista + dw null$status + +?co: ; character output + call vector$io + dw ff.out + dw as0out + dw as1out + dw rret + +?cost: ; character output status + call vector$io + dw ff.o.st + dw as0osta + dw as1osta + dw ret$true + +vector$io: + ld a,max$device + ld e,b +vector: + pop hl + ld d,0 + cp e + jr nc,exist + ld e,a ; use null device if a >= max$device +exist: add hl,de + add hl,de + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + jp (hl) + + +null$input: + ld a,1Ah +rret: + ret +ret$true: + or 0FFh + ret + +null$status: + xor a + ret + +;-------------------------------------------------------------- + + +@ctbl: + db 'HOST ' ; device 0 + db mb$in$out + db baud$none + + db 'ASCI0 ' ; device 1 + db mb$in$out+mb$serial+mb$soft$baud +ser0$baud: + db baud$19200 + + db 'ASCI1 ' ; device 2 + db mb$in$out+mb$serial+mb$soft$baud +ser1$baud: + db baud$19200 + + db 0 ; table terminator + + end diff --git a/z180/conbuf-a.180 b/z180/conbuf-a.180 new file mode 100644 index 0000000..f69b86d --- /dev/null +++ b/z180/conbuf-a.180 @@ -0,0 +1,163 @@ + page 255 + .z80 + +; +; FIFO channels for communication with avr +; + global ff.init,ff.in,ff.out,ff.i.st,ff.o.st + + extrn bufinit + + include config.inc + if CPU_Z180 + include z180reg.inc + endif + + +;-------------------------------------------------------------- + + dseg + + + mkbuf ci.fifo_id, ci.fifo, ci.fifo_len + mkbuf co.fifo_id, co.fifo, co.fifo_len + + +;-------------------------------------------------------------- + + cseg + +; Init Serial I/O for console input and output +; + +ff.init: + ld ix,ci.fifo + call bufinit + ld ix,co.fifo + jp bufinit + + +ff.i.st: + push ix + ld ix,ci.fifo ; + +buf.empty: + ld a,(ix+o.in_idx) ; + sub (ix+o.out_idx) ; + pop ix + ret z + or 0ffh + ret + + +ff.in: + push ix + ld ix,ci.fifo ; + +buf.get: + ld a,(ix+o.out_idx) ; +bg.wait: + cp (ix+o.in_idx) ; + jr z,bg.wait + + push hl ; + push ix + pop hl + add a,l + ld l,a + jr nc,bg.nc + inc h +bg.nc: + ld l,(hl) + + ld a,(ix+o.out_idx) ; + inc a + and (ix+o.mask) + ld (ix+o.out_idx),a + + ld a,l + pop hl + pop ix + ret + + +ff.o.st: + push ix + ld ix,co.fifo ; + +buf.full: + ld a,(ix+o.in_idx) ; + inc a + and (ix+o.mask) + sub (ix+o.out_idx) ; + pop ix + ret z + or 0ffh + ret + + + if 1 +ff.out: + push ix ;15 + ld ix,co.fifo ;14 + +buf.put: + push hl ;11 + push bc ;11 + push ix ;15 + pop hl ;10 + ld a,c ;4 + ld c,(ix+o.in_idx) ;19 + ld b,0 ;7 + add hl,bc ;11 + ld (hl),a ;7 + ld b,a ;4 + + ld a,c ;4 + inc a ;4 + and (ix+o.mask) ;19 +bp.wait: + cp (ix+o.out_idx) ;19 + jr z,bp.wait ;12/7 + ld (ix+o.in_idx),a ;19 + + out (AVRINT6),a ;11 + ld a,b ;4 + pop bc ;10 + pop hl ;10 + pop ix ;14 + ret ;10 + + else + +ff.out: + push ix ;15 + ld ix,co.fifo ;14 + +buf.put: + push hl ;11 + push ix ;15 + pop hl ;10 + ld a,(ix+o.in_idx) ;19 + add a,l ;4 + ld l,a ;4 + jr nc,bp.1 ;12/7 + inc l ;4 + ld (hl),c ;7 + ld a,(ix+o.in_idx) ;19 + inc a ;4 + and (ix+o.mask) ;19 +bp.wait: + cp (ix+o.out_idx) ;19 + jr z,bp.wait ;12/7 + ld (ix+o.in_idx),a ;19 + + out (AVRINT6),a ;11 + ld a,c ;4 + pop hl ;10 + pop ix ;14 + ret ;10 | + + endif + + end diff --git a/z180/config.inc b/z180/config.inc new file mode 100644 index 0000000..bea6e05 --- /dev/null +++ b/z180/config.inc @@ -0,0 +1,220 @@ + +FALSE equ 0 +TRUE equ NOT FALSE + + +banked equ true + +;----------------------------------------------------- +; CPU and BANKING types + + +CPU_Z180 equ TRUE +CPU_Z80 equ FALSE + +ROMSYS equ FALSE + +AVRCLK equ 18432 ;[KHz] + + if CPU_Z180 + +;----------------------------------------------------- +;FOSC equ AVRCLK/2 ;Oscillator frequency [KHz] +;PHI equ FOSC*2 ;CPU frequency (clock doubler enabled) + +;---------------------------------------------------------------------- +; Baudrate Generator for x16 clock mode: +; TC = (f PHI / (32 * baudrate)) - 2 +; +; PHI [MHz]: 9.216 18.432 +; baudrate TC TC +; ---------------------- +; 115200 - 3 +; 57600 3 8 +; 38400 - 13 +; 19200 13 28 +; 9600 28 58 + + +;----------------------------------------------------- +; Programmable Reload Timer (PRT) + +PRT_PRE equ 20 ;PRT prescaler + +;----------------------------------------------------- +; MMU + +COMMON_SIZE equ 4*1024 ;Common Area size in bytes + ;must be multiple of 4K +if (COMMON_SIZE mod 1000h) + .printx COMMON_SIZE not multiple of 4K! + end ;stop assembly +endif +CMN_SIZE equ COMMON_SIZE/1000h ;4K units +BNK_SIZE equ 64/4 - CMN_SIZE ;bank size (4K units) +BANKS equ (512/4 - CMN_SIZE)/BNK_SIZE ;max nr. of banks + +; Logical address space, CBAR values + +CA equ 10h - CMN_SIZE ;common area start (64K - common size) +BA equ 0 ;banked area start + + if 0 + +SYS$CBR equ 0 +SYS$CBAR equ CA*16 + CA ;CBAR in system mode +USR$CBAR equ CA*16 + BA ;CBAR in user mode (CP/M) + + endif + if 1 + +SYS$CBR equ BNK_SIZE +SYS$CBAR equ CA*16 + CA ;CBAR in system mode +USR$CBAR equ CA*16 + BA ;CBAR in user mode (CP/M) + + endif + + +;----------------------------------------------------- + +CREFSH equ 0 ;Refresh rate register (disable refresh) +CWAITIO equ 3 shl IWI0 ;Max I/O Wait States, 0 Memory Wait States +PHI_X2 equ 0 ;set to M_X2CM to enable the clock doubler + + endif ;CPU_Z180 + if CPU_Z80 + +PHI equ AVRCLK/5 ;CPU frequency [KHz] +BAUDCLCK equ AVRCLK/10 ;Baudrate clock [KHz] +;BDCLK16 equ + +SIOAD EQU 0bch +SIOAC EQU 0bdh +SIOBD EQU 0beh +SIOBC EQU 0bfh + +CTC0 EQU 0f4h +CTC1 EQU 0f5h +CTC2 EQU 0f6h +CTC3 EQU 0f7h + +; +; Init Serial I/O for console input and output (SIO-A) +; +; Baudrate clock: 1843200 Hz (Bus connector pin A17) +; +; Baudrate Divider SIO CTC +; --------------------------------- +; 115200 16 16 1 +; 57600 32 16 2 +; 38400 48 16 3 +; 19200 96 16 6 +; 9600 192 16 12 +; 4800 384 16 24 +; 2400 768 16 48 +; 1200 1536 16 96 +; 600 3072 16 192 +; 300 6144 64 92 + + endif ; CPU_Z80 + + if ROMSYS +c$rom equ 0a5h +ROM_EN equ 0C0h +ROM_DIS equ ROMEN+1 + if CPU_Z180 +CWAITROM equ 2 shl MWI0 + endif + endif + + +DDTZRSTVEC equ 030h ;DDTZ Restart vector (breakpoints) + +INIDONE equ 03Fh ;CP/M skip hw init, if this address +INIDONEVAL equ 080h ; is set to this value. + +mtx.fifo_len equ 64 ;Message transfer fifos +mtx.fifo_id equ 0 ; This *must* have #0 +mrx.fifo_len equ 64 +mrx.fifo_id equ 1 + +ci.fifo_len equ 32 ;AVRCON (USB0) Character I/O via AVR +ci.fifo_id equ 2 +co.fifo_len equ 32 +co.fifo_id equ 3 + +s0.rx_len equ 128 ;Serial 0 (ASCI0) buffers +s0.rx_id equ 4 ; +s0.tx_len equ 128 ; +s0.tx_id equ 5 ; + +s1.rx_len equ 128 ;Serial 1 (ASCI1) buffers +s1.rx_id equ 6 ; +s1.tx_len equ 128 ; +s1.tx_id equ 7 ; + +AVRINT5 equ 4Fh +AVRINT6 equ 5Fh +;PMSG equ 80h + +IDEBASE equ 60h + +;----------------------------------------------------- +; Definition of (logical) top 2 memory pages + +sysram_start equ 0FE00h +bs$stack$size equ 80 + +isvsw_loc equ 0FEE0h + +ivtab equ 0ffc0h ;int vector table +iv2tab equ ivtab + 2*9 + + + +;----------------------------------------------------- + +o.id equ -4 +o.mask equ -3 +o.in_idx equ -2 +o.out_idx equ -1 + + .lall + +mkbuf macro id,name,size + if ((size AND (size-1)) NE 0) OR (size GT 256) + .printx Error: buffer ^size must be power of 2 and in range 0..256! + name&.mask equ ;wrong size error + else + db id + db size-1 + ds 2 + name:: ds size + name&.mask equ low (size-1) + if size ne 0 + name&.end equ $-1 + name&.len equ size + name&.id equ id + endif + endif +endm + +;----------------------------------------------------- + +inidat macro + cseg +??ps.a defl $ + endm + +inidate macro +??ps.len defl $ - ??ps.a + dseg + ds ??ps.len + endm + +;----------------------------------------------------- + +b0call macro address + call _b0call + dw address + endm diff --git a/z180/console.180 b/z180/console.180 new file mode 100644 index 0000000..1241d5a --- /dev/null +++ b/z180/console.180 @@ -0,0 +1,137 @@ + ;page 255 + .z80 + + +; iobyte: +; 0 = console on AVR-System +; 1 = console on SIO/ASCI + + + extrn iobyte + extrn ff.init,ff.i.st,ff.in + extrn ff.o.st,ff.out + if CPU_Z180 + extrn as0init,as0ista,as0inp,as0osta,as0out + extrn as1init,as1ista,as1inp,as1osta,as1out + else + extrn ser.init,ser.ist,ser.in,ser.ost,ser.out + endif + + public charini + public ?const,?conin + public ?conos,?cono + + include config.inc + if CPU_Z180 + include z180reg.inc + endif + + cseg + + if CPU_Z180 +charini: + call ff.init + call as0init + jp as1init + +?const: + ld a,(iobyte) + and 03h + jp z,ff.i.st + dec a + jp z,as0ista + dec a + jp z,as1ista + jr nullstatus + +?conin: + ld a,(iobyte) + and 03h + jp z,ff.in + dec a + jp z,as0inp + dec a + jp z,as1inp + jr nullinput + +?conos: + ld a,(iobyte) + and 03h + jp z,ff.o.st + dec a + jp z,as0osta + dec a + jp z,as1osta + jr rettrue + +?cono: + ld a,(iobyte) + and 03h + jp z,ff.out + dec a + jp z,as0out + dec a + jp z,as1out + jr nulloutput + + else + +charini: + call ff.init + ld c,0 + call ser.init + ld c,1 + jp ser.init + +?const: + ld a,(iobyte) + and 03h + jp z,ff.i.st + dec a + ld b,a + jp ser.ist + +?conin: + ld a,(iobyte) + and 03h + jp z,ff.in + dec a + ld b,a + jp ser.in + +?conos: + ld a,(iobyte) + and 03h + jp z,ff.o.st + dec a + ld b,a + jp ser.ost + +?cono: + ld a,(iobyte) + and 03h + jp z,ff.out + dec a + ld b,a + jp ser.out + endif + + +nullinput: + ld a,1Ah + ret + +nulloutput: + ld a,c + ret + +rettrue: + or 0FFh + ret + +nullstatus: + xor a + ret + + end + diff --git a/z180/ddtz.180 b/z180/ddtz.180 new file mode 100644 index 0000000..d18330c --- /dev/null +++ b/z180/ddtz.180 @@ -0,0 +1,6062 @@ + page 255 + .z80 + + extrn ?const,?conin,?cono + extrn getiff + extrn selbnk,@cbnk + + global ddtz,bpent + global $stack + + + include config.inc + if CPU_Z180 + include z180reg.inc + include z180.lib + endif + +BS equ 08h +TAB equ 09h +CR equ 0dh +LF equ 0ah +DEL equ 7fh +CNTRX equ 'X'-'@' + +TPA equ 100h +TOPRAM equ 0f000h + + +MEMDUMP_CNT equ 16 ;mem dump bytes per line +BP_CNT equ 12 ;number of breakbpoints + + +;-------------------------------------------------- +; + +; copy code to common memory and execute it there +comst macro + call ?excom + ds 1 +?lcs defl $ + endm + +; mark end of common code snippet +comend macro +?lce defl $ +?lclen defl ?lce-?lcs + org ?lcs-1 + db ?lclen + org ?lce + ifndef ?lcmax +?lcmax defl 0 + endif + if ?lclen gt ?lcmax +?lcmax defl ?lclen + endif + endm + + + + + cseg + +;---------------------------------------------------------- + +MSG: + DB 'DDT/Z - HD64180 (ROM)' + DB CR,LF,0 + +HLPMSG: + DB 'DDT/Z180 (ROM) Commands:',CR,LF + DB '> @ examine/substitute the displacement register @',CR,LF + DB '> A [address] Assemble',CR,LF + DB '> B[X] display [or clear] all Breakpoints',CR,LF + DB ' B breakp [:count] [breakp..] set Breakpoints',CR,LF + DB ' BX address [address..] clear Breakpoints',CR,LF + DB '>>C[N][J] [count] trace over Calls [No list] [Jumps only]',CR,LF + DB ' C[N][J] W|U expression trace over Calls While|Until ...',CR,LF + DB '>>D [startadr] [endadr] Display memory in hex and ascii',CR,LF + DB '> G [startadr] [;breakp..] Go [to start] [temporary breakpoints]',CR,LF + DB '> H [expression [expression]] compute expressions / show High/max load adr.',CR,LF + DB '>>I [port] Input a byte from port',CR,LF + DB '>>L [startadr] [endadr] List disassembled code',CR,LF + DB '> M[V] startadr endadr destadr Move memory [and verify]',CR,LF + DB '>>O [byte] [port] Output a byte to port',CR,LF + DB '> Q[J] startadr endadr bytes Qery memory for byte string [Justified]',CR,LF + DB '> R [displacement] Read intel hex from console [add displacemt]',CR,LF + DB '> S address Substitute memory',CR,LF + DB '>>T[N][J] [count] Trace [No list] [Jumps only] [count steps]',CR,LF + DB ' T[N][J] W|U expression Trace While|Until expression',CR,LF + DB '> V startadr endadr destadr Verify (compare) two memory areas',CR,LF + DB '> X[register] eXamine [and substitute] registers',CR,LF + DB '> Y[0..9] eXamine [and substitute] Y variables',CR,LF + DB '> Z startadr endadr bytes Zap (fill) memory with a byte string',CR,LF + DB 0 + +ddtz: + ld sp,$stack + ld a,(wstrtflg) ;check warm start flag + or a +;;; jr nz,ddtz_w + + exx + ld hl,sysramc + ld de,topcodbeg + ld bc,topcodend-topcodbeg + ldir + + exx + + if CPU_Z180 + ld a,e + ld (ubbr),a + endif + +ddtz_w: + ld hl,MSG + call PSTR + call ddtei + +; DDTZ main loop + +DDTZML: + ld sp,$stack + ld hl,l07eah + ld (CMD_ERR),hl + ld hl,(REG.PC) + ld (OFFS.pc),hl + call sub_0e68h + ld hl,(CMD_RPT) + ld de,DDTZML + call CP.HL.DE + ld a,'>' + call OUTCHAR + call nz,OUTCHAR + call z,OUTBL + call INLINE + call SKIPBL + jr z,exe_hl + ld hl,DDTZML + ld (CMD_RPT),hl + inc de + sub '?' + jr c,ERROR + cp 'Z'+1-'?' + jr nc,ERROR + add a,a + ld hl,CMDTAB + call ADD_HL_A + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + jr exe_hl +ERROR: + ld hl,(CMD_ERR) +exe_hl: + call CALL.HL + jr DDTZML + +CALL.HL: + jp (hl) + + +CMDTAB: + defw CMD.? ;Help + defw CMD.@ ;Offset + defw CMD.A ;Assemble + defw CMD.B ;Breakpoint + defw CMD.C ;Call + defw CMD.D ;Display + defw ERROR ; + defw ERROR ; + defw CMD.G ;Go + defw CMD.H ;Hex Math + defw CMD.I ;In Port + defw ERROR ; + defw ERROR ; + defw CMD.L ;List + defw CMD.M ;Move + defw ERROR ; + defw CMD.O ;Out Port + defw ERROR ; + defw CMD.Q ;Query + defw CMD.R ;Read Intel Hex + defw CMD.S ;Substitute + defw CMD.T ;Trace + defw ERROR ; + defw CMD.V ;Verify + defw ERROR ; + defw CMD.X ;eXamine + defw CMD.Y ;eXamine Y Registers + defw CMD.Z ;Zap (fill) memory +l07eah: + ld a,'?' + call OUTCHAR + jp CRLF + +CMD.?: + call assert_eol + ld hl,HLPMSG + call PSTR + ret + +$ci: + push hl + push de + push bc + call ?conin + pop bc + pop de + pop hl + ret + +$co: + push hl + push de + push bc + ld c,a + call ?cono + pop bc + pop de + pop hl + ret + +DELC: + ld a,b + or a + ret z + call DELC1 + dec hl + dec b + inc c + ld a,(hl) + cp ' ' + ret nc +DELC1: + push de + push hl + push bc + ld c,BS + call ?cono + ld c,' ' + call ?cono + ld c,BS + call ?cono + pop bc + pop hl + pop de + ret + +DELL: + ld a,b ; + or a ; + ret z ; + call DELC ; + jr DELL ; + +INLINE: + push hl ; + ld hl,CI.BUF ; + ld c,(hl) ; + inc hl ; + ld b,000h ; + inc hl ; +inlnxtch: + ld a,c ; + or a ; + jr z,inl_e ; + call $ci ; + cp CR ; + jr z,inl_e ;Accept line + cp LF ; + jr z,inl_e ;Accept line + cp BS ; + jr nz,l0844h ; + call DELC ;Delete Char + jr inlnxtch ; +l0844h: + cp DEL ; + jr nz,l084dh ; + call DELC ;Delete Char + jr inlnxtch ; +l084dh: + cp CNTRX ; + jr nz,l0856h ; + call DELL ;Delete Line + jr inlnxtch ; +l0856h: + cp TAB ; + jr nz,l085ch ; + ld a,' ' ; +l085ch: + ld (hl),a ; + cp ' ' ; + jr nc,l0869h ; + ld a,'^' ;Controll characters + call $co ; + ld a,(hl) ; + add a,'@' ; +l0869h: + call $co ; + inc hl ; + inc b ; + dec c ; + jr inlnxtch ; + +inl_e: + ld hl,ci.buf+1 ; + ld (hl),b ; + call CRLF ; + ld de,ci.buf+1 ; + ld a,(de) ; + ld b,a ; + ld c,000h ; + inc b ; +l0880h: + inc de ; + dec b ; + jr z,l08b2h ; + ld a,(de) ; + bit 0,c ; + call z,UPCASE ; + ld (de),a ; + cp '''' ; + jr nz,l0880h ; + push de ; + dec de ; + ld a,(de) ; + cp '''' ; + jr z,l08aeh ; + dec de ; + ld a,(de) ; + cp '^' ; + jr z,l08a2h ; + dec de ; + ld a,(de) ; + cp '^' ; + jr nz,l08aeh ; +l08a2h: + inc de ; + push bc ; + call sub_0a0eh ; + pop bc ; + dec de ; + ld a,(de) ; + cp '''' ; + jr z,l08afh ; +l08aeh: + inc c ; +l08afh: + pop de ; + jr l0880h ; +l08b2h: + xor a ; + ld (de),a ; + ld de,ci.buf+2 ; + pop hl ; + ret ; + +UPCASE: + cp 'a' ; + ret c ; + cp 'z'+1 ; + ret nc ; + and 05fh ; + ret ; + +out.hl.@: + call out.hl ; + push de ; + push hl ; + ld de,(offs.@) ; + ld a,d ; + or e ; + jr z,l08ddh ; + call OUTBL ; + ld a,'@' ; + call OUTCHAR ; + and a ; + sbc hl,de ; + call out.hl ; +l08ddh: + pop hl ; + pop de ; + ret ; + +out.bin.w: + ld a,h ; + call out.bin.b ; + ld a,l ; +out.bin.b: + ld b,008h ; +l08e7h: + add a,a ; + push af ; + ld a,0 ; + adc a,a ; + call out.digit ; + pop af ; + djnz l08e7h ; + ld a,'"' ; + jp OUTCHAR ; + +sub_08f7h: + ld a,'-' ; + call OUTCHAR ; + dec hl ; + jp cpl.hl ; + +out.hl.decm: + push hl ; + call sub_08f7h ; + db 3eh ; ld a,0E5h +out.hl.dec: + push hl + ld b,6 ; + call sub_0917h ; + pop hl ; + ld a,'.' ; + call OUTCHAR ; +l0911h: + call OUTBL ; + djnz l0911h ; + ret ; + + +sub_0917h: + dec b + push de + ld de,10 + call DIV_HL_DE + ld a,h + or l + call nz,sub_0917h + ld a,e + pop de + jr out.digit + +sub_0928h: + push hl + call sub_08f7h + call out.hl + pop hl + ret +out.hl: + ld a,h + call out.hex + ld a,l +out.hex: + push af + rra + rra + rra + rra + call out.digit + pop af +out.digit: + and 00fh + cp 10 + jr c,l0947h + add a,007h +l0947h: + add a,'0' + jr OUTCHAR +l094bh: + ld a,'-' + call OUTCHAR + ld a,040h +out.ascii: + ex af,af' + call outquote + ex af,af' + push af + res 7,a + cp ' ' + jr nc,l0960h + sub 0c0h +l0960h: + call OUTCHAR + push af + cp '''' + call z,OUTCHAR + pop af + ex af,af' + call outquote + pop af + or a + ld a,'.' + call m,OUTCHAR + ex af,af' + jr c,l094bh + ret + +outquote: + ld a,'''' +OUTCHAR: + push hl + push de + push bc + push af + and 07fh + ld c,a + call ?cono + ld hl,CON.COL + inc (hl) + pop af + pop bc + pop de + pop hl + ret + +inchar: + push hl + push de + push bc + call ?const + and a + jr z,inch1 + call ?conin + scf +inch1: + pop bc + pop de + pop hl + ret + +PSTR: + ld c,000h +l0995h: + ld a,(hl) + and a + ret z + call OUTCHAR + inc c + inc hl + and a + ret m + jr l0995h + +outbl6: + call outbl2 +outbl4: + call outbl2 +outbl2: + call OUTBL +OUTBL: + ld a,' ' + jr OUTCHAR +CRLF: + call inchar + ld a,CR + call OUTCHAR + ld a,LF + call OUTCHAR + ld a,000h + ld (CON.COL),a + jp c,DDTZML + ret + +ADD_HL_A: + add a,l + ld l,a + ret nc + inc h + ret + +SKIPBL0: + inc de +SKIPBL: + ld a,(de) + cp ' ' + jr z,SKIPBL0 + cp 009h + jr z,SKIPBL0 + or a + ret + +skip_to_nextarg: + call SKIPBL + cp ',' + ret nz + inc de + call SKIPBL + cp a + ret + +assert_eol: + call SKIPBL + ret z +l09e5h: + jp ERROR + +chk.sp: + push hl + push de + ld hl,0 + add hl,sp + ld de,$stack-50 + call CP.HL.DE + pop de + pop hl + jr c,l09e5h + ret + +CP.HL.DE: + and a + sbc hl,de + add hl,de + ret + +lookupch: + ld b,000h +l0a00h: + ld a,(hl) + and a + ret z + ld a,(de) + cp (hl) + jr z,l0a0bh + inc hl + inc b + jr l0a00h +l0a0bh: + scf + inc de + ret + +sub_0a0eh: + ld hl,b_0x132A_start + ld b,07fh + jr l0a17h + +sub_0a15h: + ld b,0ffh +l0a17h: + inc b + ld a,(hl) + and a + ret z + call l0a27 + jr nc,l0a17h + res 7,b + ret + +sub_0a23h: + push bc + res 7,b + db 3eh ;0a26 ld a,0c5h +l0a27: + push bc + push de +l0a29h: + ld a,(de) + xor (hl) + and 07fh + jr nz,l0a41h + bit 7,(hl) + inc hl + inc de + jr z,l0a29h + scf + bit 7,b + call z,sub_0d20h + jr nc,l0a44h + pop af + scf + pop bc + ret + +l0a41h: + call sub_0a50h +l0a44h: + pop de + and a + pop bc + ret + +sub_0a48h: + inc b +l0a49h: + dec b + ret z + call sub_0a50h + jr l0a49h +sub_0a50h: + ld a,(hl) + and a + ret z +l0a53h: + ld a,(hl) + inc hl + and a + ret m + jr l0a53h + +get_arg3: + call get_arg_range + push hl + push bc + call skip_to_nextarg + call get_arg + ex de,hl + pop bc + pop hl + ret + +sub_0a68h: + call EXPR + jr c,error0 + ret + +get_arg: + call sub_0a68h +l0a71h: + jp assert_eol + +get_lastarg_def: + call get_arg_def + jr l0a71h + +get_arg_def: + push hl + call EXPR + jr c,l0a80h + ex (sp),hl +l0a80h: + pop hl + ret + +sub_0a82h: + call sub_0a87h + jr l0a71h + +sub_0a87h: + db 0e6h ;0a87 and 037h (clear carry) +get_arg_range: + scf + ex af,af' + push bc + push hl + call EXPR + jr nc,l0a97h + ex af,af' + jr c,error0 + ex af,af' + pop hl + + defb 03eh +l0a97h: + pop af + call sub_0aa5h + jr nc,l0aa3h + ex af,af' + pop bc + ret nc +error0: + jp ERROR + +l0aa3h: + pop af + ret + +sub_0aa5h: + call skip_to_nextarg + cp 'S' + jr nz,l0aadh + inc de +l0aadh: + push hl + push af + call EXPR + jr c,l0ac3h + ld b,h + ld c,l + pop af + pop hl + jr z,l0ac1h + ld a,c + sub l + ld c,a + ld a,b + sbc a,h + ld b,a + inc bc +l0ac1h: + and a + ret + +l0ac3h: + pop af + pop hl + jr z,error0 + scf + ret + +EXPR: + call SKIPBL +EXPR1: + call do_subexpr + ret c + call do_rel_op + ret nc + push bc + push hl + call do_subexpr + jr c,error0 + ex de,hl + ex (sp),hl + and a + sbc hl,de + ld hl,0ffffh + pop de + ret + +do_op_eq: + jr z,l0af8h + jr l0af7h +do_op_ne: + jr nz,l0af8h + jr l0af7h +do_op_le: + jr z,l0af8h +do_op_lt: + jr c,l0af8h + jr l0af7h +do_op_gt: + jr z,l0af7h +do_op_ge: + jr nc,l0af8h +l0af7h: + inc hl +l0af8h: + and a + ret + +do_rel_op: + push hl + ld hl,tab_eq_le_ge + call lookupch + jr nc,l0b28h + ld a,b + or a + jr z,l0b1ch + ld a,(de) + cp '=' + jr nz,l0b11h + inc de + inc b + inc b + jr l0b1ch + +l0b11h: + bit 0,b + jr z,l0b1ch + cp '>' + jr nz,l0b1ch + inc de + ld b,005h +l0b1ch: + ld hl,tab_func_eqlege + ld a,b + add a,a + call ADD_HL_A + ld c,(hl) + inc hl + ld b,(hl) + scf +l0b28h: + pop hl + ret + +tab_eq_le_ge: + db '=<>',0 + +tab_func_eqlege: + defw do_op_eq + defw do_op_lt + defw do_op_gt + defw do_op_le + defw do_op_ge + defw do_op_ne + +do_subexpr: + call do_factor + ret c +l0b3eh: + call do_binary_op + push hl + push bc + call do_factor + pop bc + ex de,hl + ex (sp),hl + jr nc,l0b52h + pop de + ld a,b + or c + ret z + jp ERROR + +l0b52h: + ld a,b + or c + push bc + ret nz + pop bc +do_op_add: + add hl,de +l0b58h: + pop de + jr l0b3eh + +do_op_sub: + and a + sbc hl,de + jr l0b58h + +do_op_mlt: + push bc + if CPU_Z180 + ld b,h + ld c,e + ld h,e + ld e,l + mlt bc + mlt de + mlt hl + ld a,h + add a,c + add a,e + ld h,a + else + ld b,h + ld c,l + ld hl,0 + ld a,16 +mlt_1: + add hl,hl + ex de,hl + add hl,hl + ex de,hl + jr nc,mlt_2 + add hl,bc +mlt_2: + dec a + jr nz,mlt_1 + endif + pop bc + jr l0b58h + +do_op_div: + call DIV_HL_DE + jr l0b58h + +do_op_mod: + call DIV_HL_DE + ex de,hl + jr l0b58h + +; divide x/y +; hl: x +; de: y +; return: +; hl: q (x/y) +; de: r (x%y) + +DIV_HL_DE: + push bc + ex de,hl ;de = x, hl = y + ld b,h ;bc = y + ld c,l + ld hl,0 ;r = 0 + ld a,16 ;count + +; de: x (x shifted out, q shifted in) +; bc: y +; hl: r (initially 0) + +l0b89h: + ex de,hl ;x + add hl,hl ;x <<= 1 + ex de,hl ;r + adc hl,hl ;r <<= 1 + + or a + sbc hl,bc + inc de + jr nc,div_no_restore + add hl,bc + dec de +div_no_restore: + dec a + jr nz,l0b89h + ex de,hl ;hl: q de: r + pop bc + ret + +do_op_and: + ld a,h + and d + ld h,a + ld a,l + and e + ld l,a + jr l0b58h + +do_op_or: + ld a,h + or d + ld h,a + ld a,l + or e + ld l,a + jr l0b58h + +do_op_xor: + ld a,h + xor d + ld h,a + ld a,l + xor e + ld l,a + jr l0b58h + +do_binary_op: + push hl + ld hl,tab_op_a + call lookupch + ld a,b + ld hl,tab_func_opa + add a,a + call ADD_HL_A + ld c,(hl) + inc hl + ld b,(hl) + pop hl + ret + +tab_op_a: + DB '+-*/%&!#',0 +tab_func_opa: + defw do_op_add + defw do_op_sub + defw do_op_mlt + defw do_op_div + defw do_op_mod + defw do_op_and + defw do_op_or + defw do_op_xor + defw 0 + +fact_factor: + call do_factor + ret nc + jp ERROR + +do_factor: + call chk.sp + call get.number + ret nc + inc de + ld hl,TOPRAM + cp 'T' + ret z + ld hl,(HILOD) + cp 'H' + ret z + ld hl,(MAXLOD) + cp 'M' + ret z + ld hl,TPA + cp 'L' + ret z + ld hl,(offs.@) + cp '@' + ret z + ld hl,(OFFS.pc) + cp '$' + ret z + cp '-' + jr z,fact_factneg + cp '~' + jr z,fact_factinv + cp '+' + jr z,fact_factor + cp '^' + jr z,fact_reg.CPU + cp 'Y' + jr z,fact_reg.Y + cp '(' + jr z,fact_mem + cp '[' + jp z,EXPR_BRCKT ;0c35 [ expression ] + cp '''' + jr z,fact_factstring + dec de + scf + ret + +fact_reg.Y: + call get.decdigit + jp c,ERROR + inc de + add a,a + ld hl,reg.Y + call ADD_HL_A + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + and a + ret +fact_factstring: + ld hl,0 +l0c56h: + ld a,(de) + cp '''' + jr z,l0c62h + and a + ret z +l0c5dh: + ld h,l + ld l,a + inc de + jr l0c56h + +l0c62h: + inc de + ld a,(de) + cp '''' + jr z,l0c5dh + sub '.' + or a + ret nz + inc de + set 7,l + ret + +fact_reg.CPU: + call sub_1315h + jr nc,l0cbbh + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + and a + bit 0,c + ret nz + ld h,000h + ret + +fact_factneg: + call fact_factor + dec hl +cpl.hl: + ld a,h + cpl + ld h,a + ld a,l + cpl + ld l,a + ret +fact_factinv: + call fact_factor + jr cpl.hl + +fact_mem: + call EXPR1 + jr c,l0cbbh + ld a,(de) + cp ')' + jr nz,l0cbbh + inc de + comst + ld a,(hl) + inc hl ; + ld h,(hl) ; + comend + ld l,a + ld a,(de) + inc de + cp '.' + ret z + dec de + xor a + ld h,a + ret + +EXPR_BRCKT: + call EXPR1 + jr c,l0cbbh + ld a,(de) + cp ']' + inc de + ret z +l0cbbh: + jp ERROR + +get.number: + call get.hexdigit + ret c + push de +l0cc3h: + inc de + call get.hexdigit + jr nc,l0cc3h + pop de + cp '.' + jr z,l0d04h + cp '"' + jr z,l0ce9h + ld hl,0 +l0cd5h: + call get.hexdigit + jr c,l0ce4h + add hl,hl + add hl,hl + add hl,hl + add hl,hl + call ADD_HL_A + inc de + jr l0cd5h +l0ce4h: + xor 'H' + ret nz + inc de + ret + +l0ce9h: + ld hl,0 +l0cech: + call get.bindigit +l0cefh: + inc de + jr c,l0cf8h + add hl,hl + call ADD_HL_A + jr l0cech +l0cf8h: + cp '"' + jp nz,ERROR + call get.bindigit + jr nc,l0cefh + or a + ret +l0d04h: + ld hl,0 +l0d07h: + call get.decdigit + inc de + jr c,l0d1ah + push bc + add hl,hl ;0d0e hl *= 10 + ld b,h + ld c,l + add hl,hl + add hl,hl + add hl,bc + pop bc + call ADD_HL_A + jr l0d07h +l0d1ah: + cp '.' + ret z + jp ERROR + +sub_0d20h: + ld a,(de) + cp 05bh + jr l0d28h + +get.hexdigit: + ld a,(de) +sub_0d26h: + cp 'F'+1 +l0d28h: + ccf + ret c + cp 'A' + jr c,l0d32h + sub 'A'-10 + ret + +get.decdigit: + ld a,(de) +l0d32h: + cp '9'+1 + jr l0d39h +get.bindigit: + ld a,(de) + cp '1'+1 +l0d39h: + ccf + ret c + cp '0' + ret c + sub '0' + ret + +l0d41h: + call assert_eol + +prnt_cpustat: + call prnt_f + call outbl2 + ld hl,b_0x0DFD_start + ld de,b_0x0E1D_start + ld b,006h +l0d52h: + call prnt_regs + djnz l0d52h + push hl + push de + ld iy,(REG.PC) + call sub_1f77h + exx + ex af,af' + call CRLF + call prnt_f2 + call outbl2 + pop de + pop hl + ld b,007h +l0d6fh: + call prnt_regs + djnz l0d6fh + exx + ex af,af' + and a + jr z,l0d7fh + call outbl6 + call sub_1f5bh +l0d7fh: + jp crlf + +prnt_f: + ld a,(reg.f) + call prnt_flags + ld a,(reg.iff) + cp 0f3h + jp z,outbl + ld a,'E' + jp outchar + +prnt_f2: + ld a,(reg.f2) + call prnt_flags + jp outbl + +prnt_flags: + ld b,a + ld a,'S' + call sub_0dbeh + ld a,'Z' + call sub_0dbeh + rl b + ld a,'H' + call sub_0dbeh + rl b + ld a,'V' + call sub_0dbeh + ld a,'N' + call sub_0dbeh + ld a,'C' +sub_0dbeh: + rl b + jp c,OUTCHAR + jp OUTBL + +prnt_regs: + push bc + push de + call PSTR + ld a,'=' + call OUTCHAR + ex (sp),hl + ld e,(hl) + inc hl + ld d,(hl) + inc hl + ld a,(hl) + inc hl + push hl + and a + jr z,l0df2h + push af + ld a,(de) + ld l,a + inc de + ld a,(de) + ld h,a + pop af + dec a + jr z,l0dedh + call out.hl.@ + call z,outbl6 + jr l0df6h +l0dedh: + call out.hl + jr l0df6h +l0df2h: + ld a,(de) + call out.hex +l0df6h: + call OUTBL + pop de + pop hl + pop bc + ret + +b_0x0DFD_start: + DC 'A ' + DC 'BC ' + DC 'DE ' + DC 'HL ' + DC 'SP' + DC 'PC' + DC 'A''' + DC 'BC''' + DC 'DE''' + DC 'HL''' + DC 'IX' + DC 'IY' + DC 'I' + DB 0 + +b_0x0E1D_start: + defw reg.a + defb 000h + defw reg.c + defb 001h + defw reg.e + defb 001h + defw reg.l + defb 001h + defw reg.sp + defb 001h + defw reg.pc + defb 002h + defw reg.a2 + defb 000h + defw reg.c2 + defb 001h + defw reg.e2 + defb 001h + defw reg.l2 + defb 001h + defw reg.ix + defb 001h + defw reg.iy + defb 001h + defw reg.i + dw 0 + +CMD.G: + sub a + ld (TCFLG),a + ld (XA747),a + call EXPR + jr c,l0e54h + ld (REG.PC),hl +l0e54h: + call SKIPBL + jp z,l1183h + cp ';' + jp nz,ERROR + inc de + ld a,002h + call sub_0f24h + jp l1183h + +sub_0e68h: + ld b,BP_CNT + ld ix,bp_tab +l0e6eh: + ld a,(ix+000h) + and 0f1h + ld (ix+000h),a + call sub_11c5h + ld de,BP_SIZE + add ix,de + djnz l0e6eh + ret + +CMD.B: + call SKIPBL + jr z,l0ecbh + inc de + cp 'X' + jr z,l0e91h + dec de + ld a,001h + jp sub_0f24h +l0e91h: + call SKIPBL + jr z,l0ea6h +l0e96h: + call EXPR + jp c,assert_eol + push de + call sub_0ea7h + pop de + call skip_to_nextarg + jr l0e96h +l0ea6h: + scf +sub_0ea7h: + ld b,BP_CNT + ld ix,bp_tab +l0eadh: + push af + jr c,l0ebbh + ld e,(ix+002h) + ld d,(ix+003h) + call CP.HL.DE + jr nz,l0ec2h +l0ebbh: + ld (ix+000h),000h + call sub_11c5h +l0ec2h: + ld de,BP_SIZE + add ix,de + pop af + djnz l0eadh + ret +l0ecbh: + ld b,BP_CNT + ld ix,bp_tab +l0ed1h: + bit 0,(ix+000h) + jr z,l0f1ch + ld a,'R' + bit 4,(ix+000h) + jr nz,l0ee1h + ld a,' ' +l0ee1h: + call OUTCHAR + call OUTBL + ld l,(ix+002h) + ld h,(ix+003h) + call out.hl.@ + call outbl2 + ld a,':' + call OUTCHAR + ld l,(ix+004h) + ld h,(ix+005h) + call out.hl + ld l,(ix+006h) + ld h,(ix+007h) + ld a,h + or l + jr z,l0f19h + call outbl4 + ld a,'I' + call OUTCHAR + call outbl2 + call PSTR +l0f19h: + call CRLF +l0f1ch: + ld de,BP_SIZE + add ix,de + djnz l0ed1h + ret + +sub_0f24h: + ld b,a + call SKIPBL + ret z + cp 'R' + jr nz,l0f30h + inc de + set 4,b +l0f30h: + push bc + call EXPR + jp c,ERROR + pop bc + bit 0,b + push bc + push de + push hl + call nz,sub_0ea7h + pop hl + call sub_0f68h + pop de + ld (ix+002h),l + ld (ix+003h),h + call sub_0f80h + ld (ix+004h),l + ld (ix+005h),h + call sub_0f91h + ld (ix+006h),l + ld (ix+007h),h + call skip_to_nextarg + pop af + ld (ix+000h),a + and 00fh + jr sub_0f24h +sub_0f68h: + ld b,BP_CNT + ld ix,bp_tab +l0f6eh: + ld a,(ix+000h) + and 00fh + ret z + push bc + ld bc,BP_SIZE + add ix,bc + pop bc + djnz l0f6eh + jp ERROR + +sub_0f80h: + call SKIPBL + ld hl,1 + cp 03ah + ret nz + inc de + call EXPR + jp c,ERROR + ret +sub_0f91h: + call SKIPBL + cp 049h + ld hl,0 + ret nz + inc de + call SKIPBL + push de + call EXPR + jp c,ERROR + ex de,hl + pop de + push de + sbc hl,de + ld b,h + ld c,l + ld hl,(sexp1) + push hl + add hl,bc + ld de,sexpbufe + call CP.HL.DE + jp nc,ERROR + pop hl + ld (sexp2),hl + pop de + ex de,hl + ldir + xor a + ld (de),a + inc de + ex de,hl + ld (sexp1),hl + ld hl,(sexp2) + ret + +bpddtz: + if ROMSYS + ld h,ROMEN + jr z,l0fd2h + inc h +l0fd2h: + push hl ;save rom enable stat + endif + push bc + push de + push ix + push iy + ld a,i + ld h,a + ld l,000h + push hl ;save I register + + if CPU_Z180 + ld a,0f3h ;DI + jp po,l0fe6h + ld a,0fbh ;EI + else ;NMOS Z80 design flaw + call getiff ;return Carry set, if INTs are disabled. + ld a,0f3h ;DI + jr c,l0fe6h + ld a,0fbh ;EI + endif +l0fe6h: + ld (reg.iff),a + ld hl,ivtab + ld a,h + ld i,a + call ddtei + ex af,af' + push af + exx + push bc + push de + push hl + call bp.unset + if CPU_Z180 + in0 a,(itc) + jp p,l1017h + res TRAP,a + out0 (itc),a + bit UFO,a + jr z,l1011h + ld hl,(REG.PC) + dec hl + ld (REG.PC),hl +l1011h: + ld hl,MSG_trap + call PSTR +l1017h: + endif + + ld a,(XBFE8) + dec a + jr z,l1051h + call inchar + jr c,l102eh + call sub_1059h + and a + jp z,l1183h + and 083h + jp z,l284ah +l102eh: + call sub_0e68h + call prnt_cpustat + jp DDTZML + + if CPU_Z180 +MSG_trap: + DB CR,LF,'Undefined opcode trap' + DB CR,LF,0 + endif + +l1051h: + ld (XBFE8),a + ld c,007h + jp l119fh +sub_1059h: + ld a,080h + ex af,af' + sub a + ld (XA747),a + ld b,BP_CNT + ld ix,bp_tab +l1066h: + ld a,(ix+000h) + and 007h + jr z,l107eh + ld e,(ix+002h) + ld d,(ix+003h) + ld hl,(REG.PC) + call CP.HL.DE + push bc + call z,sub_1087h + pop bc +l107eh: + ld de,BP_SIZE + add ix,de + djnz l1066h + ex af,af' + ret +sub_1087h: + ex af,af' + res 7,a + ex af,af' + ld e,(ix+006h) + ld d,(ix+007h) + ld a,d + or e + ld hl,0ffffh + call nz,EXPR + ld a,h + or l + jr z,l10aeh + ld e,(ix+004h) + ld d,(ix+005h) + dec de + ld a,d + or e + jr z,l10b9h + ld (ix+004h),e + ld (ix+005h),d +l10aeh: + bit 4,(ix+000h) + ret z + ld a,001h + ld (XA747),a + ret +l10b9h: + ex af,af' + or (ix+000h) + ex af,af' + ret + +bp.unset: + ld b,BP_CNT + ld ix,bp_tab +l10c5h: + bit 5,(ix+000h) + res 5,(ix+000h) + jr z,l10e7h + ld l,(ix+002h) + ld h,(ix+003h) + ld a,(ddtzrst) + comst + cp (hl) + comend + jr nz,l10e7h + ld a,(ix+001h) + comst + ld (hl),a + comend +l10e7h: + res 3,(ix+000h) + ld de,BP_SIZE + add ix,de + djnz l10c5h + ret +sub_10f3h: + ld b,BP_CNT + ld ix,bp_tab +l10f9h: + ld a,(ix+000h) + and 003h + jr z,l110dh + ld e,(ix+002h) + ld d,(ix+003h) + ld hl,(REG.PC) + call CP.HL.DE + ret z +l110dh: + ld de,BP_SIZE + add ix,de + djnz l10f9h + sub a + inc a + ret +sub_1117h: + call sub_0f68h + ld (ix+004h),001h + ld (ix+005h),000h + ld (ix+002h),l + ld (ix+003h),h + ld (ix+006h),000h + ld (ix+007h),000h + ld a,(XBFE8) + and a + ld a,008h + jr nz,l113ah + ld a,004h +l113ah: + ld (ix+000h),a + ret + +bp.set: + ld b,BP_CNT + ld ix,bp_tab +l1144h: + ld a,(ix+000h) + and c + jr z,l117bh + set 5,(ix+000h) + ld l,(ix+002h) + ld h,(ix+003h) + + + ld a,(ddtzrst) + comst + ld e,(hl) + ld (hl),a + comend + ld (ix+001h),e + and 038h + ld h,0 + ld l,a + ld de,bpent + comst ; + ld (hl),0c3h + inc hl + ld (hl),e + inc hl + ld (hl),d + comend + + +l117bh: + ld de,BP_SIZE + add ix,de + djnz l1144h + ret + +l1183h: + sub a + ld (XBFE8),a + ld a,(XA747) + and a + call nz,prnt_cpustat + call sub_10f3h + ld c,007h + jr nz,l119fh + ld a,001h + ld (XBFE8),a + call sub_26e7h + ld c,008h +l119fh: + call bp.set + ld sp,$stack ;11a2 set/restore user cpu state + pop hl + pop de + pop bc + pop af + exx + ex af,af' + pop af + ld i,a + pop iy + pop ix + pop de + pop bc + if ROMSYS + pop hl + ld a,l + and M_MWI + ld l,a + di + in0 a,(dcntl) + and ~M_MWI + or l + ld l,a + ld a,h + else + pop hl + di + endif + jp $go ;11c2 common ram, switch banks and go to user prog + +sub_11c5h: + ld a,(ix+000h) + and 003h + ret nz + ld e,(ix+006h) + ld d,(ix+007h) + ld a,d + or e + ret z + push bc + ld h,d + ld l,e + sub a + ld (ix+006h),a + ld (ix+007h),a + ld bc,0ffffh + cpir +l11e3h: + push de + ld de,(sexp1) + call CP.HL.DE + pop de + jr nc,l11f9h + call sub_11ffh +l11f1h: + ld a,(hl) + ldi + and a + jr nz,l11f1h + jr l11e3h +l11f9h: + ld (sexp1),de + pop bc + ret +sub_11ffh: + ld iy,bp_tab + push de +l1204h: + ld e,(iy+006h) + ld d,(iy+007h) + call CP.HL.DE + jr z,l1216h + ld de,BP_SIZE + add iy,de + jr l1204h +l1216h: + pop de + ld (iy+006h),e + ld (iy+007h),d + ret + +CMD.Y: + call get.decdigit + jr c,l122fh + inc de + push af + call assert_eol + pop af + call sub_1248h + jp l127ch +l122fh: + call assert_eol + xor a +l1233h: + push af + call sub_1248h + call outbl4 + pop af + inc a + bit 0,a + push af + call z,CRLF + pop af + cp LF + jr c,l1233h + ret + +sub_1248h: + ld c,a + ld b,0 + add a,'0'+080h + ld de,msg.Y+1 + ld (de),a + dec de + ld hl,reg.Y + add hl,bc + add hl,bc + ex de,hl + ld c,003h + jp l129ah + +CMD.X: + call SKIPBL + call sub_1315h + jp nc,l0d41h + call assert_eol + ld a,b + cp 01fh + jr z,l12c6h + cp 020h + jr z,l12b6h + ex de,hl + ld hl,b_0x132A_start + call sub_0a48h +l1279h: + call l129ah +l127ch: + call OUTBL + push de + push bc + call INLINE + call SKIPBL + jr z,l1297h + call get_arg + ld b,h + ld c,l + pop af + pop hl + ld (hl),c + bit 0,a + ret z + inc hl + ld (hl),b + ret +l1297h: + pop af + pop hl + ret +l129ah: + ld b,c + call PSTR + ld a,'=' + call OUTCHAR + ld a,(de) + bit 0,b + jp z,out.hex + ld l,a + inc de + ld a,(de) + dec de + ld h,a + bit 1,b + jp z,out.hl + jp out.hl.@ + +l12b6h: + call prnt_f + ld a,0f3h + ld (reg.iff),a + scf + call sub_12d1h + ld (reg.f),a + ret + +l12c6h: + call prnt_f2 + and a + call sub_12d1h + ld (reg.f2),a + ret + +sub_12d1h: + ex af,af' + ld b,000h + call outbl + call assert_eol + call inline +l12ddh: + call skipbl + ld a,b + ret z + push bc + ld hl,tab_pr_flags + call lookupch + jp nc,error + ld a,b + cp 008h + jr z,l12feh + inc b + ld a,001h + jr l12f7h +l12f6h: + rlca +l12f7h: + djnz l12f6h + pop bc + or b + ld b,a + jr l12ddh +l12feh: + ex af,af' + jp nc,ERROR + ex af,af' + ld a,0FBh + ld (reg.iff),a + pop bc + jr l12ddh + +tab_pr_flags: + db 'CNV H ZSE' + db 0 + +sub_1315h: + call sub_0a0eh + ret nc + ld a,b + add a,b + add a,b + ld hl,b_0x136C_start + call ADD_HL_A + ld c,(hl) + inc hl + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + scf + ret + +b_0x132A_start: + if ROMSYS + DC 'ROMSEL' + endif + if CPU_Z180 + DC 'CBAR' + DC 'BBR' + else + DC 'BNK' + endif + DC 'BC''' + DC 'DE''' + DC 'HL''' + DC 'BC' + DC 'DE' + DC 'HL' + DC 'A''' + DC 'B''' + DC 'C''' + DC 'D''' + DC 'E''' + DC 'H''' + DC 'L''' + DC 'A' + DC 'B' + DC 'C' + DC 'D' + DC 'E' + DC 'H' + DC 'L' + DC 'IX' + DC 'IY' + DC 'SP' + DC 'PC' + DC 'X' + DC 'Y' + DC 'S' + DC 'P' + DC 'I' + DC 'F''' + DC 'F' + DB 0 +b_0x136C_start: + if ROMSYS + defb 000h + defw uromen + endif + if CPU_Z180 + defb 000h + defw ucbar + defb 000h + defw ubbr + else + defb 000h + defw ubnk + endif + defb 003h + defw reg.c2 + defb 003h + defw reg.e2 + defb 003h + defw reg.l2 + defb 003h + defw reg.c + defb 003h + defw reg.e + defb 003h + defw reg.l + defb 000h + defw reg.a2 + defb 000h + defw reg.b2 + defb 000h + defw reg.c2 + defb 000h + defw reg.d2 + defb 000h + defw reg.e2 + defb 000h + defw reg.h2 + defb 000h + defw reg.l2 + defb 000h + defw reg.a + defb 000h + defw reg.b + defb 000h + defw reg.c + defb 000h + defw reg.d + defb 000h + defw reg.e + defb 000h + defw reg.h + defb 000h + defw reg.l + defb 003h + defw reg.ix + defb 003h + defw reg.iy + defb 003h + defw reg.sp + defb 003h + defw reg.pc + defb 003h + defw reg.ix + defb 003h + defw reg.iy + defb 003h + defw reg.sp + defb 003h + defw reg.pc + defb 000h + defw reg.i + defb 000h + defw reg.f2 + defb 000h + defw reg.f +CMD.S: + ld hl,(lst.S) + call get_lastarg_def +l13d8h: + ld (lst.S),hl + call out.hl.@ + call OUTBL + comst + ld a,(hl) + comend + call out.hex + call outbl2 + call INLINE + call SKIPBL + inc hl + jr z,l13d8h + dec hl + inc de + cp '.' + jp z,assert_eol + cp '-' + jr nz,l1406h + ld a,(de) + or a + dec hl + jr z,l13d8h + inc hl +l1406h: + dec de + call get_bytes_m + jr l13d8h + +CMD.@: + call assert_eol + ld hl,MSG_at + ld de,offs.@ + ld c,001h + jp l1279h +MSG_at: + dc '@' + +CMD.I: + ld hl,CMD.I + ld (CMD_RPT),hl + ld hl,(lst.IP) + call get_lastarg_def + ld (lst.IP),hl + ld b,h + ld c,l + if CPU_Z180 + ld a,b + or a + jr nz,l1442h + ld a,c + ld hl,ucbar + cp cbar + jr z,l143fh + ld hl,ubbr + cp bbr + jr nz,l1442h +l143fh: + ld a,(hl) + jr l1444h +l1442h: + endif + in a,(c) +l1444h: + push af + call out.hex + call outbl4 + pop af + call out.bin.b + jp CRLF +CMD.O: + ld hl,CMD.O + ld (CMD_RPT),hl + ld hl,(lst.OD) + call get_arg_def + ld a,l + ld (lst.OD),a + push af + call skip_to_nextarg + ld hl,(lst.OP) + call get_lastarg_def + ld (lst.OP),hl + ld b,h + ld c,l + if CPU_Z180 + ld a,b + or a + jr nz,l1489h + ld a,c + ld hl,ucbar + cp cbar + jr z,l148dh + ld hl,ubbr + cp bbr + jr z,l148dh + cp cbr + jp z,ERROR +l1489h: + endif + pop af + out (c),a + ret + if CPU_Z180 +l148dh: + pop af + ld (hl),a + ret + endif + +CMD.V: + call get_arg3 ;1490 get from, size, to +cmp_mem: + push bc + comst + ld a,(de) + ld b,(hl) + comend + cp b + jr z,l14bah + ld c,a + call out.hl.@ + call OUTBL + ld a,b + call out.hex + call outbl2 + ld a,c + call out.hex + call OUTBL + ex de,hl + call out.hl.@ + ex de,hl + call CRLF +l14bah: + pop bc + inc hl + inc de + dec bc + ld a,b + or c + jr nz,cmp_mem + ret + +CMD.M: + ld a,(de) + cp 'V' + jr nz,bm_nv + inc de +bm_nv: + push af ;14c9 save 'V' flag + call get_arg3 + push hl + push de + push bc + call CP.HL.DE + jr nc,bm_mvdown + add hl,bc + ex de,hl + add hl,bc + ex de,hl + dec hl + dec de + comst + lddr + comend + jr bm_done +bm_mvdown: + comst + ldir + comend +bm_done: + pop bc + pop de + pop hl + pop af + jr z,cmp_mem ;14ed validate? + ret +CMD.H: + call EXPR + jp c,l173ch ;no parameters, print High and Max + call skip_to_nextarg + push hl + call EXPR + push af + call assert_eol + pop af + ex de,hl + pop hl + jr c,l1511h + push hl + push de + add hl,de + call l1511h + pop de + pop hl + and a + sbc hl,de +l1511h: + call out.hl ;1511 val + call outbl2 + call sub_0928h ;1517 -val + call outbl4 + call out.hl.dec ;151d dec + call outbl2 + call out.hl.decm ;1523 -dec + call outbl4 + call out.bin.w ;1529 bin + call outbl2 + ld a,l + call out.ascii + jp CRLF + +CMD.Q: + ld a,(de) + sub 'J' + ld (lst.Qj),a + jr nz,l153fh + inc de +l153fh: + call get_arg_range + push bc + push hl + call sub_15a7h + pop hl +l1548h: + call sub_1594h + jr nz,l1562h + push bc + push hl + ld a,(lst.Qj) + or a + jr nz,l1559h + ld bc,-8 + add hl,bc +l1559h: + ld bc,MEMDUMP_CNT + and a + call memdump + pop hl + pop bc +l1562h: + inc hl + ex (sp),hl + dec hl + ld a,h + or l + ex (sp),hl + jr nz,l1548h + pop bc + ret + +CMD.Z: + call get_arg_range + push bc + push hl + call sub_15a7h + ld a,b + pop hl + pop bc + push hl + ex de,hl +l1579h: + push af + ld a,(hl) + comst + ld (de),a + comend + pop af + inc de + cpi + jp po,l1592h + dec a + jr nz,l1579h + pop hl + comst + ldir + comend + ret +l1592h: + pop hl + ret + +sub_1594h: + push hl + push de + push bc +l1597h: + ld a,(de) + comst + cp (hl) + comend + jr nz,l15a3h + inc de + inc hl + djnz l1597h +l15a3h: + pop bc + pop de + pop hl + ret + +sub_15a7h: + ld hl,ci.buf+1 + call get_bytes + ld de,ci.buf+1 + and a + sbc hl,de + ld b,l + ret nz + jp ERROR + +get_bytes: + db 0e6h ;15b8 and 037h (clear carry, skip next opc) +get_bytes_m: + scf +l15bah: + push af + call skip_to_nextarg + cp 'W' + jr nz,l15d9h + inc de + push hl + call sub_0a68h + ex de,hl + pop bc + pop af + push af + push bc + ex (sp),hl + jr nc,l15d3h + comst +l15d3h: + ld (hl),e + comend + inc hl + ld c,d + pop de + jr l15e5h +l15d9h: + cp '''' + jr z,l15f1h + push hl + call EXPR + ld c,l + pop hl + jr c,l1626h +l15e5h: + pop af + push af + jr nc,l15edh + comst +l15edh: + ld (hl),c + comend + inc hl + jr l161eh +l15f1h: + inc de + ld a,(de) + cp '''' + jr z,l1607h + or a + jr z,l1626h +l15fah: + ld c,a + pop af + push af + jr nc,l1603h + comst +l1603h: + ld (hl),c + comend + inc hl + jr l15f1h +l1607h: + inc de + ld a,(de) + cp '''' + jr z,l15fah + cp '.' + jr nz,l161eh + inc de + dec hl + pop af + push af + jr nc,l161bh + comst +l161bh: + set 7,(hl) + comend + inc hl +l161eh: + pop af + jr nc,l15bah + ld (lst.S),hl + jr l15bah + +l1626h: + pop af + ret nc + ld (lst.S),hl + ret + +CMD.D: + ld hl,CMD.D + ld (CMD_RPT),hl + ld hl,(lst.D) + ld bc,00080h + call sub_0a82h + scf +memdump: + push bc + push de + push hl + ex af,af' +l1640h: + call out.hl.@ + call z,outbl2 + call OUTBL + ld de,0 +l164ch: + comst + ld a,(hl) + comend + inc hl + call out.hex + call OUTBL + dec bc + inc e + ld a,e + cp 010h + jr z,l1668h + and 003h + call z,OUTBL + ld a,b + or c + jr nz,l164ch +l1668h: + call OUTBL + and a + sbc hl,de +l166eh: + comst + ld a,(hl) + comend + call sub_168fh + call OUTCHAR + inc hl + dec e + jr nz,l166eh + ex af,af' + jr nc,l1683h + ld (lst.D),hl +l1683h: + ex af,af' + call CRLF + ld a,b + or c + jr nz,l1640h + pop hl + pop de + pop bc + ret +sub_168fh: + and 07fh + cp 07fh + jr z,l1698h + cp 020h + ret nc +l1698h: + ld a,02eh + ret + +; Read Intel Hex File from console. +CMD.R: + ld hl,0 + call get_lastarg_def ;169e get offset from command line + push hl + ld hl,0 + ld (HILOD),hl +w_recstart: + call i.getchar + jr z,l16deh + cp ':' + jr nz,w_recstart + ld c,0 ;16b1 init checksum + call i.gethexbyte ;16b3 record len + ld b,a + call i.gethexbyte ;16b7 address high + ld h,a + call i.gethexbyte ;16bb address low + ld l,a + call i.gethexbyte ;16bf record type (ignored) + ld a,b + and a ;16c3 record len == 0? + jr z,l16deh +l16c6h: + call i.gethexbyte + pop de ;16c9 offset + push de + push hl + add hl,de + call i.storebyte + pop hl + inc hl + djnz l16c6h ;16d2 repeat for record len + call i.gethexbyte ;16d4 checksum + ld a,c + and a + jp nz,ERROR ;16d9 exit if checksum error + jr w_recstart ;16dc next record +l16deh: + pop hl + call i.gethexbyte + jp l173fh + +i.gethexbyte: + call sub_16f6h + rlca + rlca + rlca + rlca + ld d,a + call sub_16f6h + add a,d + ld d,a + add a,c + ld c,a + ld a,d + ret + +sub_16f6h: + call i.getchar + jr z,l16ffh + call sub_0d26h + ret nc +l16ffh: + jp ERROR + +i.getchar: + call $ci + cp 01ah + ret + +i.storebyte: + push af + push de + ld de,TPA ;170a lowest allowed load address + call CP.HL.DE + jp c,ERROR + ld de,$stcka ;1713 highest allowed load address + call CP.HL.DE + jp nc,ERROR + ld de,(HILOD) + call CP.HL.DE + jr c,l1728h + ld (HILOD),hl +l1728h: + ld de,(MAXLOD) + call CP.HL.DE + jr c,l1734h + ld (MAXLOD),hl +l1734h: + pop de + pop af + comst + ld (hl),a ;173a store byte + comend + ret + +l173ch: + call assert_eol +l173fh: + ld hl,MSG_high + call PSTR + ld hl,(HILOD) + call out.hl + ld hl,MSG_max + call PSTR + ld hl,(MAXLOD) + call out.hl + jp CRLF + +MSG_high: + DC 'High = ' +MSG_max: + DC ' Max = ' + +CMD.A: + ld hl,(lst.A) + call get_lastarg_def + push hl + pop iy + ld hl,l17c4h + ld (CMD_ERR),hl + ld (XB068),sp +l177ch: + push iy + pop hl + ld (lst.A),hl + ld (OFFS.pc),hl + push hl + call sub_1f3fh + pop iy + ld c,b + ld de,(offs.@) + ld a,d + or e + ld b,011h + jr z,l1798h + ld b,019h +l1798h: + call OUTBL + ld a,(CON.COL) + cp b + jr c,l1798h + push bc + call INLINE + pop bc + call SKIPBL + cp '.' + ret z + cp '-' + jr nz,l17b6h + ld iy,(XB06C) + jr l177ch +l17b6h: + and a + call nz,sub_17cdh + ld (XB06C),iy + ld b,0 + add iy,bc + jr l177ch +l17c4h: + call l07eah + ld sp,(XB068) + jr l177ch + +sub_17cdh: + call SKIPBL + ld hl,t_MNEMONICS + call sub_0a15h + jp nc,ERROR + call SKIPBL + push de + ld a,b + add a,b + add a,b + ld hl,b_0x17EE_start + call ADD_HL_A + ld e,(hl) + inc hl + ld d,(hl) + inc hl + ld b,(hl) + ex de,hl + pop de + jp (hl) + +b_0x17EE_start: + defw l1b54h + defb 088h + defw l1b74h + defb 080h + defw l1babh + defb 0a0h + defw l1c14h + defb 040h + defw l1c38h + defb 0c4h + defw l1b36h + defb 03fh + defw l1babh + defb 0b8h + defw gen.opc.ED2 + defb 0a9h + defw gen.opc.ED2 + defb 0b9h + defw gen.opc.ED2 + defb 0a1h + defw gen.opc.ED2 + defb 0b1h + defw l1b36h + defb 02fh + defw l1b36h + defb 027h + defw l1dabh + defb 005h + defw l1b36h + defb 0f3h + defw l1ca4h + defb 010h + defw l1b36h + defb 0fbh + defw l1d54h + defb 0e3h + defw l1b36h + defb 0d9h + defw l1b36h + defb 076h + defw l1cbfh + defb 046h + defw l1cf8h + defb 040h + defw l1dabh + defb 004h + defw gen.opc.ED2 + defb 0aah + defw gen.opc.ED2 + defb 0bah + defw gen.opc.ED2 + defb 0a2h + defw gen.opc.ED2 + defb 0b2h + defw l1c5eh + defb 0c2h + defw l1cabh + defb 020h + defw l1934h + defb 040h + defw gen.opc.ED2 + defb 0a8h + defw gen.opc.ED2 + defb 0b8h + defw gen.opc.ED2 + defb 0a0h + defw gen.opc.ED2 + defb 0b0h + defw gen.opc.ED2 + defb 044h + defw l1b36h + defb 000h + defw l1babh + defb 0b0h + defw gen.opc.ED2 + defb 0bbh + defw gen.opc.ED2 + defb 0b3h + defw l1d2ch + defb 041h + defw gen.opc.ED2 + defb 0abh + defw gen.opc.ED2 + defb 0a3h + defw l1ce4h + defb 0c1h + defw l1ce4h + defb 0c5h + defw l1c14h + defb 080h + defw l1c50h + defb 0c0h + defw gen.opc.ED2 + defb 04dh + defw gen.opc.ED2 + defb 045h + defw l1bd8h + defb 010h + defw l1b36h + defb 017h + defw l1bd8h + defb 000h + defw l1b36h + defb 007h + defw gen.opc.ED2 + defb 06fh + defw l1bd8h + defb 018h + defw l1b36h + defb 01fh + defw l1bd8h + defb 008h + defw l1b36h + defb 00fh + defw gen.opc.ED2 + defb 067h + defw l1cd5h + defb 0c7h + defw l1b54h + defb 098h + defw l1b36h + defb 037h + defw l1c14h + defb 0c0h + defw l1bd8h + defb 020h + defw l1bd8h + defb 028h + defw l1bd8h + defb 038h + defw l1babh + defb 090h + defw l1babh + defb 0a8h + defw A.IN0 + defb 000h + defw A.MLT +b_0x18BC_start: + defb 04ch + ld b,e + dec de + +b_0x18BF_start: + defb 08bh + defw gen.opc.ED2 + defb 09bh + defw gen.opc.ED2 + defb 083h + defw gen.opc.ED2 + defb 093h + defw l18fdh + defb 001h + defw gen.opc.ED2 + defb 076h + defw l191dh + defb 004h + defw l192ch + defb 074h +A.IN0: + call sub_1e41h + jr nc,l1931h + cp 006h + jr z,l1931h + rlca + rlca + rlca + add a,b + ld b,a + call sub_1ed1h + call sub_1e06h +l18e9h: + call assert_eol + comst + ld (iy+000h),0edh + ld (iy+001h),b + ld (iy+002h),l + comend + ld c,003h + ret +l18fdh: + call sub_1e06h + call sub_1ed1h + call sub_1e41h + jr nc,l1931h + cp 006h + jr z,l1931h + rlca + rlca + rlca + add a,b + ld b,a + jr l18e9h +A.MLT: + call sub_1e2eh + jr nc,l1931h + add a,b + ld b,a + jp gen.opc.ED2 +l191dh: + call sub_1e41h + jr nc,l192ah + rlca + rlca + rlca + add a,b + ld b,a + jp gen.opc.ED2 +l192ah: + ld b,064h +l192ch: + call sub_1e12h + jr l18e9h +l1931h: + jp ERROR +l1934h: + call sub_1e41h + jp c,l19bfh + call sub_1e68h + jp c,l1a64h + call sub_1e2eh + jp c,l1a93h + call sub_1e50h + jp c,l1af0h + ld a,(de) + cp 049h + jp z,l1b0ch + cp 052h + jp z,l1b14h + cp 028h + jp nz,ERROR + inc de + call sub_1e2eh + jp c,l1b23h + call tst_EXPR + call sub_1ed8h + call sub_1ed1h + call sub_1e2eh + jr c,l19adh + call sub_1e50h + jr nc,l1991h + ld b,022h +l1978h: + call assert_eol + ld a,(pfx.IXY) +l197eh: + comst + ld (iy+000h),a + ld (iy+001h),b + ld (iy+002h),l + ld (iy+003h),h + comend + ld c,004h + ret +l1991h: + ld a,(de) + cp 041h + jp nz,ERROR + inc de + ld b,032h +l199ah: + call assert_eol + comst + ld (iy+000h),b + ld (iy+001h),l + ld (iy+002h),h + comend + ld c,003h + ret +l19adh: + cp 020h + jr z,l19bbh + add a,043h + ld b,a +l19b4h: + call assert_eol + ld a,0edh + jr l197eh +l19bbh: + ld b,022h + jr l199ah +l19bfh: + ld b,a + call sub_1ed1h + call sub_1e41h + jr nc,l19dbh + push af + ld a,b + rlca + rlca + rlca + ld b,a + pop af + add a,b + add a,040h + cp 076h + jp z,ERROR +l19d7h: + ld b,a + jp l1b36h +l19dbh: + call sub_1e68h + jr nc,l1a02h + ld a,b + rlca + rlca + rlca + add a,046h + cp 076h + jp z,ERROR +l19ebh: + ld b,a + call assert_eol + ld a,(pfx.IXY) + comst + ld (iy+000h),a + ld (iy+001h),b + ld (iy+002h),c + comend + ld c,003h + ret +l1a02h: + ld a,(de) + cp 'I' + jr z,l1a15h + cp 'R' + jr nz,l1a21h + ld a,b + cp 007h + jp nz,ERROR + ld b,05fh + jr l1a1dh +l1a15h: + ld a,b + cp 007h + jp nz,ERROR + ld b,057h +l1a1dh: + inc de + jp gen.opc.ED2 +l1a21h: + cp '(' + jr z,l1a3fh + call sub_1e12h + ld a,b ;1a28 ld r,nn + rlca + rlca + rlca + add a,006h +l1a2eh: + ld b,a +l1a2fh: + call assert_eol + comst + ld (iy+000h),b + ld (iy+001h),l + comend + ld c,002h + ret +l1a3fh: + inc de + ld a,b + cp 007h + jp nz,ERROR + call sub_1e2eh + jr nc,l1a59h + cp 030h + jp nc,ERROR + add a,00ah + ld b,a + call sub_1ed8h + jp l1b36h +l1a59h: + call tst_EXPR + call sub_1ed8h + ld b,03ah + jp l199ah +l1a64h: + call sub_1ed1h + call sub_1e41h + jr nc,l1a76h + cp 006h + jp z,ERROR + add a,070h + jp l19ebh +l1a76h: + call sub_1e12h + call assert_eol + ld a,(pfx.IXY) + comst + ld (iy+000h),a ;1a83 dd/fd + ld (iy+001h),036h + ld (iy+002h),c ;1a8a displacement + ld (iy+003h),l ;1a8d nn + comend + ld c,4 + ret +l1a93h: + ld b,a + call sub_1ed1h + ld hl,t_HL.AF + call sub_0a23h + jr c,l1abeh + call sub_1e50h + jr nc,l1ac7h + ld a,b + cp 030h + jr nz,l1b20h + ld b,0f9h +l1aabh: + call assert_eol + ld a,(pfx.IXY) + comst + ld (iy+000h),a + ld (iy+001h),b + comend + ld c,002h + ret +l1abeh: + ld a,b + cp 030h + jr nz,l1b20h + ld b,0f9h + jr l1b36h +l1ac7h: + ld a,(de) + cp 028h + jr nz,l1ae3h + inc de + call tst_EXPR + call sub_1ed8h + ld a,b + cp 020h + jr z,l1adeh + add a,04bh + ld b,a + jp l19b4h +l1adeh: + ld b,02ah + jp l199ah +l1ae3h: + call tst_EXPR + call assert_eol + ld a,001h + add a,b + ld b,a + jp l199ah +l1af0h: + call sub_1ed1h + ld a,(de) + cp 028h + jr nz,l1b04h + inc de + call tst_EXPR + call sub_1ed8h + ld b,02ah + jp l1978h +l1b04h: + call tst_EXPR + ld b,021h + jp l1978h +l1b0ch: + inc de + call sub_1ed1h + ld b,047h + jr l1b1ah +l1b14h: + inc de + call sub_1ed1h + ld b,04fh +l1b1ah: + ld a,(de) + inc de + cp 041h + jr z,gen.opc.ED2 +l1b20h: + jp ERROR +l1b23h: + cp 020h + jr nc,l1b20h + add a,002h + ld b,a + call sub_1ed8h + call sub_1ed1h + ld a,(de) + cp 041h + jr nz,l1b20h + inc de +l1b36h: + call assert_eol + comst + ld (iy+000h),b + comend + ld c,001h + ret +gen.opc.ED2: + call assert_eol + comst + ld (iy+000h),0edh + ld (iy+001h),b + comend + ld c,002h + ret +l1b54h: + ld hl,t_HL.AF + call sub_0a23h + jr nc,l1babh + call sub_1ed1h + call sub_1e2eh + jp nc,ERROR + push af + ld a,b + cp 088h + ld b,04ah + jr z,l1b6fh + ld b,042h +l1b6fh: + pop af + add a,b +l1b71h: + ld b,a + jr gen.opc.ED2 +l1b74h: + ld hl,t_HL.AF + call sub_0a23h + jr c,l1b9dh + call sub_1e50h + jr nc,l1babh + call sub_1ed1h + ld hl,t_BC.DE.IX.SP + ld a,(pfx.IXY) + cp 0fdh + jr nz,l1b91h + ld hl,t_BC.DE.IY.SP +l1b91h: + call sub_1e2bh + jp nc,ERROR + add a,009h +l1b99h: + ld b,a + jp l1aabh +l1b9dh: + call sub_1ed1h + call sub_1e2eh + jp nc,ERROR + add a,009h + jp l19d7h +l1babh: + ld a,(de) + cp 041h + jr nz,l1bbbh + push de + inc de + call skip_to_nextarg + jr z,l1bbah + pop de + jr l1bbbh +l1bbah: + pop af +l1bbbh: + call sub_1e41h + jr c,l1bceh + call sub_1e68h + jr c,l1bd2h + call sub_1e12h + ld a,b + add a,046h + jp l1a2eh +l1bceh: + add a,b + jp l19d7h +l1bd2h: + ld a,b + add a,006h + jp l19ebh +l1bd8h: + call sub_1e41h + jr c,l1c01h + call sub_1e68h + jp nc,ERROR + ld a,b + add a,006h + ld b,a +l1be7h: + call assert_eol + ld a,(pfx.IXY) + comst + ld (iy+000h),a + ld (iy+001h),0cbh + ld (iy+002h),c + ld (iy+003h),b + comend + ld c,004h + ret +l1c01h: + add a,b +l1c02h: + ld b,a + call assert_eol + comst + ld (iy+000h),0cbh + ld (iy+001h),b + comend + ld c,002h + ret +l1c14h: + call sub_1de6h + call sub_1ed1h + call sub_1e41h + jr c,l1c2fh + call sub_1e68h + jp nc,ERROR + ld a,l + rlca + rlca + rlca + add a,006h + add a,b + ld b,a + jr l1be7h +l1c2fh: + add a,b + ld b,a + ld a,l + rlca + rlca + rlca + add a,b + jr l1c02h +l1c38h: + push de + call sub_1eb8h + jr nc,l1c47h + add a,b + ld b,a + call skip_to_nextarg + jr z,l1c49h + pop de + push de +l1c47h: + ld b,0cdh +l1c49h: + pop af + call tst_EXPR + jp l199ah +l1c50h: + call sub_1eb8h + jr nc,l1c59h + add a,b + ld b,a + jr l1c5bh +l1c59h: + ld b,0c9h +l1c5bh: + jp l1b36h +l1c5eh: + push de + call sub_1eb8h + jr c,l1c71h +l1c64h: + pop de + ld hl,b_0x1C97_start + call sub_0a15h + jr c,l1c7fh + ld b,0c3h + jr l1c79h +l1c71h: + add a,b + ld b,a + call skip_to_nextarg + jr nz,l1c64h + pop af +l1c79h: + call tst_EXPR + jp l199ah +l1c7fh: + call assert_eol + ld a,b + and a + jr nz,l1c8bh + ld b,0e9h + jp l1b36h +l1c8bh: + ld b,0ddh + dec a + jr z,l1c92h + ld b,0fdh +l1c92h: + ld l,0e9h + jp l1a2fh + +b_0x1C97_start: + DC '(HL)' + DC '(IX)' + DC '(IY)' + DB 0 + +l1ca4h: + call skip_to_nextarg + ld b,010h + jr l1cb9h +l1cabh: + call sub_1ebfh + jr c,l1cb4h + ld b,018h + jr l1cb9h +l1cb4h: + add a,b + ld b,a + call sub_1ed1h +l1cb9h: + call sub_1defh + jp l1a2fh +l1cbfh: + call sub_1e12h + ld a,l + cp 003h + jr nc,l1d23h + and a + jr z,l1cd2h + ld b,056h + cp 001h + jr z,l1cd2h + ld b,05eh +l1cd2h: + jp gen.opc.ED2 +l1cd5h: + call sub_1e12h + ld a,l + push af + add a,b + ld b,a + pop af + and 0c7h + jr nz,l1d23h + jp l1b36h +l1ce4h: + call sub_1e50h + jr c,l1cf2h + call sub_1e25h + jr nc,l1d23h + add a,b + jp l19d7h +l1cf2h: + ld a,b + add a,020h + jp l1b99h +l1cf8h: + call sub_1e41h + jr nc,l1d23h + cp 006h + jr z,l1d23h + rlca + rlca + rlca + add a,b + ld b,a + cp 078h + jr nz,l1d1ah + call sub_1ed1h + call sub_1d26h + jr c,l1d20h + call sub_1e06h + ld b,0dbh + jp l1a2fh +l1d1ah: + call sub_1ed1h + call sub_1d26h +l1d20h: + jp c,gen.opc.ED2 +l1d23h: + jp ERROR +sub_1d26h: + ld hl,t__C_ + jp sub_0a23h +l1d2ch: + call sub_1d26h + jr nc,l1d44h + call sub_1ed1h + call sub_1e41h + jr nc,l1d23h + cp 006h + jr z,l1d23h + rlca + rlca + rlca + add a,b + jp l1b71h +l1d44h: + call sub_1e06h + call sub_1ed1h + cp 041h + jr nz,l1d23h + inc de + ld b,0d3h + jp l1a2fh +l1d54h: + ld hl,b_0x1D80_start + call sub_0a15h + jp nc,ERROR + ld c,b + call assert_eol + ld b,000h + ld hl,b_0x1DA1_start + add hl,bc + add hl,bc + ld a,(hl) + comst + ld (iy+000h),a + comend + ld c,001h + inc hl + ld a,(hl) + and a + ret z + comst + ld (iy+001h),a + comend + ld c,002h + ret + +b_0x1D80_start: + DC 'AF,AF''' +l1d86h: + DC 'DE,HL' + DC '(SP),HL' + DC '(SP),IX' + DC '(SP),IY' + db 000h + +b_0x1DA1_start: + db 008h + db 000h + db 0ebh + db 000h + db 0e3h + db 000h + db 0ddh + db 0e3h + db 0fdh + db 0e3h +l1dabh: + call sub_1e50h + jr c,l1dc6h + call sub_1e2eh + jr c,l1dd2h + call sub_1e41h + jr c,l1ddfh + call sub_1e68h + jp nc,ERROR + ld a,b + add a,030h + jp l19ebh +l1dc6h: + ld a,b + ld b,023h + cp 004h + jr z,l1dcfh + ld b,02bh +l1dcfh: + jp l1aabh +l1dd2h: + push af + ld a,b + ld b,003h + cp 004h + jr z,l1ddch + ld b,00bh +l1ddch: + pop af + jr l1de2h +l1ddfh: + rlca + rlca + rlca +l1de2h: + add a,b + jp l19d7h +sub_1de6h: + call sub_1e12h + ld a,l + cp 008h + jr nc,error1 + ret +sub_1defh: + call tst_EXPR + push bc + push iy + pop bc + and a + sbc hl,bc + dec hl + dec hl + pop bc + call sub_1e15h + ld a,h + xor l + bit 7,a + jr nz,error1 + ret +sub_1e06h: + ld a,(de) + cp 028h + jr nz,sub_1e12h + inc de + call sub_1e12h + jp sub_1ed8h + +sub_1e12h: + call tst_EXPR +sub_1e15h: + ld a,h + and a + ret z + inc a + ret z + jr error1 + +tst_EXPR: + push bc + call EXPR + pop bc + ret nc +error1: + jp ERROR +sub_1e25h: + push hl + ld hl,t_BC.DE.HL.AF + jr l1e32h +sub_1e2bh: + push hl + jr l1e32h +sub_1e2eh: + push hl + ld hl,t_BC.DE.HL.SP +l1e32h: + push bc + call sub_0a15h + jr nc,l1e3eh + ld a,b + rlca + rlca + rlca + rlca + scf +l1e3eh: + pop bc + pop hl + ret +sub_1e41h: + call SKIPBL + push bc + push hl + ld hl,t_BCDEHL_HL_A + call sub_0a15h + ld a,b + pop hl + pop bc + ret +sub_1e50h: + push hl + push bc + ld hl,t_IX.IY + call sub_0a15h + jr nc,l1e65h + ld a,0ddh + dec b + jr nz,l1e61h + ld a,0fdh +l1e61h: + ld (pfx.IXY),a + scf +l1e65h: + pop bc + pop hl + ret +sub_1e68h: + push hl + push bc + ld a,(de) + cp '(' + jr nz,l1eb4h + push de + inc de + ld hl,t_IX.IY + call sub_0a15h + jr nc,l1eb3h + pop af + ld a,0ddh + dec b + jr nz,l1e81h + ld a,0fdh +l1e81h: + ld (pfx.IXY),a + ld a,(de) + cp '+' + jr z,l1e95h + cp ')' + ld hl,0 + jr z,l1eadh + cp '-' + jp nz,ERROR +l1e95h: + push af + inc de + call sub_1e12h ;1e97 get displacement + pop af + cp '+' + jr z,l1ea7h + ld b,h + ld c,l + ld hl,0 + and a + sbc hl,bc +l1ea7h: + ld a,(de) + cp ')' + jp nz,ERROR +l1eadh: + inc de + pop bc + ld c,l + pop hl + scf + ret +l1eb3h: + pop de +l1eb4h: + pop bc + pop hl + and a + ret +sub_1eb8h: + ld hl,t_tstfl_ZCPS + ld c,007h + jr l1ec4h +sub_1ebfh: + ld hl,t_tstfl_ZC + ld c,003h +l1ec4h: + push bc + call sub_0a15h + ld a,b + pop bc + ret nc + and c + rlca + rlca + rlca + scf + ret +sub_1ed1h: + call skip_to_nextarg + ret z +l1ed5h: + jp ERROR +sub_1ed8h: + ld a,(de) + cp 029h + jr nz,l1ed5h + inc de + ret +CMD.L: + ld hl,CMD.L + ld (CMD_RPT),hl + call EXPR + jr nc,l1eedh + ld hl,(lst.L) +l1eedh: + push hl + pop iy + call skip_to_nextarg + call sub_0aa5h + jr nc,l1f17h + call assert_eol + ld b,010h +l1efdh: + push bc + push iy + pop hl + push hl + call sub_1f3fh + call CRLF + pop iy + ld c,b + ld b,000h + add iy,bc + ld (lst.L),iy + pop bc + djnz l1efdh + ret +l1f17h: + call assert_eol + ld h,b + ld l,c + ld a,b + or c + jr nz,l1f21h + dec hl +l1f21h: + push hl + push iy + pop hl + push hl + call sub_1f3fh + call CRLF + pop iy + ld e,b + ld d,000h + add iy,de + ld (lst.L),iy + pop hl + and a + sbc hl,de + ret z + ret c + jr l1f21h +sub_1f3fh: + call out.hl.@ + call z,OUTBL + call OUTBL + sub a + ld (CON.COL),a + call sub_1f77h + and a + ret z +l1f51h: + call OUTBL + ld a,(CON.COL) + cp 010h + jr c,l1f51h +sub_1f5bh: + ld de,(offs.@) + ld a,d + or e + ret z + ld a,'(' + call OUTCHAR + ld a,'@' + call OUTCHAR + and a + sbc hl,de + call out.hl + ld a,')' + jp OUTCHAR +sub_1f77h: + sub a + ld (XBE03),a + call sub_1f9eh + jr nc,l1f91h + push bc + call sub_2581h + ex de,hl + call sub_1fdbh + pop bc + ld a,(XBE03) + ld hl,(XBE01) + scf + ret +l1f91h: + ld hl,b_0x1F9B_start + call PSTR + ld b,001h + sub a + ret + +b_0x1F9B_start: + DC '???' + +sub_1f9eh: + sub a + ld (is.pfx.IXY),a + comst + ld a,(iy+000h) + comend + cp 0edh + jp z,disas_pfx.ED + cp 0ddh + jr z,l1fc5h + cp 0fdh + jr z,l1fc9h +sub_1fb6h: + comst + ld a,(iy+000h) + comend + cp 0cbh + jp z,l2061h + jp l2078h +l1fc5h: + ld a,001h + jr l1fcbh +l1fc9h: + ld a,002h +l1fcbh: + ld (is.pfx.IXY),a + call sub_1fdch + ret nc + push bc + call sub_1fb6h + pop af + add a,b + ld b,a + scf + ret + +sub_1fdbh: + jp (hl) + +sub_1fdch: + inc iy + ld hl,b_0x2011_start + call sub_20bbh + ld b,002h + ret c + ld hl,l202ch + call sub_20bbh + ld b,001h + ret c + comst + ld a,(iy+000h) + comend + cp 0cbh + jr nz,l200fh + comst + ld a,(iy+002h) + comend + cp 036h + ret z + and 007h + cp 006h + jr nz,l200fh + ld b,002h + scf + ret +l200fh: + and a + ret + +b_0x2011_start: + db 034h + db 035h + db 036h + db 046h + db 04eh + db 056h + db 05eh + db 066h + db 06eh + db 070h + db 071h + db 072h + db 073h + db 074h + db 075h + db 076h + db 077h + db 07eh + db 086h + db 08eh + db 096h + db 09eh + db 0a6h + db 0aeh + db 0b6h + db 0beh + db 000h +l202ch: + db 009h + db 019h + db 021h + db 022h + db 023h + db 029h + db 02ah + db 02bh + db 039h + db 0e1h + db 0e3h + db 0e5h + db 0e9h + db 0f9h + db 000h + +disas_pfx.ED: + inc iy + ld hl,b_0x2200_start + call sub_209dh + ld b,002h + ret c + ld hl,l2235h + call lookup_opc + ld b,002h + ret c + ld hl,l228bh + call lookup_opc + ld b,003h + ret c + ld hl,l22b4h + call lookup_opc + ld b,004h + ret +l2061h: + push iy + inc iy + ld a,(is.pfx.IXY) + and a + jr z,l206dh + inc iy +l206dh: + ld hl,l22c9h + call lookup_opc + pop iy + ld b,002h + ret +l2078h: + ld hl,b_0x218B_start + call lookup_opc + ld b,002h + ret c + ld hl,b_0x20ED_start + call sub_209dh + ld b,001h + ret c + ld hl,b_0x2108_start + call lookup_opc + ld b,001h + ret c + ld hl,b_0x21D2_start + call lookup_opc + ret nc + ld b,003h + ret + +sub_209dh: + ld a,(hl) + cp 0ffh + ret z + comst + cp (iy+000h) + comend + jr z,l20aeh + inc hl + inc hl + jr sub_209dh +l20aeh: + inc hl + ld c,(hl) + ld hl,t_MNEMONICS + ld b,000h + add hl,bc + ld de,l230bh + scf + ret +sub_20bbh: + ld a,(hl) + and a + ret z + inc hl + comst + cp (iy+000h) + comend + jr nz,sub_20bbh + scf + ret + +lookup_opc: + comst + ld a,(iy+000h) + comend + and (hl) + inc hl + cp (hl) + jr z,l20dfh + inc hl + inc hl + inc hl + inc hl + ld a,(hl) + and a + jr nz,lookup_opc + ret +l20dfh: + inc hl + ld c,(hl) + inc hl + ld e,(hl) + inc hl + ld d,(hl) + ld hl,t_MNEMONICS + ld b,000h + add hl,bc + scf + ret + +b_0x20ED_start: ; 1 byte opcodes (no parameters) + db 076h ;20ed halt + db 039h ;20ee + db 0d9h ;20ef exx + db 036h + db 0f3h ;20f1 di + db 02ch + db 0fbh ;20f3 ei + db 032h + db 000h ;20f5 nop + db 069h + db 007h ;20f7 rlca + db 09eh + db 00fh ;20f9 rrca + db 0adh + db 017h ;20fb rla + db 098h + db 01fh ;20fd rra + db 0a7h + db 027h ;20ff daa + db 026h + db 02fh ;2101 cpl + db 023h + db 037h ;2103 scf + db 0bah + db 03fh ;2105 ccf + db 010h + db 0ffh ;2107 EOT + +b_0x2108_start: ; 1 byte opcodes + defb 0c0h ;2108 ld r,r + defb 040h + defb 056h + defw l22fch + + defb 0f8h ;210d add a,r + defb 080h + defb 003h + defw l2305h + + defb 0f8h ;2112 adc a,r + defb 088h + defb 000h + defw l2305h + + defb 0f8h + defb 090h + defb 0c9h + defw l24ebh + + defb 0f8h + defb 098h + defb 0b7h + defw l2305h + + defb 0f8h + defb 0a0h + defb 006h + defw l24ebh + + defb 0f8h + defb 0a8h + defb 0cch + defw l24ebh + + defb 0f8h + defb 0b0h + defb 06ch + defw l24ebh + + defb 0f8h + defb 0b8h + defb 013h + defw l24ebh + + defb 0c7h + defb 0c0h ;2136 ret cc + defb 08bh + defw l2561h + + defb 0c7h ;213a rst + defb 0c7h + defb 0b4h + defw l231eh + + defb 0ffh ;213f ret + defb 0c9h + defb 08bh + defw l230bh + + defb 0cfh ;2144 pop rr + defb 0c1h + defb 081h + defw l2546h + + defb 0cfh ;2149 push rr + defb 0c5h + defb 084h + defw l2546h + + defb 0ffh ;214e ex (sp),hl + defb 0e3h + defb 034h + defw l232ah + + defb 0ffh ;2153 jp (hl) + defb 0e9h + defb 052h + defw l2338h + + defb 0ffh ;2158 ex de,hl + defb 0ebh + defb 034h + defw l2345h + + defb 0ffh ;215d ld sp,hl + defb 0f9h + defb 056h + defw l234bh + + defb 0cfh ;2162 inc rr + defb 003h + defb 041h + defw l254bh + + defb 0cfh ;2167 dec rr + defb 00bh + defb 029h + defw l254bh + + + defb 0c7h ;216c inc r + defb 004h + defb 041h + defw l24dfh + + defb 0c7h ;2171 dec r + defb 005h + defb 029h + defw l24dfh + + defb 0ffh ;2176 ex af,af' + defb 008h + defb 034h + defw l2357h + + defb 0cfh ;217b add hl,rr + defb 009h + defb 003h + defw l235dh + + defb 0efh ;2180 ld (rr),a ;rr=bc,de + defb 002h + defb 056h + defw l2366h + + defb 0efh ;2185 ld a,(rr) ;rr=bc,de + defb 00ah + defb 056h + defw l236fh + + defb 000h ;218a EOT + +b_0x218B_start: ; 2 byte opdodes + defb 0c7h ;218b ld r,nn + defb 006h + defb 056h + defw l2384h + + defb 0ffh ;2190 add a,nn + defb 0c6h + defb 003h + defw l237fh + + defb 0ffh ;2195 adc a,nn + defb 0ceh + defb 000h + defw l237fh + + defb 0ffh ;219a sub a,nn + defb 0d6h + defb 0c9h + defw l2397h + + defb 0ffh + defb 0deh + defb 0b7h + defw l237fh + + defb 0ffh ;21a4 and a,nn + defb 0e6h + defb 006h + defw l2397h + + defb 0ffh + defb 0eeh + defb 0cch + defw l2397h + + defb 0ffh + defb 0f6h + defb 06ch + defw l2397h + + defb 0ffh ;21b3 cp a,nn + defb 0feh + defb 013h + defw l2397h + + defb 0ffh ;21b8 djnz + defb 010h + defb 02eh + defw l23b0h + + defb 0ffh ;21bd jr + defb 018h + defb 054h + defw l23b0h + + defb 0e7h ;21c2 jr,cc + defb 020h + defb 054h + defw l23a1h + + defb 0ffh + defb 0d3h ;21c8 out (nn),a + defb 076h + defw l23d5h + + defb 0ffh ;21cc in a,(nn) + defb 0dbh + defb 03fh + defw l23c3h + + defb 000h ;21d1 EOT + +b_0x21D2_start: ; 3 byte opcodes + defb 0c7h + defb 0c2h + defb 052h + defw l23e0h + + defb 0c7h + defb 0c4h + defb 00ch + defw l23e0h + + defb 0cfh + defb 001h + defb 056h + defw l23fch + + defb 0ffh + defb 0c3h + defb 052h + defw l23e6h + + defb 0ffh + defb 0cdh + defb 00ch + defw l23e6h + + defb 0ffh + defb 022h + defb 056h + defw l2404h + + defb 0ffh + defb 02ah + defb 056h + defw l240dh + + defb 0ffh + defb 032h + defb 056h + defw l2416h + + defb 0ffh + defb 03ah + defb 056h + defw l2421h + + defb 000h + +b_0x2200_start: ; prefix ED + 1 byte opcode + defb 044h ;2200 neg + defb 066h + defb 045h ;2202 retn + defb 092h + defb 04dh ;2204 reti + defb 08eh + defb 067h ;2206 rrd + defb 0b1h + defb 06fh ;2208 rld + defb 0a2h + defb 0a0h ;220a ldi + defb 05fh + defb 0a1h + defb 01ch + defb 0a2h + defb 04bh + defb 0a3h + defb 07dh + defb 0a8h ;2212 ldd + defb 058h + defb 0a9h + defb 015h + defb 0aah + defb 044h + defb 0abh + defb 079h + defb 0b0h ;221a ldir + defb 062h + defb 0b1h + defb 01fh + defb 0b2h + defb 04eh + defb 0b3h + defb 072h + defb 0b8h ;2222 lddr + defb 05bh + defb 0b9h + defb 018h + defb 0bah + defb 047h + defb 0bbh + defb 06eh + defb 08bh ;222a otdm + defb 0d5h + defb 09bh ;222c otdmr + defb 0d9h + defb 083h ;222e otim + defb 0deh + defb 093h ;2230 otimr + defb 0e2h + defb 076h ;2232 slp + defb 0ebh + defb 0ffh ;2234 EOT + +l2235h: + defb 0e7h ;2235 in r,(c) ;r=bcde + defb 040h + defb 03fh + defw l2455h + + defb 0f7h ;223a in r,(c) ;r=hl + defb 060h + defb 03fh + defw l2455h + + defb 0ffh ;223f in r,(c) ;r=a + defb 078h + defb 03fh + defw l2455h + + defb 0e7h + defb 041h + defb 076h + defw l2461h + + defb 0f7h + defb 061h + defb 076h + defw l2461h + + defb 0ffh ;224e out (c),r ;r=a + defb 079h + defb 076h + defw l2461h + + defb 0cfh ;2253 sbc hl,rr + defb 042h + defb 0b7h + defw l246dh + + defb 0cfh ;2258 adc hl,rr + defb 04ah + defb 000h + defw l246dh + + defb 0ffh ;225d im 0 + defb 046h + defb 03dh + defw l2427h + + defb 0ffh ;2262 im 1 + defb 056h + defb 03dh + defw l242bh + + defb 0ffh ;2267 im 2 + defb 05eh + defb 03dh + defw l242fh + + defb 0ffh ;226c ld i,a + defb 047h + defb 056h + defw l2434h + + defb 0ffh + defb 057h + defb 056h + defw l2439h + + defb 0ffh + defb 04fh + defb 056h + defw l243eh + + defb 0ffh + defb 05fh + defb 056h + defw l2443h + + defb 0cfh ;2280 mlt rr + defb 04ch + defb 0d2h + defw l254bh + + defb 0c7h ;2285 tst r + defb 004h + defb 0eeh + defw l24dfh + + defb 000h + +l228bh: + defb 0e7h + defb 000h + defb 0cfh + defw l230ch + + defb 0f7h + defb 020h + defb 0cfh + defw l230ch + + defb 0ffh + defb 038h + defb 0cfh + defw l230ch + + defb 0e7h + defb 001h + defb 0e7h + defw l2315h + + defb 0f7h + defb 021h + defb 0e7h + defw l2315h + + defb 0ffh + defb 039h + defb 0e7h + defw l2315h + + defb 0ffh + defb 064h + defb 0eeh + defw l2397h + + defb 0ffh + defb 074h + defb 0f1h + defw l2397h + defb 000h + +l22b4h: + defb 0efh + defb 043h + defb 056h + +b_0x22B7_start: + defw l2476h + +b_0x22B9_start: + defb 0ffh + defb 073h + defb 056h + +b_0x22BC_start: + defw l2476h + +b_0x22BE_start: + defb 0efh + defb 04bh + defb 056h + +b_0x22C1_start: + defw l247fh + +b_0x22C3_start: + defb 0ffh + defb 07bh + defb 056h + +b_0x22C6_start: + defw l247fh + +b_0x22C8_start: + defb 000h +l22c9h: + defb 0f8h + defb 000h + defb 09bh + +b_0x22CC_start: + defw l24aeh + +b_0x22CE_start: + defb 0f8h + defb 008h + defb 0aah + +b_0x22D1_start: + defw l24aeh + +b_0x22D3_start: + defb 0f8h + defb 010h + defb 096h + +b_0x22D6_start: + defw l24aeh + +b_0x22D8_start: + defb 0f8h + defb 018h + defb 0a5h + +b_0x22DB_start: + defw l24aeh + +b_0x22DD_start: + defb 0f8h + defb 020h + defb 0c0h + +b_0x22E0_start: + defw l24aeh + +b_0x22E2_start: + defb 0f8h + defb 028h + defb 0c3h + +b_0x22E5_start: + defw l24aeh + +b_0x22E7_start: + defb 0f8h + defb 038h + defb 0c6h + +b_0x22EA_start: + defw l24aeh + +b_0x22EC_start: + defb 0c0h + defb 040h + defb 009h + +b_0x22EF_start: + defw l2487h + +b_0x22F1_start: + defb 0c0h + defb 080h + defb 088h + +b_0x22F4_start: + defw l2487h + +b_0x22F6_start: + defb 0c0h + defb 0c0h + defb 0bdh + +b_0x22F9_start: + defw l2487h + +b_0x22FB_start: + defb 000h +l22fch: + call l24dfh + call sub_257ch + jp l24ebh +l2305h: + call sub_2579h + jp l24ebh +l230bh: + ret +l230ch: + call l24dfh + call sub_257ch + jp l23c6h +l2315h: + call l23c6h + call sub_257ch + jp l24dfh +l231eh: + comst + ld a,(iy+000h) + comend + and 038h + jp out.hex +l232ah: + ld hl,b_0x2333_start + call PSTR + jp l253eh + +b_0x2333_start: + DC '(SP),' + +l2338h: + ld a,'(' + call OUTCHAR + call l253eh + ld a,')' + jp OUTCHAR +l2345h: + ld hl,l1d86h + jp PSTR +l234bh: + ld hl,b_0x2354_start + call PSTR + jp l253eh + +b_0x2354_start: + DC 'SP,' + +l2357h: + ld hl,b_0x1D80_start + jp PSTR +l235dh: + call l253eh + call sub_257ch + jp l254bh +l2366h: + call sub_2372h + call sub_257ch + jp l23dbh +l236fh: + call sub_2579h +sub_2372h: + ld a,'(' + call OUTCHAR + call l254bh + ld a,')' + jp OUTCHAR +l237fh: + call sub_2579h + jr l2397h +l2384h: + call l24dfh + call sub_257ch + ld a,(is.pfx.IXY) + and a + comst + ld a,(iy+002h) + comend + jr nz,l239eh +l2397h: + comst + ld a,(iy+001h) + comend +l239eh: + jp out.hex +l23a1h: + comst + ld a,(iy+000h) + comend + and 018h + call sub_2568h + call sub_257ch +l23b0h: + comst + ld c,(iy+001h) + comend + ld a,c + rla + sbc a,a + ld b,a + push iy + pop hl + add hl,bc + inc hl + inc hl + jr l23f0h +l23c3h: + call sub_2579h +l23c6h: + ld a,028h + call OUTCHAR + comst + ld a,(iy+001h) + comend + jp l252bh +l23d5h: + call l23c6h + call sub_257ch +l23dbh: + ld a,041h + jp OUTCHAR +l23e0h: + call l2561h + call sub_257ch +l23e6h: + comst + ld l,(iy+001h) + ld h,(iy+002h) + comend +l23f0h: + ld a,002h +sub_23f2h: + ld (XBE03),a + ld (XBE01),hl + call out.hl + ret +l23fch: + call l254bh + call sub_257ch + jr l23e6h +l2404h: + call sub_24c6h + call sub_257ch + jp l253eh +l240dh: + call l253eh + call sub_257ch + jp sub_24c6h +l2416h: + call sub_24c6h + call sub_257ch + ld a,041h + jp OUTCHAR +l2421h: + call sub_2579h + jp sub_24c6h +l2427h: + ld a,030h + jr l2431h +l242bh: + ld a,031h + jr l2431h +l242fh: + ld a,032h +l2431h: + jp OUTCHAR +l2434h: + ld hl,b_0x2449_start + jr l2446h +l2439h: + ld hl,l244ch + jr l2446h +l243eh: + ld hl,l244fh + jr l2446h +l2443h: + ld hl,l2452h +l2446h: + jp PSTR + +b_0x2449_start: + DC 'I,A' +l244ch: + DC 'A,I' +l244fh: + DC 'R,A' +l2452h: + DC 'A,R' + +l2455h: + call l24dfh + call sub_257ch + ld hl,t__C_ + jp PSTR +l2461h: + ld hl,t__C_ + call PSTR + call sub_257ch + jp l24dfh +l246dh: + call l253eh + call sub_257ch + jp l254bh +l2476h: + call sub_24c6h + call sub_257ch + jp l254bh +l247fh: + call l254bh + call sub_257ch + jr sub_24c6h +l2487h: + ld a,(is.pfx.IXY) + and a + jr nz,l2496h + comst + ld a,(iy+001h) + comend + jr l249dh +l2496h: + comst + ld a,(iy+002h) + comend +l249dh: + push af + rra + rra + rra + and 007h + add a,'0' + call OUTCHAR + call sub_257ch + pop af + jr l24f2h +l24aeh: + ld a,(is.pfx.IXY) + and a + jr nz,l24bdh + comst + ld a,(iy+001h) + comend + jr l24c4h +l24bdh: + comst + ld a,(iy+002h) + comend +l24c4h: + jr l24f2h +sub_24c6h: + ld a,'(' + call OUTCHAR + comst + ld l,(iy+001h) + ld h,(iy+002h) + comend + ld a,001h + call sub_23f2h + ld a,')' + jp OUTCHAR +l24dfh: + comst + ld a,(iy+000h) + comend + rra + rra + rra + jr l24f2h +l24ebh: + comst + ld a,(iy+000h) + comend +l24f2h: + and 007h + cp 006h + jr nz,l2533h + ld a,(is.pfx.IXY) + and a + ld a,006h + jr z,l2533h + ld hl,b_0x2538_start + ld a,(is.pfx.IXY) + dec a + jr z,l250ch + ld hl,b_0x253B_start +l250ch: + call PSTR + comst + ld a,(iy+001h) + comend + and a + push af + jp m,l2523h + ld a,'+' + call OUTCHAR + pop af + jr l252bh +l2523h: + ld a,'-' + call OUTCHAR + pop af + neg +l252bh: + call out.hex + ld a,')' + jp OUTCHAR +l2533h: + ld hl,t_BCDEHL_HL_A + jr l2572h + +b_0x2538_start: + DC '(IX' +b_0x253B_start: + DC '(IY' + +l253eh: + ld a,(is.pfx.IXY) + ld hl,t_HL.IX.IY + jr l2572h +l2546h: + ld hl,t_BC.DE.HL.AF + jr l254eh +l254bh: + ld hl,t_BC.DE.HL.SP +l254eh: + comst + ld a,(iy+000h) + comend + rra + rra + rra + rra + and 003h + cp 002h + jr z,l253eh + jr l2572h +l2561h: + comst + ld a,(iy+000h) + comend +sub_2568h: + rra + rra + rra + and 007h + ld hl,t_tstfl_ZCPS + jr l2572h +l2572h: + ld b,a + call sub_0a48h + jp PSTR +sub_2579h: + call l23dbh +sub_257ch: + ld a,',' + jp OUTCHAR +sub_2581h: + call PSTR +l2584h: + call OUTBL + inc c + ld a,c + cp 006h + jr nz,l2584h + ret + +t_MNEMONICS: + DC 'ADC' + DC 'ADD' + DC 'AND' + DC 'BIT' + DC 'CALL' + DC 'CCF' + DC 'CP' + DC 'CPD' + DC 'CPDR' + DC 'CPI' + DC 'CPIR' + DC 'CPL' + DC 'DAA' + DC 'DEC' + DC 'DI' + DC 'DJNZ' + DC 'EI' + DC 'EX' + DC 'EXX' + DC 'HALT' + DC 'IM' + DC 'IN' + DC 'INC' + DC 'IND' + DC 'INDR' + DC 'INI' + DC 'INIR' + DC 'JP' + DC 'JR' + DC 'LD' + DC 'LDD' + DC 'LDDR' + DC 'LDI' + DC 'LDIR' + DC 'NEG' + DC 'NOP' + DC 'OR' + DC 'OTDR' + DC 'OTIR' + DC 'OUT' + DC 'OUTD' + DC 'OUTI' + DC 'POP' + DC 'PUSH' + DC 'RES' + DC 'RET' + DC 'RETI' + DC 'RETN' + DC 'RL' + DC 'RLA' + DC 'RLC' + DC 'RLCA' + DC 'RLD' + DC 'RR' + DC 'RRA' + DC 'RRC' + DC 'RRCA' + DC 'RRD' + DC 'RST' + DC 'SBC' + DC 'SCF' + DC 'SET' + DC 'SLA' + DC 'SRA' + DC 'SRL' + DC 'SUB' + DC 'XOR' + DC 'IN0' + DC 'MLT' + DC 'OTDM' + DC 'OTDMR' + DC 'OTIM' + DC 'OTIMR' + DC 'OUT0' + DC 'SLP' + DC 'TST' + DC 'TSTIO' + DB 0 + +t_BCDEHL_HL_A: + DC 'B' + DC 'C' + DC 'D' + DC 'E' + DC 'H' + DC 'L' + DC '(HL)' + DC 'A' + DB 0 +t_BC.DE.HL.SP: + DC 'BC' + DC 'DE' + DC 'HL' + DC 'SP' + DB 0 +t_BC.DE.HL.AF: + DC 'BC' + DC 'DE' +t_HL.AF: + DC 'HL' + DC 'AF' + DB 0 +t_BC.DE.IY.SP: + DC 'BC' + DC 'DE' + DC 'IY' + DC 'SP' + DB 0 +t_BC.DE.IX.SP: + DC 'BC' + DC 'DE' + DC 'IX' + DC 'SP' + DB 0 +t_HL.IX.IY: + DC 'HL' +t_IX.IY: + DC 'IX' + DC 'IY' + DB 0 +t_tstfl_ZC: + DC 'NZ' + DC 'Z' + DC 'NC' + DC 'C' + DC 'NE' + DC 'EQ' + DC 'GE' + DC 'LT' + DB 0 +t_tstfl_ZCPS: + DC 'NZ' + DC 'Z' + DC 'NC' + DC 'C' + DC 'PO' + DC 'PE' + DC 'P' + DC 'M' + DC 'NE' + DC 'EQ' + DC 'GE' + DC 'LT' + DC 'NV' + DC 'V' + DB 0 +t__C_: + DC '(C)' + DB 0 + +sub_26e7h: + ld hl,(REG.PC) + ld a,h + or l + jr z,l2715h + ld iy,(REG.PC) + call sub_1f9eh + jp nc,ERROR + ld c,b + ld b,000h + ld hl,(REG.PC) + add hl,bc + call sub_1117h + ld iy,(REG.PC) + ld hl,b_0x2717_start + call lookup_opc + ccf + ret c + ex de,hl + call CALL.HL + call c,sub_1117h +l2715h: + scf + ret + +b_0x2717_start: + db 0ffh + db 0ddh + db 000h + dw x278d + + db 0ffh + db 0fdh + db 000h + dw x2792 + + db 0ffh + db 0edh + db 000h + dw x27a2 + +l2726h: + db 0ffh + db 0cdh + db 000h + dw x275e + + db 0ffh + db 0c3h + db 000h + dw x2769 + + db 0ffh + db 0e9h + db 000h + dw x2788 + + db 0ffh + db 0c9h + db 000h + dw x27c9 + + db 0ffh + db 0cfh + db 000h + dw x280e + + db 0c7h + db 0c7h + db 000h + dw x27ea + + db 0c7h + db 0c4h + db 000h + dw x275e + + db 0f7h + db 010h + db 000h + dw x2775 + + db 0e7h + db 020h + db 000h + dw x2775 + + db 0c7h + db 0c2h + db 000h + dw x2769 + + db 0c7h + db 0c0h + db 000h + dw x27b3 + + db 000h + +x275e: + ld a,(XBFE8) + and a + jr nz,x2769 + ld a,(TCFLG) + and a + ret nz + +x2769: + comst + ld l,(iy+001h) + ld h,(iy+002h) + comend + scf + ret + +x2775: + comst + ld c,(iy+001h) + comend + ld a,c + rla + sbc a,a + ld b,a + ld hl,(REG.PC) + add hl,bc + inc hl + inc hl + scf + ret + +x2788: + ld hl,(REG.L) + scf + ret + +x278d: + ld hl,(reg.ix) + jr l2795h + +x2792: + ld hl,(reg.iy) +l2795h: + comst + ld a,(iy+001h) + comend + cp 0e9h + scf + ret z + and a + ret + +x27a2: + comst + ld a,(iy+001h) + comend + cp 04dh + jr z,x27c9 + cp 045h + jr z,x27c9 + and a + ret + +x27b3: + comst + ld a,(iy+000h) + comend + ld (XBEDD),a + ld hl,(REG.F) + push hl + pop af + call XBEDD + scf + jr c,x27c9 + ret + +x27c9: + ld a,(XBFE8) + and a + jr nz,l27dah + ld a,(TCFLG) + and a + jr z,l27dah + call l27dah + pop hl + ret +l27dah: + ld hl,(REG.SP) + comst + ld e,(hl) + inc hl + ld d,(hl) + comend + ex de,hl + call sub_1117h + and a + ret + +x27ea: + ld a,(ddtzrst) + comst + cp (iy+000h) + comend + ret z + comst + ld a,(iy+000h) + comend + and 038h + ld l,a + ld h,000h + ld a,(XBFE8) + and a + jr nz,l280ch + ld a,(TCFLG) + and a + ret nz +l280ch: + scf + ret + +x280e: + and a + ret + +CMD.C: + ld hl,CMD.C + ld a,001h + jr l281bh + +CMD.T: + xor a + ld hl,CMD.T +l281bh: + ld (CMD_RPT),hl + ld (TCFLG),a + ld a,(de) + sub 'N' + jr nz,l2827h + inc de +l2827h: + ld (TCNFLG),a + ld a,(de) + sub 'J' + jr nz,l2830h + inc de +l2830h: + ld (TRJFLG),a + call sub_289fh + jr z,l283eh + ld hl,1 + call get_lastarg_def +l283eh: + ld (TCCSTR),hl + sub a + ld (XA747),a +l2845h: + call sub_26e7h + jr l289ch +l284ah: + call sub_0e68h + ld a,(TRJFLG) + and a + jr nz,l2864h + ld iy,(REG.PC) + call sub_28c1h + jr z,l2864h + ld hl,l2726h + call lookup_opc + jr nc,l2845h +l2864h: + ld a,(XBFEA) + and a + jr z,l2881h + ld de,(TCCSTR) + call EXPR + ld a,h + or l + add a,0ffh + sbc a,a + ld hl,XBFEA + xor (hl) + bit 1,a + jr z,l288ch +l287eh: + jp l102eh +l2881h: + ld hl,(TCCSTR) + dec hl + ld (TCCSTR),hl + ld a,h + or l + jr z,l287eh +l288ch: + call sub_26e7h + jr nc,l287eh + ld a,(TCNFLG) + ld b,a + ld a,(XA747) + or b + ld (XA747),a +l289ch: + jp l1183h + +sub_289fh: + call SKIPBL + xor a + ld (XBFEA),a + ld a,(de) + cp 'U' + jr z,l28aeh + cp 'W' + ret nz + +l28aeh: + inc de + push af + push de + call EXPR + jp c,ERROR + call assert_eol + pop hl + pop af + ld (XBFEA),a + sub a + ret + +sub_28c1h: + comst + ld a,(iy+000h) + ld b,(iy+0001) + comend + cp 0edh + jr z,l28dbh + and 0dfh + cp 0ddh + ret nz + ld a,b + cp 0e9h + ret +l28dbh: + ld a,b + and 0f7h + cp 045h + ret + +?excom: + ex (sp),hl + push af + push bc + push de + ld c,(hl) + ld b,000h + inc hl + ld a,?lcmax + sub c + ld de,?exeit + ldir + ex de,hl + ld (hl),018h + inc hl + ld (hl),a + ex de,hl + pop de + pop bc + pop af + ex (sp),hl + if CPU_Z180 + push hl + ld hl,(ubbr) + + else + push af + ld a,(ubnk) + endif + if ROMSYS + push af + ld a,(uromen) + endif + jp ?comcod + +;------------------------------------------ +; ddtram +;------------------------------------------ + +vartab: +; dseg + cseg +ddtram: +;todo: +; The following 2 params are changeable by user. +; Should these moved to top ram? +; +ddtzrst: + rst DDTZRSTVEC ;rst used by ddtz +ddtei: ei ;ints enabled/disabled while ddtz is running + ret ; +offs.pc: + dw TPA +offs.@: + dw 0 +CMD_ERR: + dw 0 +CMD_RPT: + dw DDTZML +ci.buf: + db 80 + rept 83 + db 0 + endm +CON.COL: + db 0 +XA747: + db 0 +bp_tab: + rept BP_CNT + db 0,0 + dw 0,0,0 + endm +BP_SIZE equ 8 +sexp1: + dw sexpbuf +sexp2: + dw sexpbuf +sexpbuf: + rept 128 + db 0 + endm +sexpbufe: + +msg.Y: + dc 'Y0' +reg.Y: + rept 10 + dw 0 + endm +lst.S: + dw 0 +lst.IP: + dw 0 +lst.OP: + dw 0 +lst.OD: + db 0 +lst.Qj: + db 0 +lst.D: + dw 0 +HILOD: + dw 0 +MAXLOD: + dw 0 +XB068: + dw 0 +lst.A: + dw 0 +XB06C: + dw 0 +pfx.IXY: + db 000h +is.pfx.IXY: + db 000h +lst.L: + dw 0 +XBE01: + dw 0 +XBE03: + db 000h +XBEDD: + ret ;ret cc + and a + pop hl + inc hl + jp (hl) +XBFE8: + db 0 +TCFLG: + db 0 +XBFEA: + db 0 +TCCSTR: + dw 0 +TCNFLG: + db 0 +TRJFLG: + db 0 +wstrtflg: + db 1 + + cseg +vartabe: + +;------------------------------------------ + + .phase sysram_start+bs$stack$size +$stack: +$stcka equ $ - bs$stack$size + +curphse defl $ + .dephase +sysramc: + .phase curphse +topcodbeg: + +reg.l2: db 0 ; 0fe50h +reg.h2: db 0 ; 0fe51h +reg.e2: db 0 ; 0fe52h +reg.d2: db 0 ; 0fe53h +reg.c2: db 0 ; 0fe54h +reg.b2: db 0 ; 0fe55h +reg.f2: db 0 ; 0fe56h +reg.a2: db 0 ; 0fe57h + db 0 +reg.i: db high ivtab +reg.iy: dw 0 ; 0fe5ah +reg.ix: dw 0 ; 0fe5ch +reg.e: db 0 ; 0fe5eh +reg.d: db 0 ; 0fe5fh +reg.c: db 0 ; 0fe60h +reg.b: db 0 ; 0fe61h + if ROMSYS +udcntl: db CWAITIO ; 0fe62h (mem-, io- wait) +uromen: db ROM_DIS ; 0fe63h + endif + if CPU_Z180 +ubbr: db 0 ; 0fe64h +ucbar: db USR$CBAR ; 0fe65h + else + db 0 ; 0fe64h +ubnk: db 0 ; 0fe65h + endif +reg.f: db 0 ; 0fe66h +reg.a: db 0 ; 0fe67h +reg.l: db 0 ; 0fe68h +reg.h: db 0 ; 0fe69h +reg.sp: dw TOPRAM ; 0fe6ah + +$go: + if ROMSYS + out (000h),a ;064c fe6c + out0 (dcntl),l + pop hl + endif + if CPU_Z180 + out0 (cbar),h + out0 (bbr),l + else + ld a,h + call selbnk + endif + pop af + pop hl + ld sp,(reg.sp) +reg.iff: + ei + db 0C3h ;jp TPA ;065f feff ($+1): reg.pc +reg.pc: + dw TPA + +bpent: + ld (reg.l),hl ;0662 fe82: bpent: + pop hl + dec hl + ld (reg.pc),hl + ld (reg.sp),sp + ld sp,reg.l + push af + if CPU_Z180 +;;; TODO: cbar on trap? + in0 h,(cbar) + in0 l,(bbr) + ld a,SYS$CBAR + out0 (cbar),a + else + ld a,(@cbnk) + ld h,a + xor a + ld l,a + call selbnk + endif + push hl + + if ROMSYS + in0 l,(dcntl) + ld a,CWAITROM+CWAITIO + out0 (dcntl),a + ld a,($crom) + cp c$rom + ld a,ROM_EN + out (000h),a + endif + + jp bpddtz + +?comcod: + if ROMSYS + out (000h),a ;0692 feb2 + pop af + endif + + if CPU_Z180 + out0 (cbar),h + out0 (bbr),l + pop hl + else + call selbnk + pop af + endif +?exeit: + ds ?lcmax+2 + push af + if CPU_Z180 + ld a,SYS$CBAR + out0 (cbar),a + +;;; TODO: bbr? + else + xor a + call selbnk + endif + if ROMSYS + ld a,ROM_EN + out (000h),a + endif + + pop af + ret + +topcodend: +curph defl $ + .dephase +sysrame: + + end diff --git a/z180/fifoio.180 b/z180/fifoio.180 new file mode 100644 index 0000000..cbcece9 --- /dev/null +++ b/z180/fifoio.180 @@ -0,0 +1,128 @@ + page 255 + .z80 + +; +; FIFO channels for communication with stm32 +; + global f.init,f.in,f.out,f.i.st + + extrn buf.init + + include config.inc + include z180reg.inc + + +;-------------------------------------------------------------- + + dseg + + + mkbuf ci.fifo_id, rx.buf,rx.buf_len + mkbuf co.fifo_id, tx.buf,tx.buf_len + + +;-------------------------------------------------------------- + + cseg + +; Init Serial I/O for console input and output +; + +f.init: + ld ix,rx.buf + ld a,rx.buf.mask + call buf.init + ld ix,tx.buf + ld a,tx.buf.mask + jp buf.init + + +f.i.st: + push ix + ld ix,rx.buf ; + +buf.empty: + ld a,(ix+o.in_idx) ; + sub (ix+o.out_idx) ; + pop ix + ret z + or 0ffh + ret + + +f.in: + push ix + ld ix,rx.buf ; + +buf.get: + ld a,(ix+o.out_idx) ; +bg.wait: + cp (ix+o.in_idx) ; + jr z,bg.wait + + push hl ; + push ix + pop hl + add a,l + ld l,a + jr nc,bg.nc + inc h +bg.nc: + ld l,(hl) + + ld a,(ix+o.out_idx) ; + inc a + and (ix+o.mask) + ld (ix+o.out_idx),a + + ld a,l + pop hl + pop ix + ret + + +f.o.st: + push ix + ld ix,tx.buf ; + +buf.full: + ld a,(ix+o.in_idx) ; + inc a + and (ix+o.mask) + sub (ix+o.out_idx) ; + pop ix + ret z + or 0ffh + ret + + +f.out: + push ix + ld ix,tx.buf ; + +buf.put: + push hl ; + push bc + push ix + pop hl + ld c,(ix+o.in_idx) ; + ld b,0 + add hl,bc + ld b,a + + ld a,c ; + inc a + and (ix+o.mask) +bp.wait: + cp (ix+o.out_idx) ; + jr z,bp.wait + ld (hl),b + ld (ix+o.in_idx),a + + ld a,b + pop bc + pop hl + pop ix + ret + + end diff --git a/z180/init-80.180 b/z180/init-80.180 new file mode 100644 index 0000000..8b71993 --- /dev/null +++ b/z180/init-80.180 @@ -0,0 +1,591 @@ + page 255 + .z80 + + extrn ddtz,bpent + extrn $stack + extrn charini,?const,?conin + extrn ?cono,?conos + + extrn romend + + global iobyte + global isv_sw + + include config.inc + + + + +;---------------------------------------------------------------------- + + cseg +romstart equ $ + + org romstart+0 + jp start + +iobyte: db 0 + +; restart vectors + +rsti defl 1 + rept 7 + + org 8*rsti + romstart + jp bpent +rsti defl rsti+1 + endm + +;---------------------------------------------------------------------- + + org romstart+40h + + dw 0 + db 0 + + cseg + + if ROMSYS +$crom: defb c$rom ; + else + db 0 ; + endif + + +hwini0: + db 0 ;count +; db rcr,CREFSH ;configure DRAM refresh +; db dcntl,INIWAITS ;wait states +; db cbar,SYS$CBAR + + +;---------------------------------------------------------------------- + + org romstart+50h + +start: + jp cstart + jp wstart + jp ?const + jp ?conin + jp ?cono + jp ?conos + jp charini + +cstart: + di + + xor a + ld (@cbnk),a + +; search warm start mark + + ld ix,mark_55AA ; top of common area + ld a,0aah ; + cp (ix+000h) ; + jr nz,kstart ; + cp (ix+002h) ; + jr nz,kstart ; + cpl ; + cp (ix+001h) ; + jr nz,kstart ; + cp (ix+003h) ; + jr nz,kstart ; + ld sp,$stack ; mark found, check +; call checkcrc_alv ; + jp z,wstart ; check ok, + +; +; ram not ok, initialize -- kstart -- + +kstart: + ld sp,$stack ;01e1 + +; Clear RAM + +; Init bank manager + +;---------------------------------------------------------------------- +; + + ld hl,055AAh ;set warm start mark + ld (mark_55AA),hl ; + ld (mark_55AA+2),hl; + +; +; -- wstart -- +; +wstart: + call sysram_init ;027f + call ivtab_init + + call charini + call bufferinit + + ld c,0 + call selbnk + + + im 2 ;?030e + ei ;0282 + + call ?const ;0284 + call ?const ;0287 + or a ;028a + call nz,?conin ;028d + +;;; ld a,(banktab) ; +;;; ld e,a ; + jp ddtz ;0290 + + +;---------------------------------------------------------------------- +; + +;TODO: Make a ringbuffer module. + + global buf.init + +buf.init: + ld (ix+o.in_idx),0 + ld (ix+o.out_idx),0 + ld (ix+o.mask),a + ret + +;---------------------------------------------------------------------- + + + extrn msginit,msg.sout + extrn mtx.fifo,mrx.fifo + extrn co.fifo,ci.fifo + + +bufferinit: + call msginit + + ld hl,buffers + ld b,buftablen +bfi_1: + ld a,(hl) + inc hl + ld (bufdat+0),a + ld e,(hl) + inc hl + ld d,(hl) + inc hl + ex de,hl + + or a + jr nz,bfi_2 + + ld a,(@cbnk) + call bnk2phys + + ld (40h+0),hl + ld (40h+2),a + out (AVRINT5),a + jr bfi_3 +bfi_2: + + ld a,(@cbnk) + call bnk2phys + + ld (bufdat+1),hl + ld (bufdat+3),a + ld hl,inimsg + call msg.sout +bfi_3: + ex de,hl + djnz bfi_1 + ret + + +buffers: + db 0 + dw mtx.fifo + db 1 + dw mrx.fifo + db 2 + dw co.fifo + db 3 + dw ci.fifo +buftablen equ ($ - buffers)/3 + +inimsg: + db inimsg_e - $ -1 + db 0AEh + db inimsg_e - $ -1 + db 0 +bufdat: + db 0 + dw 0 + db 0 +inimsg_e: + + +; +;---------------------------------------------------------------------- +; + +bnk2phys: + sla h + jr nc,b2p_1 ;A15=1 --> common + ld a,3 +b2p_1: + srl a + rr h + ret + +; +;---------------------------------------------------------------------- +; + +sysram_init: + ld hl,sysramw + ld de,topcodsys + ld bc,sysrame-sysramw + ldir + + ret + +;---------------------------------------------------------------------- + +ivtab_init: + ld hl,ivtab ; + ld a,h ; + ld i,a ; +; out0 (il),l ; + +; Let all vectors point to spurious int routines. + + ld d,high sp.int0 + ld a,low sp.int0 + ld b,9 +ivt_i1: + ld (hl),a + inc l + ld (hl),d + inc l + add a,sp.int.len + djnz ivt_i1 + ret + +;---------------------------------------------------------------------- +; + + global io.ini + +io.ini: + push bc + + if CPU_Z180 + + ld b,0 ;high byte port adress + ld a,(hl) ;count + inc hl + or a + jr z,ioi_e +ioi_1: + ld c,(hl) ;port address + inc hl + outi + inc b ;outi decrements b + dec a + jr nz,ioi_1 + + else + jr ioi_nxt +ioi_l: + ld c,(hl) ;port address + inc hl + otir +ioi_nxt: + ld b,(hl) ;count + inc hl + inc b + djnz ioi_l + endif +ioi_e: + pop bc + ret + + if CPU_Z180 +io.ini.m: + push bc + ld b,(hl) + inc hl + ld c,(hl) + inc hl + otimr + pop bc + ret + endif + +io.ini.l: +; + + +;---------------------------------------------------------------------- +; +;return: +; hl = hl + a +; Flags undefined +; + +add_hl_a: + add a,l + ld l,a + ret nc + inc h + ret + +; --------------------------------------------------------- + +sysramw: + + .phase isvsw_loc +topcodsys: + +; Trampoline for interrupt routines in banked ram. +; Switch stack pointer to "system" stack in top ram + +; todo: z80 bank switch + +isv_sw: ; + ex (sp),hl ; save hl, return adr in hl + push de ; + push af ; + ex de,hl ; + ld hl,0 ; + add hl,sp ; + ld a,h ; + cp 0f8h ; + jr nc,isw_1 ; + ld sp,$stack ; +isw_1: + push hl ; + ; save current bank +; in0 h,(cbar) ; + push hl ; + ; switch to system bank +; ld a,SYS$CBAR ; +; out0 (cbar),a ; + ex de,hl ; + ld e,(hl) ; + inc hl ; + ld d,(hl) ; + ex de,hl ; + push bc ; + call jphl ; + + pop bc ; + pop hl ; restore bank +; out0 (cbar),h ; + pop hl ; + ld sp,hl ; + pop af ; + pop de ; + pop hl ; + ei ; + ret ; +jphl: + jp (hl) ; + +; --------------------------------------------------------- + +sp.int0: + ld a,0d0h + jr sp.i.1 +sp.int.len equ $-sp.int0 + ld a,0d1h + jr sp.i.1 + ld a,0d2h + jr sp.i.1 + ld a,0d3h + jr sp.i.1 + ld a,0d4h + jr sp.i.1 + ld a,0d5h + jr sp.i.1 + ld a,0d6h + jr sp.i.1 + ld a,0d7h + jr sp.i.1 + ld a,0d8h +sp.i.1: +; out (80h),a + halt + +; --------------------------------------------------------- + +; Get IFF2 +; This routine may not be loaded in page zero +; +; return Carry clear, if INTs are enabled. +; + global getiff +getiff: + xor a ;clear accu and carry + push af ;stack bottom := 00xxh + pop af + ld a,i ;P flag := IFF2 + ret pe ;exit carry clear, if enabled + dec sp + dec sp ;has stack bottom been overwritten? + pop af + and a ;if not 00xxh, INTs were + ret nz ;actually enabled + scf ;Otherwise, they really are disabled + ret + +;---------------------------------------------------------------------- + + global selbnk + +; a: bank (0..2) + +selbnk: + push bc + ld c,a + call getiff + push af + + ld a,c + di + ld (@cbnk),a + ld a,5 + out (SIOAC),a + ld a,(mm_sio0) + rla + srl c + rra + out (SIOAC),a + ld (mm_sio0),a + + ld a,5 + out (SIOBC),a + ld a,(mm_sio1) + rla + srl c + rra + out (SIOBC),a + ld (mm_sio1),a + pop af + pop bc + ret c ;INTs were disabled + ei + ret + +;---------------------------------------------------------------------- + +; c: bank (0..2) + + if 0 + +selbnk: + ld a,(@cbnk) + xor c + and 3 + ret z ;no change + + call getiff + push af + ld a,c + di + ld (@cbnk),a + ld a,5 + out (SIOAC),a + ld a,(mm_sio0) + rla + srl c + rra + out (SIOAC),a + ld (mm_sio0),a + + ld a,5 + out (SIOBC),a + ld a,(mm_sio1) + rla + srl c + rra + out (SIOBC),a + ld (mm_sio1),a + pop af + ret nc ;INTs were disabled + ei + ret + + endif + +;---------------------------------------------------------------------- + + if 0 + ex af,af' + push af + ex af,af' + + rra + jr nc,stbk1 + ex af,af' + ld a,5 + out (SIOAC),a + ld a,(mm_sio0) + rla + srl c + rra + out (SIOAC),a + ld (mm_sio1),a + ex af,af' + +stbk1: + rra + jr nc,stbk2 + ex af,af' + ld a,5 + out (SIOBC),a + ld a,(mm_sio1) + rla + srl c + rra + out (SIOBC),a + ld (mm_sio1),a + ex af,af' + +stbk2: + endif + + global @cbnk + global mm_sio0, mm_sio1 + +@cbnk: db 0 ; current bank (0..2) +mm_sio0: + ds 1 +mm_sio1: + ds 1 + +;---------------------------------------------------------------------- + +curph defl $ + .dephase +sysrame: + .phase curph +tim_ms: db 0 +tim_s: dw 0 + .dephase + +;----------------------------------------------------- + + cseg + + ;.phase 0ffc0h +;ivtab equ 0ffc0h ; 0ffc0h ;int vector table + ;.dephase + + ;.phase 0fffch +mark_55AA equ 0fffch + ;ds 4 ; 0fffch + ;.dephase + + + end + diff --git a/z180/init.180 b/z180/init.180 new file mode 100644 index 0000000..05c24ff --- /dev/null +++ b/z180/init.180 @@ -0,0 +1,913 @@ + page 255 + .z80 + + extrn ddtz,bpent + extrn $stack + extrn charini,?const,?conin + extrn ?cono,?conos + extrn romend + + + global iobyte + global isv_sw + + include config.inc + if CPU_Z180 + include z180reg.inc + include z180.lib + endif + + + + +;---------------------------------------------------------------------- + + cseg +romstart equ $ + + org romstart+0 + jp start + +iobyte: db 2 + +; restart vectors + +rsti defl 1 + rept 7 + org 8*rsti + romstart + jp bpent +rsti defl rsti+1 + endm + +;---------------------------------------------------------------------- +; Config space +; + + org romstart+40h + + dw 0 + db 0 + + + if ROMSYS +$crom: defb c$rom ; + else + db 0 ; + endif + +INIWAITS defl CWAITIO + if ROMSYS +INIWAITS defl INIWAITS+CWAITROM + endif + +;---------------------------------------------------------------------- + + org romstart+50h +start: + jp cstart + jp wstart + jp ?const + jp ?conin + jp ?cono + jp ?conos + jp charini + +;---------------------------------------------------------------------- + +hwini0: + if CPU_Z180 + db ;count + db rcr,CREFSH ;configure DRAM refresh + db dcntl,INIWAITS ;wait states + db cbr,SYS$CBR + db cbar,SYS$CBAR + endif + db 0 + + if CPU_Z180 +dmclrt: ;clear ram per dma + db dmct_e-dmclrt-2 ; + db sar0l ;first port + dw nullbyte ;src (fixed) +nullbyte: + db 000h ;src + dw romend ;dst (inc), start after "rom" code + db 00h ;dst + dw 0-romend ;count (64k) +dmct_e: + db 0 + endif + + +cstart: + if CPU_Z180 + + push af + in0 a,(itc) ;Illegal opcode trap? + jp m,??st01 + ld a,i ;I register == 0 ? + jr z,hw_reset ; yes, harware reset + +??st01: + ; TODO: SYS$CBR + ld a,(syscbr) + out0 (cbr),a + pop af ;restore registers + jp bpent ; + +hw_reset: + di ;0058 + ld a,CREFSH + out0 (rcr),a ; configure DRAM refresh + ld a,CWAITIO + out0 (dcntl),a ; wait states + + ld a,M_NCD ;No Clock Divide + out0 (ccr),a +; ld a,M_X2CM ;X2 Clock Multiplier +; out0 (cmr),a + else + di + xor a + ld (@cbnk),a + endif + +; check warm start mark + + ld ix,mark_55AA ; top of common area + ld a,0aah ; + cp (ix+000h) ; + jr nz,kstart ; + cp (ix+002h) ; + jr nz,kstart ; + cpl ; + cp (ix+001h) ; + jr nz,kstart ; + cp (ix+003h) ; + jr nz,kstart ; + ld sp,$stack ; mark found, check + jp z,wstart ; check ok, + +; ram not ok, initialize -- kstart -- + +kstart: + if CPU_Z180 + ld a,SYS$CBR ;TODO: + out0 (cbr),a + ld a,SYS$CBAR + out0 (cbar),a + endif + + ld sp,$stack ;01e1 + +; Clear RAM using DMA0 + + if CPU_Z180 + if 0 + + ld hl,dmclrt ;load DMA registers + call ioiniml + ld a,0cbh ;01ef dst +1, src fixed, burst + out0 (dmode),a ;01f1 + + ld b,512/64 + ld a,062h ;01f4 enable dma0, +??cl_1: + out0 (dstat),a ;01f9 clear (up to) 64k + djnz ??cl_1 ; end of RAM? + + endif + endif + + ld hl,055AAh ;set warm start mark + ld (mark_55AA),hl + ld (mark_55AA+2),hl + +; -- wstart -- + +wstart: + call sysram_init + call ivtab_init + if CPU_Z180 +; call prt0_init + endif + + call msginit + call charini + + if CPU_Z80 + ld a,0 + call selbnk + endif + + ld a,INIDONEVAL ;tell others (CP/M) that hardware and fifos + ld (INIDONE),a ; are allready initialized + + im 2 + ei + + call ?const + call ?const + or a + call nz,?conin + + if CPU_Z180 + ld e,0 ;Sys$Bank + else +; TODO: + endif + jp ddtz + + + if CPU_Z180 +; TODO: SYS$CBR +syscbr: db 0 + endif + +; +;---------------------------------------------------------------------- +; + + global bufinit + +bufinit: + ld (ix+o.in_idx),0 ;reset pointers (empty fifo) + ld (ix+o.out_idx),0 + ld a,(ix+o.id) + ld hl,fifolst + ld e,a + ld d,0 + add hl,de + add hl,de + push ix + pop de + cp 4 + jr nc,bfi_skip + + ld (hl),e + inc hl + ld (hl),d + +bfi_skip: + ex de,hl + call hwl2phy ;get phys. address of fifo + ld c,a + ld a,(ix+o.id) ;fifo id + or a ;test if fifo 0 + ret z + + ld b,a + push bc ;c: bank-addr, b: ignored + push hl ;address + ld c,0 + push bc ;c: function, b:subf + ld b,5 + ld h,c + ld l,c + add hl,sp + call msg.sm + pop hl + pop hl + pop hl + ret + + public fifolst +fifolst : + rept 4 + dw 0 + endm + +;---------------------------------------------------------------------- + + extrn msg.sm + extrn msginit,msg.sout + extrn mtx.fifo,mrx.fifo + extrn ff.init,co.fifo,ci.fifo + + +fifoinit: + if CPU_Z180 + + ret + + else ;CPU_Z180 + + call msginit + + ld hl,buffers + ld b,buftablen +bfi_1: + ld a,(hl) + inc hl + ld (bufdat+0),a + ld e,(hl) + inc hl + ld d,(hl) + inc hl + ex de,hl + + or a + jr nz,bfi_2 + + ld a,(@cbnk) + call bnk2phy + + ld (40h+0),hl + ld (40h+2),a + out (AVRINT5),a + jr bfi_3 +bfi_2: + + ld a,(@cbnk) + call bnk2phy + + ld (bufdat+1),hl + ld (bufdat+3),a + ld hl,inimsg + call msg.sout +bfi_3: + ex de,hl + djnz bfi_1 + ret + endif + + + + +; +;---------------------------------------------------------------------- +; + +sysram_init: + ld hl,sysramw + ld de,topcodsys + ld bc,sysrame-sysramw + ldir + + ret + +;---------------------------------------------------------------------- + +ivtab_init: + ld hl,ivtab ; + ld a,h ; + ld i,a ; + if CPU_Z180 + out0 (il),l ; + endif + +; Let all vectors point to spurious int routines. + + ld d,high sp.int0 + ld a,low sp.int0 + ld b,9 +ivt_i1: + ld (hl),a + inc l + ld (hl),d + inc l + add a,sp.int.len + djnz ivt_i1 + ret + +;---------------------------------------------------------------------- + +; Reload value for 10 ms Int. (0.1KHz): +; tc10ms = phi/prescale/0.1KHz = phi / (prescale/10) + +PRT_TC10MS equ 18432 / (PRT_PRE/10) + + + if CPU_Z180 +prt0_init: + ld a,i + ld h,a + in0 a,(il) + and 0E0h + or IV$PRT0 + ld l,a + ld (hl),low iprt0 + inc hl + ld (hl),high iprt0 + ld hl,prt0itab + call ioiniml + ret + +prt0itab: + db prt0it_e-prt0itab-2 + db tmdr0l + dw PRT_TC10MS + dw PRT_TC10MS + db M_TIE0+M_TDE0 ;enable timer 0 interrupt and down count. +prt0it_e: + db 0 + endif + + +; +;---------------------------------------------------------------------- +; + + if CPU_Z180 +io.ini: + if 0 + push bc + ld b,0 ;high byte port adress +ioi_nxt: + ld a,(hl) ;count + inc hl + or a + jr z,ioi_e + + ld c,(hl) ;port address + inc hl +ioi_r: + outi + inc b ;outi decrements b + dec a + jr nz,ioi_r + jr ioi_nxt +ioi_e: + pop bc + ret + + else ;(if 1/0) + + push bc + jr ioi_nxt +ioi_l: + ld c,(hl) ;port address + inc hl + inc c +ioi_r: + dec c ;otim increments c + otim + jr z,ioi_r +ioi_nxt: + ld b,(hl) ;count + inc hl + inc b ;stop if count == 0 + djnz ioi_l + pop bc + ret + + endif ;(1/0) + + else + +io.ini: + push bc + jr ioi_nxt +ioi_l: + ld c,(hl) ;port address + inc hl + otir +ioi_nxt: + ld b,(hl) ;count + inc hl + inc b + djnz ioi_l + endif + pop bc + ret + +;---------------------------------------------------------------------- + + if CPU_Z180 + + global ioiniml + +ioiniml: + push bc + xor a +ioml_lp: + ld b,(hl) + inc hl + cp b + jr z,ioml_e + + ld c,(hl) + inc hl + otimr + jr ioml_lp +ioml_e: + pop bc + ret z + endif + +io.ini.l: +; + + + +;---------------------------------------------------------------------- +; + if CPU_Z180 + +;-------------------------------------------------------------------- +; Return the BBR value for the given bank number +; +; in a: Bank number +; out a: bbr value + +bnk2log: + or a ; + ret z ; Bank 0 is at physical address 0 + + push bc ; + ld b,a ; + ld c,CA ; + mlt bc ; + ld a,c ; + add a,10h ; + pop bc ; + ret ; + +;-------------------------------------------------------------- + +;in hl: Log. Address +; a: Bank number +; +;out ahl: Phys. (linear) Address + + +bnk2phy: + call bnk2log + ; fall thru + +;-------------------------------------------------------------- +; +; hl: Log. Address +; a: Bank base (bbr) +; +; 2 0 0 +; 0 6 8 0 +; hl hhhhhhhhllllllll +; a + bbbbbbbb +; +; OP: ahl = (a<<12) + (h<<8) + l +; +;out ahl: Phys. (linear) Address + +log2phy: + push bc ; +l2p_i: + ld c,a ; + ld b,16 ; + mlt bc ; bc = a<<4 + ld a,c ; + add a,h ; + ld h,a ; + ld a,b ; + adc a,0 ; + pop bc ; + ret ; + +;-------------------------------------------------------------- +; +; hl: Log. Address +; +; +; OP: ahl = (bankbase<<12) + (d<<8) + e +; +;out ahl: Phys. (linear) Address + + public hwl2phy + +hwl2phy: + push bc ; + in0 c,(cbar) ; + ld a,h ; + or 00fh ; log. addr in common1? + cp c + jr c,hlp_1 + + in0 a,(cbr) ; yes, cbr is address base + jr hl2p_x +hlp_1: + ld b,16 ; log. address in baked area? + mlt bc + ld a,h + cp c + jr c,hlp_2 + in0 a,(bbr) ; yes, bbr is address base + jr hl2p_x +hlp_2: + xor a ; common1 +hl2p_x: + jr nz,l2p_i + + pop bc ; bank part is 0, no translation + ret ; + + + + else ;CPU_Z180 + +;---------------------------------------------------------------------- +; + +bnk2phy: + sla h + jr nc,b2p_1 ;A15=1 --> common + ld a,3 +b2p_1: + srl a + rr h + ret + + endif + +;-------------------------------------------------------------- +; +;return: +; hl = hl + a +; Flags undefined +; + +add_hl_a: + add a,l + ld l,a + ret nc + inc h + ret + +; --------------------------------------------------------- + +sysramw: + + .phase isvsw_loc +topcodsys: + +; Trampoline for interrupt routines in banked ram. +; Switch stack pointer to "system" stack in top ram +; Save cbar + +isv_sw: ; + ex (sp),hl ;save hl, 'return adr' in hl + push de ; + push af ; + ex de,hl ;'return address' in de + ld hl,0 ; + add hl,sp ; + ld a,h ; + cp 0f8h ; + jr nc,isw_1 ;stack allready in top ram + ld sp,$stack ; +isw_1: + push hl ;save user stack pointer + in0 h,(cbar) ; + push hl ; + ld a,SYS$CBAR ; + out0 (cbar),a ; + ex de,hl ; + ld e,(hl) ; + inc hl ; + ld d,(hl) ; + ex de,hl ; + push bc ; + call jphl ; + + pop bc ; + pop hl ; + out0 (cbar),h ; + pop hl ; + ld sp,hl ; + pop af ; + pop de ; + pop hl ; + ei ; + ret ; +jphl: + jp (hl) ; + +; --------------------------------------------------------- + + if CPU_Z180 + +iprt0: + push af + push hl + in0 a,(tcr) + in0 a,(tmdr0l) + in0 a,(tmdr0h) + ld a,(tim_ms) + inc a + cp 100 + jr nz,iprt_1 + xor a + ld hl,(tim_s) + inc hl + ld (tim_s),hl +iprt_1: + ld (tim_ms),a + pop hl + pop af + ei + ret + + endif + +; --------------------------------------------------------- + +sp.int0: + ld a,0d0h + jr sp.i.1 +sp.int.len equ $-sp.int0 + ld a,0d1h + jr sp.i.1 + ld a,0d2h + jr sp.i.1 + ld a,0d3h + jr sp.i.1 + ld a,0d4h + jr sp.i.1 + ld a,0d5h + jr sp.i.1 + ld a,0d6h + jr sp.i.1 + ld a,0d7h + jr sp.i.1 + ld a,0d8h +sp.i.1: +; out (80h),a + halt + +; --------------------------------------------------------- + + if CPU_Z80 + +; Get IFF2 +; This routine may not be loaded in page zero +; +; return Carry clear, if INTs are enabled. +; + global getiff +getiff: + xor a ;clear accu and carry + push af ;stack bottom := 00xxh + pop af + ld a,i ;P flag := IFF2 + ret pe ;exit carry clear, if enabled + dec sp + dec sp ;has stack bottom been overwritten? + pop af + and a ;if not 00xxh, INTs were + ret nz ;actually enabled + scf ;Otherwise, they really are disabled + ret + +;---------------------------------------------------------------------- + + global selbnk + +; a: bank (0..2) + +selbnk: + push bc + ld c,a + call getiff + push af + + ld a,c + di + ld (@cbnk),a + ld a,5 + out (SIOAC),a + ld a,(mm_sio0) + rla + srl c + rra + out (SIOAC),a + ld (mm_sio0),a + + ld a,5 + out (SIOBC),a + ld a,(mm_sio1) + rla + srl c + rra + out (SIOBC),a + ld (mm_sio1),a + pop af + pop bc + ret c ;INTs were disabled + ei + ret + +;---------------------------------------------------------------------- + +; c: bank (0..2) + + if 0 + +selbnk: + ld a,(@cbnk) + xor c + and 3 + ret z ;no change + + call getiff + push af + ld a,c + di + ld (@cbnk),a + ld a,5 + out (SIOAC),a + ld a,(mm_sio0) + rla + srl c + rra + out (SIOAC),a + ld (mm_sio0),a + + ld a,5 + out (SIOBC),a + ld a,(mm_sio1) + rla + srl c + rra + out (SIOBC),a + ld (mm_sio1),a + pop af + ret nc ;INTs were disabled + ei + ret + + endif + +;---------------------------------------------------------------------- + + if 0 + ex af,af' + push af + ex af,af' + + rra + jr nc,stbk1 + ex af,af' + ld a,5 + out (SIOAC),a + ld a,(mm_sio0) + rla + srl c + rra + out (SIOAC),a + ld (mm_sio1),a + ex af,af' + +stbk1: + rra + jr nc,stbk2 + ex af,af' + ld a,5 + out (SIOBC),a + ld a,(mm_sio1) + rla + srl c + rra + out (SIOBC),a + ld (mm_sio1),a + ex af,af' + +stbk2: + endif + + global @cbnk + global mm_sio0, mm_sio1 + +@cbnk: db 0 ; current bank (0..2) +mm_sio0: + ds 1 +mm_sio1: + ds 1 + + + endif + +;---------------------------------------------------------------------- + +curph defl $ + .dephase +sysrame: + .phase curph +tim_ms: db 0 +tim_s: dw 0 + .dephase + +;----------------------------------------------------- + + + cseg + + ;.phase 0ffc0h +;ivtab equ 0ffc0h ; 0ffc0h ;int vector table + ;.dephase + + ;.phase 0fffah +mark_55AA equ 0 - 2 - 4 ;2 byte for trap stack + ;ds 4 + ;.dephase + + + end diff --git a/z180/modebaud.inc b/z180/modebaud.inc new file mode 100644 index 0000000..2e60e44 --- /dev/null +++ b/z180/modebaud.inc @@ -0,0 +1,31 @@ + ; equates for mode byte bit fields + +mb$input equ 00000001b ; device may do input +mb$output equ 00000010b ; device may do output +mb$in$out equ mb$input+mb$output + +mb$soft$baud equ 00000100b ; software selectable + ; baud rates + +mb$serial equ 00001000b ; device may use protocol +mb$xon$xoff equ 00010000b ; XON/XOFF protocol + ; enabled + +baud$none equ 0 ; no baud rate associated + ; with this device +baud$50 equ 1 ; 50 baud +baud$75 equ 2 ; 75 baud +baud$110 equ 3 ; 110 baud +baud$134 equ 4 ; 134.5 baud +baud$150 equ 5 ; 150 baud +baud$300 equ 6 ; 300 baud +baud$600 equ 7 ; 600 baud +baud$1200 equ 8 ; 1200 baud +baud$1800 equ 9 ; 1800 baud +baud$2400 equ 10 ; 2400 baud +baud$3600 equ 11 ; 3600 baud +baud$4800 equ 12 ; 4800 baud +baud$7200 equ 13 ; 7200 baud +baud$9600 equ 14 ; 9600 baud +baud$19200 equ 15 ; 19.2k baud + diff --git a/z180/msgbuf-a.180 b/z180/msgbuf-a.180 new file mode 100644 index 0000000..3575569 --- /dev/null +++ b/z180/msgbuf-a.180 @@ -0,0 +1,374 @@ + page 255 + .z80 + + public mrx.fifo,mtx.fifo + + public msginit,msgi.st,msg.in,msgo.st + public msg.sm,msg.sout + + extrn bufinit,hwl2phy + extrn fifolst + + include config.inc + if CPU_Z180 + include z180reg.inc + endif + +;-------------------------------------------------------------- + + dseg + + mkbuf mtx.fifo_id, mtx.fifo, mtx.fifo_len + mkbuf mrx.fifo_id, mrx.fifo, mrx.fifo_len + +;-------------------------------------------------------------- + + cseg + +; +; Init buffer +; + +msginit: + ld a,(043h) +;TODO: value should be 0 + ld ix,mtx.fifo + call bufinit + push ix + pop hl + call hwl2phy + ld (040h),hl + ld (040h+2),a + ld a,0ffh + ld (043h),a + out (AVRINT5),a +wait: + ld a,(043h) + or a + jr nz,wait + + ld ix,mrx.fifo + jp bufinit + +;-------------------------------------------------------------- + +msgi.st: + push ix + ld ix,mrx.fifo ; + +buf.empty: + ld a,(ix+o.in_idx) ; + sub (ix+o.out_idx) ; + pop ix + ret z + or 0ffh + ret + +;-------------------------------------------------------------- + +msg.in: + push ix + ld ix,mrx.fifo ; + +buf.get: + ld a,(ix+o.out_idx) ; +bg.wait: + cp (ix+o.in_idx) ; + jr z,bg.wait + + push hl ; + push ix + pop hl + add a,l + ld l,a + jr nc,bg.nc + inc h +bg.nc: + ld l,(hl) + + ld a,(ix+o.out_idx) ; + inc a + and (ix+o.mask) + ld (ix+o.out_idx),a + + ld a,l + pop hl + pop ix + ret + +;-------------------------------------------------------------- + +msgo.st: + push ix + ld ix,mtx.fifo ; + +buf.full: + ld a,(ix+o.in_idx) ; + inc a + and (ix+o.mask) + sub (ix+o.out_idx) ; + pop ix + ret z + or 0ffh + ret + +;-------------------------------------------------------------- + + if 0 + +msg.out: + push ix + ld ix,mtx.fifo ; + +buf.put: + push hl ; + push bc + push ix + pop hl + ld c,(ix+o.in_idx) ; + ld b,0 + add hl,bc + ld b,a + + ld a,c ; + inc a + and (ix+o.mask) +bp.wait: + cp (ix+o.out_idx) ; + jr z,bp.wait + ld (hl),b + ld (ix+o.in_idx),a + + ld a,b + out (AVRINT5),a + pop bc + pop hl + pop ix + ret + + endif + +;-------------------------------------------------------------- + + if 0 + +msg.out: + push ix + ld ix,mtx.fifo ; + +buf.put: + push bc + ld c,(ix+o.in_idx) ; + ld b,0 + push ix ;14 + add ix,bc ;10 + ld (ix+0),a ;15 + pop ix ;12 / 51 + ld b,a ; 4 + ld a,c ; + inc a ; + and (ix+o.mask) ; +bp.wait: + cp (ix+o.out_idx) ; + jr z,bp.wait ; + ld (ix+o.in_idx),a ; + + ld a,b + out (AVRINT5),a + pop bc + pop ix + ret + + endif + +;---------------------------------------------------------------------- +; +; Put char in message buffer: +; ix: buffer to put into +; c: char + +buf.put: + push ix ;15 + push bc ;11 + ld a,(ix+o.in_idx) ;19 + ld c,a ;4 + ld b,0 ;7 + add ix,bc ;11 + pop bc ;10 + ld (ix),c ;7 + pop ix ;14 + + inc a ;4 + and (ix+o.mask) ;19 =121 +bufp.wait: + cp (ix+o.out_idx) ;19 + jr z,bufp.wait ;12/7 + ld (ix+o.in_idx),a ;19 + + out (AVRINT5),a ;11 + ld a,c ;4 + ret ;10 =191 + + +;-------------------------------------------------------------- + + if 0 + ; Works only, if buffer size < (128 - 3) + ; --> mask must be 03fh or less + +msg.out: + push ix + ld ix,mtx.fifo ; + +buf.put: + push bc + ld b,a ; 4 + ld a,(ix+o.in_idx) ;14 + ld ($ + 3 + 2),a ;15 + ld (ix+0),b ;15 + inc a ; + and (ix+o.mask) ; +bp.wait: + cp (ix+o.out_idx) ; + jr z,bp.wait ; + ld (ix+o.in_idx),a ; + + ld a,b + out (AVRINT5),a + pop bc + pop ix + ret + + endif + +;-------------------------------------------------------------- +; +; (hl): data + +msg.sout: + push ix ;14 + ld ix,mtx.fifo ;12 + push bc ;11 + push de ;11 + ld c,(hl) ; 6 + ld b,0 ; 6 + inc hl ; 7 +ms.ol: ; \ + ld a,low mtx.fifo ; 6 + add a,(ix+o.in_idx) ;14 + ld e,a ; 4 + ld a,high mtx.fifo ; 6 + adc a,b ; 4 + ld d,a ; 4 + + ld a,(ix+o.in_idx) ;14 + inc a ; 4 + and (ix+o.mask) ;14 +ms.wait: + cp (ix+o.out_idx) ;14 + jr z,ms.wait ; 6/8 + + ldi ;12 + ld (ix+o.in_idx),a ;15 + jp pe,ms.ol ; 6/9 -- 126 + + out (AVRINT5),a ;10 + pop de ; 9 + pop bc ; 9 + pop ix ;12 + ret ; 9 + +;-------------------------------------------------------------- +; +; (hl): data + + if 0 + +msg.sout: + push ix ;14 + ld ix,mtx.fifo ;12 + push bc ;11 + push de ;11 + ld b,(hl) ; 6 + inc hl ; 4 + ex de,hl ; 3 +ms.ol: ; \ + push ix ;14 + pop hl ; 9 + ld c,(ix+o.in_idx) ;14 + ld a,c ; 4 + add l ; 4 + ld l,a ; 4 + jr nc,ms.on ; 6/8 + inc h ; 4 +ms.on: + ld a,c ; 4 + inc a ; 4 + and (ix+o.mask) ;14 +ms.wait: + cp (ix+o.out_idx) ;14 + jr z,ms.wait ; 6/8 + ld c,a ; 4 + ld a,(de) ; 6 + inc de ; 4 + ld (hl),a ; 7 + ld (ix+o.in_idx),c ;15 + djnz ms.ol ; 7/9 -- 130 + + out (AVRINT5),a ;10 + ex de,hl ; 3 + pop de ; 9 + pop bc ; 9 + pop ix ;12 + ret ; 9 + + endif + +;-------------------------------------------------------------- + +msg.co: + push af + push hl + ld (buf_char),a + ld hl,buf + call msg.sout + pop hl + pop af + ret + + +buf: + db buf_end - $ - 1 ;output string length + db 0AEh ; message start token + db buf_end - $ - 1 ; message length + db 1 ; command + db 1 ; subcommand +buf_char: + db 0 ; pay load +buf_end: + +;---------------------------------------------------------------------- + +;---------------------------------------------------------------------- +; Send message MEMORY +; +; hl: pointer to message (netto) +; b: msg length + +msg.sm: + push ix + ld ix,mtx.fifo + ld c,0AEh + call buf.put + ld c,b + call buf.put +msm_l: + ld c,(hl) + inc hl + call buf.put + djnz msm_l + pop ix + ret + + + end diff --git a/z180/msgbuf-s.180 b/z180/msgbuf-s.180 new file mode 100644 index 0000000..6bfd709 --- /dev/null +++ b/z180/msgbuf-s.180 @@ -0,0 +1,129 @@ + page 255 + .z80 + + global msg_fifo + global msginit + global msg.out,msg.sout,msg.co + + extrn buf.init + + include config.inc + include z180reg.inc + +;-------------------------------------------------------------- + + dseg + + mkbuf msg_fifo, 0 + + +;-------------------------------------------------------------- + + cseg + +; +; Init buffer +; + +msginit: + ld ix,msg_fifo + ld a,msg_fb_len-1 + jp buf.init + + +;-------------------------------------------------------------- + +msg.sts: + push ix + ld ix,msg_fifo ; + + ld a,(ix+o.in_idx) ; + inc a + and (ix+o.mask) + sub (ix+o.out_idx) ; + pop ix + ret z + or 0ffh + ret + +;-------------------------------------------------------------- + +msg.out: + push ix + ld ix,msg_fifo ; + + push bc + ld b,a ;save char + ld a,(ix+o.in_idx) ; + inc a + and (ix+o.mask) +bp.wait: + cp (ix+o.out_idx) ; + jr z,bp.wait + ld c,a + ld a,b + out (PMSG),a + ld (ix+o.in_idx),c + + pop bc + pop ix + ret + +;-------------------------------------------------------------- +; +; (hl): data + +msg.sout: + push ix + ld ix,msg_fifo ; + push bc + + ld b,(hl) ;count + inc hl +obs_1: + ld a,(ix+o.out_idx) ; + sub (ix+o.in_idx) ; + dec a + and (ix+o.mask) + cp b + jr c,obs_1 + + ld c,(hl) ;port address + inc hl + ld a,b + otir + add (ix+o.in_idx) + and (ix+o.mask) + ld (ix+o.in_idx),a + pop bc + pop ix + ret + +;---------------------------------------------------------------------- + +msg.co: + push af + push hl + ld (buf_char),a + ld hl,buf + call msg.sout + pop hl + pop af + ret + + +buf: + db buf_end - $ - 2 ;output string length + db PMSG ;output port + db 0AEh ; message start token + db buf_end - $ - 1 ; message length + db 1 ; command + db 1 ; subcommand +buf_char: + db 0 ; pay load +buf_end: + +;---------------------------------------------------------------------- + + end + diff --git a/z180/msgfifo.180 b/z180/msgfifo.180 new file mode 100644 index 0000000..cf1ae2a --- /dev/null +++ b/z180/msgfifo.180 @@ -0,0 +1,259 @@ + page 255 + .z80 + + global msg_rx_fifo,msg_tx_fifo + + global msginit,msgi.st,msg.in,msgo.st,msg.out + global msg.sout,msg.co + + extrn buf.init + + include config.inc + include z180reg.inc + +;-------------------------------------------------------------- + + dseg + + mkbuf mtx.fifo_id, msg_tx_fifo, msg_tx_fifo_len + mkbuf mrx.fifo_id, msg_rx_fifo, msg_rx_fifo_len + + + +;-------------------------------------------------------------- + + cseg + +; +; Init buffer +; + +msginit: + ld ix,msg_rx_fifo + ld a,msg_rx_fifo.mask + call buf.init + ld ix,msg_tx_fifo + ld a,msg_tx_fifo.mask + jp buf.init + +;-------------------------------------------------------------- + +msgi.st: + push ix + ld ix,msg_rx_fifo ; + +buf.empty: + ld a,(ix+o.in_idx) ; + sub (ix+o.out_idx) ; + pop ix + ret z + or 0ffh + ret + +;-------------------------------------------------------------- + +msg.in: + push ix + ld ix,msg_rx_fifo ; + +buf.get: + ld a,(ix+o.out_idx) ; +bg.wait: + cp (ix+o.in_idx) ; + jr z,bg.wait + + push hl ; + push ix + pop hl + add a,l + ld l,a + jr nc,bg.nc + inc h +bg.nc: + ld l,(hl) + + ld a,(ix+o.out_idx) ; + inc a + and (ix+o.mask) + ld (ix+o.out_idx),a + + ld a,l + pop hl + pop ix + ret + +;-------------------------------------------------------------- + +msgo.st: + push ix + ld ix,msg_tx_fifo ; + +buf.full: + ld a,(ix+o.in_idx) ; + inc a + and (ix+o.mask) + sub (ix+o.out_idx) ; + pop ix + ret z + or 0ffh + ret + +;-------------------------------------------------------------- + +msg.out: + push ix + ld ix,msg_tx_fifo ; + +buf.put: + push hl ; + push bc + push ix + pop hl + ld c,(ix+o.in_idx) ; + ld b,0 + add hl,bc + ld b,a + + ld a,c ; + inc a + and (ix+o.mask) +bp.wait: + cp (ix+o.out_idx) ; + jr z,bp.wait + ld (hl),b + ld (ix+o.in_idx),a + + ld a,b + out0 (AVRINT5),a + pop bc + pop hl + pop ix + ret + + +;-------------------------------------------------------------- +;-------------------------------------------------------------- +;-------------------------------------------------------------- + +if 0 +msg.out: + push ix + ld ix,msg_fifo ; + + push bc + ld b,a ;save char + ld a,(ix+o.in_idx) ; + inc a + and (ix+o.mask) +bp.wait: + cp (ix+o.out_idx) ; + jr z,bp.wait + ld c,a + ld a,b + out (PMSG),a + ld (ix+o.in_idx),c + + pop bc + pop ix + ret +endif + +;-------------------------------------------------------------- +; +; (hl): data + +msg.sout: + push ix + ld ix,msg_tx_fifo ; + + push bc + push de + ld b,(hl) ; + inc hl + ex de,hl + +ms.ol: + push ix + pop hl + ld c,(ix+o.in_idx) ; + ld a,c + add l + ld l,a + jr nc,ms.on + inc h +ms.on: + ld a,c ; + inc a + and (ix+o.mask) +ms.wait: + cp (ix+o.out_idx) ; + jr z,ms.wait + ld c,a + ld a,(de) + inc de + ld (hl),a + ld (ix+o.in_idx),c + djnz ms.ol + out0 (AVRINT5),a + ex de,hl + pop de + pop bc + pop ix + ret + +;-------------------------------------------------------------- + +if 0 +msg.sout: + push ix + ld ix,msg_fifo ; + push bc + + ld b,(hl) ;count + inc hl +obs_1: + ld a,(ix+o.out_idx) ; + sub (ix+o.in_idx) ; + dec a + and (ix+o.mask) + cp b + jr c,obs_1 + + ld c,(hl) ;port address + inc hl + ld a,b + otir + add (ix+o.in_idx) + and (ix+o.mask) + ld (ix+o.in_idx),a + pop bc + pop ix + ret + +;---------------------------------------------------------------------- +endif + +msg.co: + push af + push hl + ld (buf_char),a + ld hl,buf + call msg.sout + pop hl + pop af + ret + + +buf: + db buf_end - $ - 1 ;output string length + db 081h ; message start token + db buf_end - $ - 1 ; message length + db 1 ; command + db 1 ; subcommand +buf_char: + db 0 ; pay load +buf_end: + +;---------------------------------------------------------------------- + + end diff --git a/z180/romend.180 b/z180/romend.180 new file mode 100644 index 0000000..2a63342 --- /dev/null +++ b/z180/romend.180 @@ -0,0 +1,9 @@ + + global romend + + cseg + +romend equ $ + + end + diff --git a/z180/z180.lib b/z180/z180.lib new file mode 100644 index 0000000..ffe0ab7 --- /dev/null +++ b/z180/z180.lib @@ -0,0 +1,120 @@ + .xlist +;; +;; Z180 / HD64180 MACRO LIBRARY +;; + +IFNDEF SLP + +;; +;; +;; HD64180 instructions: +;; +;; SLP ; Enter SLEEP mode +;; MLT RR ; 8 bit multiply with 16 bit result +;; IN0 R,P ; Input from internal port +;; OUT0 P,R ; Output to internal port +;; OTIM ; Block output, increment +;; OTIMR ; Block output, increment and repeat +;; OTDM ; Block output, decrement +;; OTDMR ; Block output, decrement and repeat +;; TSTIO P ; Non destructive AND, I/O port and A +;; TST R ; Non destructive AND, reg and A +;; TST ID ; Non destructive AND, immediate data and A +;; TST (HL) ; Non destructive AND, (HL) and A +;; +;; + +??BC EQU 0 ; Double-register definitions +??DE EQU 1 +??HL EQU 2 +??SP EQU 3 + +??A EQU 7 ; Single-register defintions +??B EQU 0 +??C EQU 1 +??D EQU 2 +??E EQU 3 +??H EQU 4 +??L EQU 5 + +SLP MACRO + DEFB 0EDH,76H + ENDM + +MLT MACRO ?R + DB 0EDH,4CH+(??&?R AND 3) SHL 4 + ENDM + +IN0 MACRO ?R,?P + DB 0EDH,(??&?R AND 7) SHL 3, ?P + ENDM + +OUT0 MACRO ?P,?R + DB 0EDH,1+(??&?R AND 7) SHL 3,?P + ENDM + +OTIM MACRO + DB 0EDH,83H + ENDM + +OTIMR MACRO + DB 0EDH,93H + ENDM + +OTDM MACRO + DB 0EDH,8BH + ENDM + +OTDMR MACRO + DB 0EDH,9BH + ENDM + +TSTIO MACRO ?P + DB 0EDH,74H,?P + ENDM + +TSTR MACRO ?R + DB 0EDH,4+(??&?R AND 7) SHL 3 + ENDM + +TSTD MACRO ?P + DB 0EDH,64H,?P + ENDM + +TSTP MACRO + DB 0EDH,34H + ENDM + +TST MACRO ?R + ?D: SET 0 + IRPC ?X,?R + ?D: SET ?D+1 ; Count # chars in "?R" + ENDM + IF ?D EQ 1 ; IF # chars = 1 + IRPC ?X,ABCDEHL ; Look up the character + IF ??&?X EQ ??&?R + DB 0EDH,4+(??&?R AND 7) SHL 3 + EXITM + ENDIF + ENDM + DB 0EDh,64h,?R + EXITM + ENDIF + IF (?R = 2) & (?D = 4) + ?D: SET 0 + IRPC ?X,?R + IFIDN ,<(> + DB 0EDh,34h + EXITM + ENDIF + ?D: SET ?D + 1 + ENDM + ENDIF + IF ?D NE 0 + DB 0EDH,64H,?R + ENDIF + ENDM + +ENDIF ;/* IFNDEF SLP / + .list + diff --git a/z180/z180reg.inc b/z180/z180reg.inc new file mode 100644 index 0000000..a1a90c2 --- /dev/null +++ b/z180/z180reg.inc @@ -0,0 +1,197 @@ + .xlist + +;; +;; HD64180/Z180 Register Definitions +;; + + +b2m macro name,nr +name equ nr +M_&name equ 1 shl nr + endm + +; ifndef IOBASE +IOBASE equ 0 +; endif + +cntla0 equ IOBASE+00h ;ASCI Control Register A Channel 0 +cntla1 equ IOBASE+01h ;ASCI Control Register A Channel 1 + b2m MPE, 7 ;Multi-Processor Mode Enable + b2m RE, 6 ;Receiver Enable + b2m TE, 5 ;Transmitter Enable + b2m RTS0, 4 ;Request to Send Channel 0 + b2m CKA1D, 4 ; + b2m MPBR, 3 ;Multiprocessor Bit Receive (Read) + b2m EFR, 3 ;Error Flag Reset (Write) + b2m MOD2, 2 ;Data Format Mode 1 = 8-Bit data + b2m MOD1, 1 ;1 = Parity enabled + b2m MOD0, 0 ;1 = 2 stop bits + +cntlb0 equ IOBASE+02h ;ASCI Control Register B Channel 0 +cntlb1 equ IOBASE+03h ;ASCI Control Register B Channel 1 + b2m MPBT,7 ;Multiprocessor Bit Transmit + b2m MP,6 ;Multiprocessor Mode + b2m CTS,5 ;Clear to Send + b2m PS,5 ;Prescale + b2m PEO,4 ;Parity Even Odd + b2m DR,3 ;Divede Ratio + b2m SS2,2 ;Source/Speed Select 2,1,0 + b2m SS1,1 ; + b2m SS0,0 ; + +stat0 equ IOBASE+04h ;ASCI Status Channel 0 +stat1 equ IOBASE+05h ;ASCI Status Channel 1 + b2m RDRF,7 ;Receive Data Register Full + b2m OVRN,6 ;Overrun Error + b2m PERR,5 ;Parity Error (M80: PE conflicts with JP/CALL cc) + b2m FE,4 ;Framing Error + b2m RIE,3 ;Receive Interrupt Enable + b2m DCD0,2 ;Data Carrier Detect (Ch 0) + b2m CTS1E,2 ;Clear To Send Enable (Ch 1) + b2m TDRE,1 ;Transmit Data Register Empty + b2m TIE,0 ;Transmit Interrupt Enable + +tdr0 equ IOBASE+06h ;ASCI Transmit Data +tdr1 equ IOBASE+07h ;ASCI Transmit Data +rdr0 equ IOBASE+08h ;ASCI Receive Data +rdr1 equ IOBASE+09h ;ASCI Receive Data + +cntr equ IOBASE+0Ah ;CSI/O Control Register +trdr equ IOBASE+0Bh ;CSI/O Transmit/Receive Data Register + +tmdr0l equ IOBASE+0Ch ;Timer Data Register Channel 0 +tmdr0h equ IOBASE+0Dh ; +rldr0l equ IOBASE+0Eh ;Timer Reload Register Channel 0 +rldr0h equ IOBASE+0Fh ; +tcr equ IOBASE+10h ;Timer Control Register + b2m TIF1,7 ;Timer Interrupt Flag + b2m TIF0,6 ; + b2m TIE1,5 ;Timer Interrupt Enable + b2m TIE0,4 ; + b2m TOC1,3 ;Timer Output Control + b2m TOC0,2 ; + b2m TDE1,1 ;Timer Down Count Enable + b2m TDE0,0 ; + + +asext0 equ IOBASE+12h ;ASCI Extension Control Register +asext1 equ IOBASE+13h ;ASCI Extension Control Register + b2m DCD0DIS,6 ;DCD0 Disable + b2m CTS0DIS,5 ;CTS0 Disable + b2m X1,4 ;CKA * 1 Clock/Samle Rate Divider + b2m BRGMOD,3 ;BRG Mode (Baud rate generator) + b2m BREAKEN,2 ;Break Enable + b2m BREAK,1 ;Break detected + b2m SENDBREAK,0 ;Send Break + +tmdr1l equ IOBASE+14h ;Timer Data Register Channel 1 +tmdr1h equ IOBASE+15h ; +rldr1l equ IOBASE+16h ;Timer Reload Register Channel 1 +rldr1h equ IOBASE+17h ; + +frc equ IOBASE+18h ;Free Running Counter + +astc0l equ IOBASE+1Ah ;ASCI Time Constant Register 0 +astc0h equ IOBASE+1Bh ; +astc1l equ IOBASE+1Ch ;ASCI Time Constant Register 1 +astc1h equ IOBASE+1Dh ; + +cmr equ IOBASE+1Eh ;Clock Mutiplier Register + b2m X2CM,7 ;X2 Clock Multiplier + b2m LNC,6 ;Low Noise Crystal + +ccr equ IOBASE+1Fh ;CPU Control Register + b2m NCD 7 ;No Clock Divide + +sar0l equ IOBASE+20h ;DMA Src Adr Register Channel 0 +sar0h equ IOBASE+21h ; +sar0b equ IOBASE+22h ; +dar0l equ IOBASE+23h ;DMA Dst Adr Register Channel 0 +dar0h equ IOBASE+24h ; +dar0b equ IOBASE+25h ; +bcr0l equ IOBASE+26h ;DMA Byte Count Register Channel 0 +bcr0h equ IOBASE+27h ; + +mar1l equ IOBASE+28h ;DMA Memory Address Register Channel 1 +mar1h equ IOBASE+29h ; +mar1b equ IOBASE+2Ah ; +iar1l equ IOBASE+2Bh ;DMA I/O Address Register Channel 1 +iar1h equ IOBASE+2Ch ; +iar1b equ IOBASE+2Dh ; + b2m ALTE,7 ;Alternating Chnnels + b2m ALTC,6 ;Currently selected DMA Channel when Bit7=1 + b2m REQ1SEL2,2 ; + b2m REQ1SEL1,1 ; + b2m REQ1SEL0,0 ; + +bcr1l equ IOBASE+2Eh ;DMA Byte Count Register Channel 1 +bcr1h equ IOBASE+2Fh ; + +dstat equ IOBASE+30h ;DMA Status Register + b2m DE1,7 ;DMA enable ch 1,0 + b2m DE0,6 ; + b2m NDWE1,5 ;DMA Enable Bit Write Enable 1,0 + b2m NDWE0,4 ; + b2m DIE1,3 ;DMA Interrupt Enable 1,0 + b2m DIE0,2 ; + b2m DME,0 ;DMA Master enable + +dmode equ IOBASE+31h ;DMA Mode Register + b2m DM1,5 ;Ch 0 Destination Mode 1,0 + b2m DM0,4 ; + b2m SM1,3 ;Ch 0 Source Mode 1,0 + b2m SM0,2 ; + b2m MMOD,1 ;Memory MODE select (0=cycle steel/1=burst) + +dcntl equ IOBASE+32h ;DMA/WAIT Control + b2m MWI1,7 ;Memory Wait Insertion + b2m MWI0,6 ; + b2m IWI1,5 ;I/O Wait Insertion + b2m IWI0,4 ; + b2m DMS1,3 ;DREQi Select (Edge/Level) + b2m DMS0,2 ; + b2m DIMA1,1 ;DMA Ch1 I/O Memory Mode Select + b2m DIMA0,0 +M_MWI equ M_MWI1 + M_MWI0 +M_IWI equ M_IWI1 + M_IWI0 + +il equ IOBASE+33h ;Interrupt Vector Low Register +itc equ IOBASE+34h ;INT/TRAP Control Register + b2m TRAP,7 ;Trap + b2m UFO,6 ;Unidentified Fetch Object + b2m ITE2,2 ;/INT Enable 2,1,0 + b2m ITE1,1 ; + b2m ITE0,0 ; + +rcr equ IOBASE+36h ;Refresh Control Register + b2m REFE,7 ;Refresh Enable + b2m REFW,6 ;Refresh Wait State + b2m CYC1,1 ;Cycle select + b2m CYC0,0 ; + +cbr equ IOBASE+38h ;MMU Common Base Register +bbr equ IOBASE+39h ;MMU Bank Base Register +cbar equ IOBASE+3Ah ;MMU Common/Bank Register + +omcr equ IOBASE+3Eh ;Operation Mode Control Register + b2m M1E,7 ;M1 Enable + b2m M1TE,6 ;M1 Temporary Enable + b2m IOC,5 ;I/O Compatibility + +icr equ IOBASE+3Fh ;I/O Control Register + b2m IOSTP,5 ;I/O Stop +; +; Interrupt Vectors +; + +IV$INT1 equ 0 ;/INT1 (highest priority) +IV$INT2 equ 2 ;/INT2 +IV$PRT0 equ 4 ;PRT channel 0 +IV$PRT1 equ 6 ;PRT channel 1 +IV$DMA0 equ 8 ;DMA channel 0 +IV$DMA1 equ 10 ;DMA channel 1 +IV$CSIO equ 12 ;CSI/O +IV$ASCI0 equ 14 ;ASCI channel 0 +IV$ASCI1 equ 16 ;ASCI channel 1 (lowest priority) + + .list