commit ee511ccde5cfbe5f880996739438334ee2fee83b Author: Lailouezzz Date: Sun Dec 29 22:28:26 2019 +0100 First commit : p7utils-v3.0.0 diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..62a693d --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,2 @@ +# p7utils authors +Copyright (C) 2016-2017 Thomas "Cakeisalie5" Touhey <> diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..0daa041 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,336 @@ +GNU General Public License +========================== + +_Version 2, June 1991_ +_Copyright © 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. + +### 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/Makefile b/Makefile new file mode 100755 index 0000000..a66836e --- /dev/null +++ b/Makefile @@ -0,0 +1,243 @@ +#!/usr/bin/make -f +#******************************************************************************# +# Include variables and message subsystem # +#******************************************************************************# +include Makefile.vars Makefile.msg + +# Check if we're a git repository + ISGIT := $(shell test -e .git && echo y) + +#******************************************************************************# +# General targets # +#******************************************************************************# +# Make it all +all: all-bins + +# Mostly clean +mostlyclean: mostlyclean-bins + mclean: mostlyclean + +# Clean it all +clean: clean-bins clean-doc + fclean: clean + +# Clean it entirely +mrproper: clean + $(call rmsg,Removing configuration.) + $(call qcmd,$(RM) Makefile.cfg) + $(call qcmd,$(RM) $(NAME)-*) + +# Remake it all +re: clean all + +# Install it all +install: install-bins + +# Uninstall it all +uninstall: uninstall-bins + +# Reinstall it all +reinstall: uninstall install + +# Make dist +dist: mrproper $(if $(ISGIT),reinit-gitmodules) + $(call bcmd,mkdir,$(NAME)-$(VERSION),\ + $(MD) .dist) + $(call bcmd,cp,* $(NAME)-$(VERSION),\ + cp -R * .dist) + $(call qcmd,\ + mv .dist $(NAME)-$(VERSION)) + $(call bcmd,tarball,$(NAME)-$(VERSION),\ + tar czf $(NAME)-$(VERSION).tar.gz \ + --exclude .git $(NAME)-$(VERSION)) + $(call qcmd,$(RM) -r $(NAME)-$(VERSION)) + +.PHONY: all mostlyclean mclean clean fclean mrproper re +.PHONY: dist install uninstall reinstall +#******************************************************************************# +# Git submodules # +#******************************************************************************# +# Main rule. + reinit-gitmodules: + $(call qcmd,git submodule deinit -- \ + $(shell grep path .gitmodules | sed 's/.*= //')) + $(call qcmd,git submodule update --init --recursive) + +# Initialize one module +ifeq ($(ISGIT),y) +define check-gitmodule +-$(call qcmd,git submodule update --init --quiet $1) +endef +else +define check-gitmodule +@true +endef +endif + +.PHONY: reinit-gitmodules +#******************************************************************************# +# Configuration (version) checking dependencies # +#******************************************************************************# +# Define the dependencies. + CHECKCFG := $(if $(shell test -f Makefile.cfg || echo y),check-config, \ + $(if $(shell [ "$(VERSION)" = "$(CONFIG_VERSION)" ] || echo y), \ + check-config-version)) + +# Define the rules. + check-config: + @printf "\033[1;31mNo configuration file found!\n" + @printf "You should configure before re-running this target.\033[0m\n" + @false + check-config-version: + @printf "\033[1;31mConfiguration version is incorrect!\n" + @printf "You should re-configure before re-running this target.\033[0m\n" + @false + +.PHONY: check-config check-config-version +#******************************************************************************# +# Information getting from the Makefile variables # +#******************************************************************************# +# Get the project name. + getname: + @echo "$(NAME)" + +# Get the project version. + getversion: + @echo "$(VERSION)" + +# Get the project author. + getmaintainer: + @echo "$(MAINTAINER_NAME) <$(MAINTAINER_MAIL)>" + +.PHONY: getname getmaintainer getversion +#******************************************************************************# +# Binaries-specific targets # +#******************************************************************************# +# Make the binaries. + all-bins: $(CHECKCFG) $(DEFAULT_BINARIES:%=all-%) + +# Make a binary object directory. + $(BINARIES:%=$(OBJDIR)/%): + $(call bcmd,mkdir,$@,$(MD) $@) + +# Make an object out of a source file/directory. +define make-binaryobj-rule +ifeq ($(shell test -f $(SRCDIR)/$1/$2.c && echo y),y) +# - Out of a C source file + $(OBJDIR)/$1/$2.o: $(SRCDIR)/$1/$2.c | $(OBJDIR)/$1 + $(call bcmd,cc,$$@,$(CC) -c -o $$@ $$< $(CFLAGS_$1)) +else +# - Out of an update.exe project + $(SRCDIR)/$1/$2.exe/$2.exe.bin:| $(SRCDIR)/$1/$2.exe + $(call check-gitmodule,$(SRCDIR)/$1/$2.exe) + $(if $(shell test -f $(SRCDIR)/$1/$2.exe/configure \ + && test -x $(SRCDIR)/$1/$2.exe/configure && echo y), \ + $(call qcmd,cd $(SRCDIR)/$1/$2.exe && ./configure 1>/dev/null)) + $(call bcmd,make,$2.exe,$(MAKE) -C $(SRCDIR)/$1/$2.exe $2.exe.bin \ + | sed -e 's/^/ /') + + $(OBJDIR)/$1/$2.o: $(SRCDIR)/$1/$2.exe/$2.exe.bin | $(OBJDIR)/$1 + $(call bcmd,ld -r,$$@,cd $(SRCDIR)/$1/$2.exe && \ + $(LDR) -o ../../../$$@ -b binary $2.exe.bin) +endif +endef +$(foreach bin,$(BINARIES),\ +$(foreach obj,$(SRC_$(bin)),\ +$(eval $(call make-binaryobj-rule,$(bin),$(obj))))) + +# Make a binary +define make-binary-rules + $1$(if $(FOR_WINDOWS),.exe): $(SRC_$1:%=$(OBJDIR)/$1/%.o) | $(OBJDIR)/$1 + $(call bcmd,ld,$$@,$(LD) -o $$@ $$^ $(LDFLAGS_$1)) + all-$1 all-$1.exe: $(CHECKCFG) $1$(if $(FOR_WINDOWS),.exe) all-doc-$1 + + clean-$1 clean-$1.exe: + $(call rmsg,Removing $1 and its objects directory.) + $(call qcmd,$(RM) -r $(OBJDIR)/$1) + $(call qcmd,$(RM) $1$(if $(FOR_WINDOWS),.exe)) + re-$1 re-$1.exe: clean-$1 all-$1 +endef +$(foreach bin,$(BINARIES),\ +$(eval $(call make-binary-rules,$(bin)))) + +# Remove object files. + mostlyclean-bins: + $(call rmsg,Removing objects directory.) + $(call qcmd,$(RM) -r $(OBJDIR)) + mclean-bins: mostlyclean-bins + +# Clean and remove binaries. + clean-bins: mostlyclean-bins + $(call rmsg,Removing binaries.) + $(call qcmd,$(RM) $(BINARIES:%=%*)) + +# Remake binaries + re-bins: clean-bins all-bins + +# Install a binary +define make-installbinary-rule + install-$1 install-$1.exe: $(CHECKCFG) \ + all-$1 $(if $(INSTALL_MANPAGES),install-doc-$1) + $(call imsg,Installing $1$(if $(FOR_WINDOWS),.exe).) + $(call qcmd,$(INSTALL) -m 755 -d "$(IBINDIR)") + $(call qcmd,$(INSTALL) -m 755 -t "$(IBINDIR)" $1$(if $(FOR_WINDOWS),.exe)) + + uninstall-$1 uninstall-$1.exe: $(CHECKCFG) uninstall-doc-$1 + $(call rmsg,Uninstalling $1) + $(call qcmd,$(RM) "$(IBINDIR)/$1"{,.exe}) +endef +$(foreach bin,$(BINARIES),\ +$(eval $(call make-installbinary-rule,$(bin)))) + +# Install binaries + install-bins: $(DEFAULT_BINARIES:%=install-%) + +# Uninstall binaries + uninstall-bins: $(BINARIES:%=uninstall-%) + +.PHONY: all-bins mostlyclean-bins mclean-bins clean-bins re-bins +.PHONY: install-bins uninstall-bins +.PHONY: $(foreach b,$(BINARIES),all-$(b) all-$(b).exe \ + clean-$(b) clean-$(b).exe re-$(b) re-$(b).exe \ + install-$(b) install-$(b).exe uninstall-$(b) uninstall-$(b).exe) +#******************************************************************************# +# Documentation-related # +#******************************************************************************# +# Make manpages directories + $(MANDIR)/man1: + $(call bcmd,mkdir,$@,$(MD) $@) + +# Make-A-Manpage +define make-manpage-rule + $(MANDIR)/man1/$1.%: $(DOCDIR)/$1.1.txt | $(MANDIR)/man1 + $(call bcmd,a2x,$$<,$(A2X) -f manpage -D $$| $$< 2>/dev/null) + + all-doc-$1: $(MANDIR)/man1/$1.1 +endef +$(foreach bin,$(BINARIES),\ +$(eval $(call make-manpage-rule,$(bin)))) + +# Remove all manpages + clean-doc: + $(call rmsg,Removing manpages directory.) + $(call qcmd,$(RM) -r $(MANDIR)) + +# Install a manpage. +define make-install-manpage-rule + install-doc-$1: $(MANDIR)/man1/$1.1 + $(call imsg,Installing $1 manpage) + $(call qcmd,$(INSTALL) -m 755 -d "$(IMANDIR)/man1") + $(call qcmd,$(INSTALL) -m 644 -t "$(IMANDIR)/man1" \ + $(MANDIR)/man1/$1.1) + $(call qcmd,$(GZIP) "$(IMANDIR)/man1/$1.1") + + uninstall-doc-$1: + $(call rmsg,Removing $1 manpage) + $(call qcmd,$(RM) "$(IMANDIR)/man1/$1.1*") +endef +$(foreach bin,$(BINARIES), \ +$(eval $(call make-install-manpage-rule,$(bin)))) + +.PHONY: $(foreach bin,$(BINARIES),all-doc-$(bin)) clean-doc +.PHONY: $(foreach bin,$(BINARIES),install-doc-$(bin) uninstall-doc-$(bin)) +# End of file. diff --git a/Makefile.msg b/Makefile.msg new file mode 100755 index 0000000..186d90a --- /dev/null +++ b/Makefile.msg @@ -0,0 +1,58 @@ +#!/usr/bin/make -f +# The Makefile message subsystem. +# For nice logs. 5 dollars per log only. +#******************************************************************************# +# Colors and misc # +#******************************************************************************# +# Used colors ANSI modifiers escape codes + color_green := 32 + color_red := 31 + color_yellow := 33 + +# Newline - comes handy in some situations +define \n + + +endef + +#******************************************************************************# +# General messages # +#******************************************************************************# +# Command message - display basic info about the command, and run it. +define cmd +@$(if $(MAKE_FULL_LOG),,printf "\033[1;""$4""m>\033[0m \033[1m%s\033[0m %s\n" "$1" "$2";) + $(if $(MAKE_FULL_LOG),,@)$3 +endef + +# Quiet command - make it non-quiet if full log is enabled. +define qcmd +$(if $(MAKE_FULL_LOG),,@)$1 +endef + +# Normal message - display it. +define msg +$(if $(MAKE_FULL_LOG),,@printf "\033[1;""$2""m>\033[0m \033[1m%s\033[0m\n" "$1") +endef + +#******************************************************************************# +# Commands # +#******************************************************************************# +# Build command +define bcmd +$(call cmd,$1,$2,$3,$(color_green)) +endef + +#******************************************************************************# +# Messages # +#******************************************************************************# +# Remove message +define rmsg +$(call msg,$1,$(color_red)) +endef + +# Install message +define imsg +$(call msg,$1,$(color_yellow)) +endef + +# End of file diff --git a/Makefile.vars b/Makefile.vars new file mode 100755 index 0000000..6c26965 --- /dev/null +++ b/Makefile.vars @@ -0,0 +1,155 @@ +#!/usr/bin/make -f +#******************************************************************************# +# Include configuration # +#******************************************************************************# +-include Makefile.cfg + +# Correct target + TARGET := $(if $(TARGET),$(TARGET)-) + +#******************************************************************************# +# Project main information # +#******************************************************************************# +# Project name. + NAME := p7utils + +# Author information. + MAINTAINER_NAME := Thomas \"Cakeisalie5\" Touhey + MAINTAINER_MAIL := thomas@touhey.fr + +# Project license. + LICENSE := GPLv2 + +# Project version. + MAJOR := 3 + MINOR := 0 + INDEV := + +# Project version string. + VERSION := $(MAJOR).$(MINOR)$(if $(INDEV),-indev) + +#******************************************************************************# +# Project directories # +#******************************************************************************# +# Sources directory + SRCDIR := ./src + +# Objects directory + OBJDIR := ./obj + +# Manpages sources directory + DOCDIR := ./doc + +# Manpages directory + MANDIR := ./man + +#******************************************************************************# +# Binary utilities # +#******************************************************************************# +# Package configuration + PKGCONFIG := $(TARGET)pkg-config + +# C Compiler + CC := $(TARGET)gcc +# - Check flags (enable warnings) + CWARN := -Wall -Wextra -Wno-unused-macros -Wno-vla +# - Maintainer flags +ifdef MORE_WARNINGS + CWERROR := shadow write-strings redundant-decls format format-nonliteral \ + format-security implicit-function-declaration \ + date-time missing-prototypes return-type pointer-arith + CWARN += $(CWERROR:%=-W%) -Wstack-protector -Wno-unused-parameter +endif +# - More flags (profiling, ...) +#CMOREFLAGS := +# - All C Compiler flags + CFLAGS := $(CWARN) -std=gnu11 -O2 -D NAME="$(NAME)" -D VERSION="$(VERSION)" \ + -D MAINTAINER="$(MAINTAINER_NAME) <$(MAINTAINER_MAIL)>" \ + -D DEFAULT_STORAGE="$(DEFAULT_STORAGE)" \ + -D DEFAULT_ZOOM="$(DEFAULT_ZOOM)" \ + $(CMOREFLAGS) + +# Linker + LD := $(TARGET)gcc +# - Specific linker flags + LDFLAGS_Linux := -Wl,-z,relro +# - Linker flags + LDFLAGS := $(if $(FOR_WINDOWS),,$(LDFLAGS_Linux)) + +# Raw ELF object maker + LDR := $(TARGET)ld -r + +# Maker + MAKE := make --no-print-directory +# Directory maker + MD := mkdir -p +# File remover + RM := rm -f +# Installer + INSTALL := install +# Asciidoc + A2X := a2x +# Gzipper + GZIP := gzip -f + +#******************************************************************************# +# Binaries and sources # +#******************************************************************************# +# Look for binaries + BINARIES := $(notdir $(shell find $(SRCDIR) -mindepth 1 -maxdepth 1 \ + -type d | sort)) + +# Get their libs +define get-binary-libs + LIBS_$1 := $(shell make -f $(SRCDIR)/$1/vars.mk libs 2>/dev/null) + DISABLE_$1 := $(shell make -f $(SRCDIR)/$1/vars.mk disable 2>/dev/null \ + && echo y) +endef +$(foreach bin,$(BINARIES), \ +$(eval $(call get-binary-libs,$(bin)))) + +# Get the default binaries + DEFAULT_BINARIES := $(foreach bin,$(BINARIES), \ + $(if $(DISABLE_$(bin)),,$(bin))) + +# Look for their sources +define get-binary-sources + SRC_$1 := $(basename $(shell find $(SRCDIR)/$1 \ + -maxdepth 1 -mindepth 1 \ + \( -name "*.c" -or -name "*.exe" \) \ + -printf "%P\n" | sort)) + +# - get the flags + CFLAGS_$1 := $(CFLAGS) $(shell $(PKGCONFIG) $(LIBS_$1) --cflags 2>/dev/null) \ + -D BIN="$1$(if $(FOR_WINDOWS),.exe)" + LDFLAGS_$1 := $(LDFLAGS) $(shell $(PKGCONFIG) $(LIBS_$1) --libs 2>/dev/null) +endef +$(foreach bin,$(BINARIES), \ +$(eval $(call get-binary-sources,$(bin)))) + +#******************************************************************************# +# Look for manpages # +#******************************************************************************# +# Get the manpages sections and contents + MAN_SECTIONS := +define check-man + MAN_SECTIONS += $1 + MAN_$1 += $2 +endef +$(foreach doc, $(basename $(shell find $(DOCDIR) \ + -maxdepth 1 -mindepth 1 -printf "%P\n" -type f -or -type l -name "*.*.txt")), \ +$(eval $(call check-man,$(patsubst .%,%,$(suffix $(doc))),$(basename $(doc))))) + +# Remove duplicate sections. + MAN_SECTIONS := $(sort $(MAN_SECTIONS)) + +#******************************************************************************# +# Check for DESTDIR (add as prefix to installation root) # +#******************************************************************************# +define add-dest-dir + $1 = $(DESTDIR)$($1) +endef +$(if $(DESTDIR), $(foreach idir,IBINDIR IMANDIR, \ +$(eval $(call add-dest-dir,$(idir))))) + +# End of file. diff --git a/README.md b/README.md new file mode 100644 index 0000000..80b859f --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# p7utils - Shell utilities to interact with CASIO calculators and files +## Introduction +**p7utils** is a set of command-line utilities that allow you to interact with +your CASIO calculators/files. The name comes from the fact that it originally +was the merge of `p7`, `p7screen` and `p7os` (which had an almost identical +project structure), then the `g1mutils` (shell utilities for +[libg1m](https://github.com/cakeisalie5/libg1m/) merged with this project. + +Available utilities are: + +* `p7` will interact with the storage memories; +* `p7screen` will display the result of the screen streaming; +* `p7os` will allow you to interact with the calculator's OS (backup, flash); +* `mcsfile` will display the content of an MCS archive file. + +## Prerequisites +### Making-only dependencies +| Name | Version | +| -------------------------------------------------- | -------- | +| [gcc](https://gcc.gnu.org/) | >= 4.9 | +| [binutils](https://www.gnu.org/software/binutils/) | >= 2.25 | +| [asciidoc](http://asciidoc.org/) | >= 8.6.9 | +| [gzip](https://www.gnu.org/software/gzip/) | >= 1.6 | + +### Making and runtime dependencies +| Name | Version | +| -------------------------------------------------- | --------- | +| [libp7](https://p7.planet-casio.com/en.html) | >= 3.0 | +| [libg1m](https://github.com/cakeisalie5/libg1m) | >= 0.1 | +| [libsdl](https://libsdl.org/) | == 1.2.15 | + +Notice that dependencies varies if you only want to build some +executables: only `p7screen` will require the SDL, and `mcsfile` +is the only one to require `libg1m`. + +You should check `src//vars.mk` to see what the dependencies of +the particular executable you want are (if you don't want them all; see +the `libs` target). + +## Building +Just `./configure` then `make`. To install, use `make install`. +Make the manpages with `make all-doc` and install them with `make install-doc`. + +Other useful targets : +- `all-[.exe]`: build only a given executable (and its doc); +- `install-[.exe]`: install only a given executable (and its doc, if + `--noinstall-manpages` is not passed to the configure script); +- `uninstall-[.exe]`: uninstall only a given executable (and its doc); +- `clean`, `clean-[.exe]`, `clean-doc`: remove built files; +- `mrproper`: remove all built files, and the configuration; +- `re`: remove all built files, and build all the default executables and docs. + +Notice that the `.exe` suffix is facultative and is valid for all targets. diff --git a/configure b/configure new file mode 100755 index 0000000..c24db40 --- /dev/null +++ b/configure @@ -0,0 +1,190 @@ +#!/bin/sh +cd "$(dirname "$0")" +#******************************************************************************# +# Defaults # +#******************************************************************************# +# Project variables +name="$(make -s getname)" +version="$(make -s getversion)" +maintainer="$(make -s getmaintainer)" + +# Make options +make_full_log= +more_warnings= + +# Build options +target= +windows= +default_zoom=8 +default_storage=fls0 + +# Installation directories +root='' +prefix='${root}/usr' +bindir='${prefix}/bin' +mandir='${prefix}/share/man' + +# Installation options +install_manpages=yes + +#******************************************************************************# +# Help message # +#******************************************************************************# +usage() { +cat </dev/null ]; then + echo "--default-zoom: a number is expected (got \"$zoom\")" >&2 + elif [ $zoom -lt 1 ]; then + echo "--default-zoom: should be 1 or more (got $zoom)" >&2 + elif [ $zoom -gt 16 ]; then + echo "--default-zoom: should be 16 or less (got $zoom)" >&2 + else default_zoom=$zoom; fi ;; +--default-storage=*) + storage="${arg#*=}" + # check if 4 chars long + if [ ! $(echo "$storage" | wc -c ) -eq 5 ]; then + echo "$0: --default-storage: must be 4 characters long" + continue + fi + # then set + default_storage="$storage" ;; +--noinstall-manpages) install_manpages= ;; +--root=*) root="${arg#*=}" ;; +--prefix=*) prefix="${arg#*=}" ;; +--bindir=*) bindir="${arg#*=}" ;; +--mandir=*) mandir="${arg#*=}" ;; +*) echo "$arg: didn't read" ;; +esac; done + +#******************************************************************************# +# Little things # +#******************************************************************************# +# Cross-compilation things +if [ ! $prefix_set ] && [ $target ]; then + prefix="$prefix"/"$target" +fi + +# Check MS-Windows targets +case "$target" in *-mingw32) windows=y ;; esac + +# Evaluate variables +for var in prefix bindir mandir; do + eval $var'='$(eval 'echo $'$var) +done + +# Check if is on Cygwin +[ "$(expr substr "$(uname -s)" 1 10)" = "MINGW32_NT" ] && windows=y + +# If on MS-Windows, do not make the manpages. +[ "$windows" ] && install_manpages= + +#******************************************************************************# +# Create Makefile configuration # +#******************************************************************************# +# Clean before. +make mrproper MAKE_FULL_LOG=y 1>/dev/null 2>/dev/null + +# Do it! +exec 3>&1 1>Makefile.cfg +cat <&3 3>&- +chmod +x Makefile.cfg + +#******************************************************************************# +# Finish # +#******************************************************************************# +echo "Configuration loaded, you can make now." + +# End of file. diff --git a/doc/mcsfile.1.txt b/doc/mcsfile.1.txt new file mode 100644 index 0000000..0a3fe61 --- /dev/null +++ b/doc/mcsfile.1.txt @@ -0,0 +1,36 @@ +MCSFILE(1) +========== +Thomas "Cakeisalie5" Touhey +:Email: thomas@touhey.fr +:man source: p7utils +:man manual: p7utils manual + +NAME +---- +mcsfile - list subfiles in a CASIO MCS archive file + +SYNOPSIS +-------- +[source,bash] +---- +mcsfile [--help] [--version] +---- + +DESCRIPTION +----------- +mcsfile is a simple utility that looks like *file*(1), excepts it lists subfiles +in a CASIO MCS archive file (things with extensions like *g1m* or *g2r*). + +OPTIONS +------- +Options start with one or two dashes. Some of the options require an additional +value next to them. + +*-h, --help*:: + Display command/subcommand help page and quit. +*-v, --version*:: + Display version and quit. + +SEE ALSO +-------- +*libg1m*(3) diff --git a/doc/p7.1.txt b/doc/p7.1.txt new file mode 100644 index 0000000..0ff3ed6 --- /dev/null +++ b/doc/p7.1.txt @@ -0,0 +1,85 @@ +P7(1) +===== +Thomas "Cakeisalie5" Touhey +:Email: thomas@touhey.fr +:man source: p7utils +:man manual: p7utils manual + +NAME +---- +p7 - command-line utility to communicate with casio calculators + +SYNOPSIS +-------- +[source,bash] +---- +p7 [-h|--help] [-v|--version] [ []] +---- + +DESCRIPTION +----------- +p7 is a command-line utility to communicate with machines using casio's +communication protocol 7.00, like (almost only, not gonna lie) CASIO +fx calculators. For now, it only implements file sending/getting functions +on flash memories. + +Available submenus are: + +*send [-f] [-o oncalc.ext] [-d oncalcdir] local.ext*:: + Send a file to the calculator. +*get [-o local.ext] [-d oncalcdir] oncalc.ext*:: + Get a file from calculator. +*copy [-d sourcedir] [-t destdir] source.ext dest.ext*:: + Copies a file into another on the calculator. +*del [-d oncalcdir] oncalc.ext*:: + Delete a file on the calculator. +*ls*:: + List files on the calculator. +*reset*:: + Reset a filesystem on the calculator. +*optimize*:: + Optimize the distant filesystem (defragment). +*info*:: + Dumps information about the calculator. + +OPTIONS +------- +Options start with one or two dashes. Some of the options require an additional +value next to them. + +*-h, --help*:: + Display command/subcommand help page and quit. +*-v, --version*:: + Display version and quit. +*--com *:: + The USB-serial port, if you want to communicate with a calculator connected + using a USB-to-serial cable. (1 to 20) + If this option isn't used, the program will look for a directly connected + USB calculator. +*--storage abc0*:: + The storage device with which to interact. +*--no-term, --no-exit*:: + Do not terminate connection when action is completed. +*--no-start, --no-init*:: + Do not initialize connection -- should only be used when + *--no-term*/*--no-exit* was used last time p7 was called. +*-d DIR, --directory=DIR*:: + The on-calc directory to work in. + Default for this option is device root. +*-t DDIR, --to=DIR*:: + The destination directory (for file copying/moving). + Default for this option is device root. +*-o OUT, --output=OUT*:: + For the *get* subcommand, the local file path to store in the output (or + '-' for stdout). For the *send* subcommand, the distant filename. For the + two subcommands, default is adapted from the input parameter. +*-f, --force*:: + For the *send* subcommand, force overwrite (default is interactive + confirmation from user). +*-#*:: + Displays a nice little loading bar for *send* and *get* subcommands. If + command is *get* and output is stdout, loading bar won't be displayed. + +SEE ALSO +-------- +*libp7*(3) diff --git a/doc/p7os.1.txt b/doc/p7os.1.txt new file mode 100644 index 0000000..9a50ba4 --- /dev/null +++ b/doc/p7os.1.txt @@ -0,0 +1,60 @@ +P7OS(1) +======= +Thomas "Cakeisalie5" Touhey +:Email: thomas@touhey.fr +:man source: p7utils +:man manual: p7utils manual + +NAME +---- +p7os - backup and setup CASIO calculator's software components using protocol 7 + +SYNOPSIS +-------- +[source,bash] +---- +p7os [-h|--help] [-v|--version] [--no-prepare] [--uexe ] + [ []] +---- + +DESCRIPTION +----------- +p7os is a command-line utility to get and upload an OS on CASIO fx calculators, +using its communication protocol 7.00 and OS update mode. + +Available submenus are : + +*prepare-only*:: + Sends the update program, but leave it for other programs to interact + with it. +*get [-o os.bin]*:: + Backup the bootcode, CASIOWIN entry and OS. + +You have to *prepare* before doing any other action. Preparing means sending +a P7 server on the calculator that will be able to execute commands required +by other subcommands. + +OPTIONS +------- +Options start with one or two dashes. Some of the options require an additional +value next to them. + +*-h, --help*:: + Display command/subcommand help page and quit. +*-v, --version*:: + Display version and quit. +*--com *:: + The USB-serial port, if you want to communicate with a calculator connected + using a USB-to-serial cable. (1 to 20) + If this option isn't used, the program will look for a directly connected + USB calculator. +*--no-prepare*:: + Use the current environment, instead of uploading one. +*--uexe *:: + Use a custom update program. +*-o OUT, --output=OUT*:: + When getting something, where to store. + +SEE ALSO +-------- +*libp7*(3) diff --git a/doc/p7screen.1.txt b/doc/p7screen.1.txt new file mode 100644 index 0000000..2d19b39 --- /dev/null +++ b/doc/p7screen.1.txt @@ -0,0 +1,43 @@ +P7SCREEN(1) +=========== +Thomas "Cakeisalie5" Touhey +:Email: thomas@touhey.fr +:man source: p7utils +:man manual: p7utils manual + +NAME +---- +p7screen - display streamed screen from casio fx calculator + +SYNOPSIS +-------- +[source,bash] +---- +p7screen [-h|--help] [-v|--version] +---- + +DESCRIPTION +----------- +p7screen is a command-line utility to display streamed screen from casio fx +calculator, using its communication protocol 7.00 and screenstreaming mode. + +OPTIONS +------- +Options start with one or two dashes. Some of the options require an additional +value next to them. + +*-h, --help*:: + Display help page and quit. +*-v, --version*:: + Display version and quit. +*--com *:: + The USB-serial port, if you want to communicate with a calculator connected + using a USB-to-serial cable. (1 to 20) + If this option isn't used, the program will look for a directly connected + USB calculator. +*-z ZOOM, --zoom=ZOOM*:: + Change the zoom (will change the window size too). + +SEE ALSO +-------- +*libp7*(3) diff --git a/src/mcsfile/args.c b/src/mcsfile/args.c new file mode 100644 index 0000000..567d1c1 --- /dev/null +++ b/src/mcsfile/args.c @@ -0,0 +1,93 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* args.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2016/12/18 01:20:51 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#define Q(x) #x +#define QUOTE(x) Q(x) + +/* ************************************************************************** */ +/* Help and version messages */ +/* ************************************************************************** */ +/* Help message */ +static const char *help_message = +"Usage: mcsfile [--version|-v] [--help|-h] \n" +"\n" +"Reads mcs files in a g1m file.\n" +"\n" +"Options are:\n" +" -h, --help Display this help message.\n" +" -v, --version Display the version message.\n" +"\n" +"Report bugs to " QUOTE(MAINTAINER) "."; + +/* Version message */ +static const char *version_message = +"mcsfile - from p7utils v" QUOTE(VERSION) " (licensed under GPLv2)\n" +"Maintained by " QUOTE(MAINTAINER) ".\n" +"\n" +"This is free software; see the source for copying conditions.\n" +"There is NO warranty; not even for MERCHANTABILITY or\n" +"FITNESS FOR A PARTICULAR PURPOSE."; + +/* ************************************************************************** */ +/* Main function */ +/* ************************************************************************** */ +/** + * parse_args: + * Args parsing main function. + * + * @arg ac the arguments count. + * @arg av the arguments values. + * @arg files pointer to the file paths tab to allocate. + * @return if execution should stop. + */ + +int parse_args(int ac, char **av, const char **path) +{ + /* getopt elements */ + const char *optstring = "hv"; + const struct option longopts[] = { + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {} + }; + + /* get options */ + int c; opterr = 0; + int help = 0, version = 0; + while ((c = getopt_long(ac, av, optstring, longopts, NULL)) != -1) + switch (c) { + case 'h': help = 1; break; + case 'v': version = 1; break; + default: switch (optopt) { + default: + fprintf(stderr, "-%c: unknown option.\n", optopt); + } + return (1); + } + + /* check parameters */ + int pc = ac - optind; + char **pv = &av[optind]; + if (pc != 1) help = 1; + else *path = *pv; + + /* display version or help message */ + if (version) { + puts(version_message); + return (1); + } else if (help) { + puts(help_message); + return (1); + } + + /* no error */ + return (0); +} diff --git a/src/mcsfile/main.c b/src/mcsfile/main.c new file mode 100644 index 0000000..6a1af66 --- /dev/null +++ b/src/mcsfile/main.c @@ -0,0 +1,53 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* main.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2016/12/18 01:19:25 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#include + +/** + * main: + * Entry point of the program. + * + * @arg ac the arguments count. + * @arg av the arguments values. + * @return the status code (0 if ok). + */ + +int main(int ac, char **av) +{ + /* parse arguments */ + const char *path; + if (parse_args(ac, av, &path)) + return (0); + + /* parse */ + g1m_t *handle; int err; + if ((err = g1m_open(&handle, path, g1m_type_mcs))) switch (err) { + case g1m_error_wrong_type: + fprintf(stderr, "An MCS file was expected (g1m/g1r, g1m/g2r, g3m)\n"); + return (0); + case g1m_error_nostream: + fprintf(stderr, "Could not open file: %s\n", strerror(errno)); + return (0); + case g1m_error_magic: + fprintf(stderr, "Magic error: file might be corrupted\n"); + return (0); + case g1m_error_eof: + fprintf(stderr, "Unexpected end of file\n"); + return (0); + } + + /* read */ + put_files(handle); + + /* no error */ + g1m_free(handle); + return (0); +} diff --git a/src/mcsfile/main.h b/src/mcsfile/main.h new file mode 100644 index 0000000..64fc6eb --- /dev/null +++ b/src/mcsfile/main.h @@ -0,0 +1,27 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* main.h |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2016/12/18 01:33:41 |___/ */ +/* */ +/* ************************************************************************** */ +#ifndef MAIN_H +# define MAIN_H +# include + +/* Some printf types */ +# ifdef _WIN64 +# define PRIuSIZE "l64u" +# elif _WIN32 +# define PRIuSIZE "u" +# else +# define PRIuSIZE "zu" +# endif + +/* Prototypes */ +int parse_args(int ac, char **av, const char **paths); +void put_files(g1m_t *handle); + +#endif /* MAIN_H */ diff --git a/src/mcsfile/print.c b/src/mcsfile/print.c new file mode 100644 index 0000000..e61eee8 --- /dev/null +++ b/src/mcsfile/print.c @@ -0,0 +1,130 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* line.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: mcsfile | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2016/12/18 01:43:52 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#include + +/* ************************************************************************** */ +/* Sort */ +/* ************************************************************************** */ +/** + * compare: + * Compare two MCS files. + * + * @arg + */ + +static int compare(const void *vpfile1, const void *vpfile2) +{ + g1m_mcsfile_t *file1 = *((g1m_mcsfile_t**)vpfile1); + g1m_mcsfile_t *file2 = *((g1m_mcsfile_t**)vpfile2); + + /* compare dirnames */ + int dirdiff = strcmp(file1->_dirname, file2->_dirname); + if (dirdiff) return (dirdiff > 0); + + /* compare names */ + return (strcmp(file1->name, file2->name) > 0); +} + +/** + * sort_files: + * Sort MCS files. + * + * @arg handle the handle. + */ + +static void sort_files(g1m_t *handle) +{ + qsort(handle->files, (size_t)handle->count, + sizeof(g1m_mcsfile_t*), &compare); +} + +/* ************************************************************************** */ +/* Display */ +/* ************************************************************************** */ +/** + * put_description: + * Put the description (with the newline). + * + * @arg file the MCS file. + */ + +static void put_description(g1m_mcsfile_t *file) +{ + if (!file->type) + printf("unknown content (%" PRIuSIZE" octets)\n", file->content_size); + else if (file->type & g1m_mcstype_program) { + printf("program ("); + if (g1m_has_password(file)) printf("password: '%s')\n", file->password); + else printf("no password)\n"); + } else if (file->type & g1m_mcstype_list) { + printf("list %d (", g1m_get_id_minor(file->id)); + if (g1m_get_id_major(file->id)) + printf("from listfile %d, ", g1m_get_id_major(file->id)); + printf("%d columns)\n", file->columns); + } else if (file->type & g1m_mcstype_mat) + printf("matrix %c (%d columns, %d rows)\n", + 'A' + file->id - 1, file->columns, file->rows); + else if (file->type & g1m_mcstype_vct) + printf("vector %c (%d rows)\n", + 'A' + file->id - 1, file->rows); + else if (file->type & g1m_mcstype_pict) + printf("picture %d (double %dx%d image)\n", + file->id, file->width, file->height); + else if (file->type & g1m_mcstype_capt) + printf("capture %d (%dx%d)\n", + file->id, file->width, file->height); + else if (file->type & g1m_mcstype_spreadsheet) + printf("spreadsheet (%d columns, %d rows)\n", + file->columns, file->rows); + else if (file->type & g1m_mcstype_string) + printf("string %d\n", file->id); + else if (file->type & g1m_mcstype_setup) + printf("setup\n"); + else if (file->type & g1m_mcstype_alphamem) + printf("alpha memory\n"); + else + printf("unmanaged format\n"); +} + +/** + * put_files: + * Put the files. + * + * @arg handle the handle. + */ + +void put_files(g1m_t *handle) +{ + if (!handle->count) { + fprintf(stderr, "Provided file was empty.\n"); + return ; + } + + sort_files(handle); + /* get first part maximum size */ + int max_size = 0; + for (int i = 0; i < handle->count; i++) { + g1m_mcsfile_t *file = handle->files[i]; + int sz = strlen(file->name) + strlen(file->_dirname); + if (sz > max_size) max_size = sz; + } + max_size += 2; + + /* put the lines */ + char buf[max_size + 1]; + for (int i = 0; i < handle->count; i++) if (handle->files[i]) { + g1m_mcsfile_t *file = handle->files[i]; + sprintf(buf, "%s/%s:", file->_dirname, file->name); + printf("%-*s ", max_size, buf); + put_description(handle->files[i]); + } +} diff --git a/src/mcsfile/vars.mk b/src/mcsfile/vars.mk new file mode 100755 index 0000000..b9df833 --- /dev/null +++ b/src/mcsfile/vars.mk @@ -0,0 +1,4 @@ +#!/usr/bin/make -f +disable: +libs: + @echo libg1m diff --git a/src/p7/args.c b/src/p7/args.c new file mode 100644 index 0000000..701fd3d --- /dev/null +++ b/src/p7/args.c @@ -0,0 +1,348 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* p7/args.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 23:55:54 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#include +#include +#include +#include + +/* ************************************************************************** */ +/* Help and version messages */ +/* ************************************************************************** */ +/* Version message */ +static const char version_message[] = +QUOTE(BIN) " - from " QUOTE(NAME) " v" QUOTE(VERSION) " (licensed under GPLv2)\n" +"Maintained by " QUOTE(MAINTAINER) ".\n" +"\n" +"This is free software; see the source for copying conditions.\n" +"There is NO warranty; not even for MERCHANTABILITY or\n" +"FITNESS FOR A PARTICULAR PURPOSE."; + +/* Main help message */ +static const char help_main[] = +"Usage: " QUOTE(BIN) " [--version|-v] [--help|-h] [--no-init] [--no-exit]\n" +" [--storage ] [--com ]\n" +" [options...]\n" +"\n" +"Subcommands you can use are:\n" +" send Send a file to the calculator.\n" +" get Get a file from the calculator.\n" +" copy Copy a file into another on the calculator.\n" +" del Delete a file on the calculator.\n" +" reset Reset the flash memory.\n" +" optimize Optimize the distant filesystem.\n" +" ls List files on the distant filesystem.\n" +" info Dump info about the calculator.\n" +"\n" +"General options:\n" +" -h, --help Display the help page of the (sub)command and quit.\n" +" -v, --version Display the version message and quit.\n" +" --com The USB-serial port, if you want to communicate with a\n" +" calculator connected using a USB-to-serial cable. (1 to 20)\n" +" If this option isn't used, the program will look for a\n" +" directly connected USB calculator.\n" +" --storage The storage device with which to interact (fls0, crd0).\n" +" Default storage device is '" QUOTE(DEFAULT_STORAGE) "'.\n" +" --no-exit Does not terminate connection when action is completed.\n" +" --no-init Does not initialize connection (should only be used\n" +" when --no-exit was used last time p7 was called).\n" +"\n" +"Type \"" QUOTE(BIN) " --help\" for some help about the subcommand.\n" +"Report bugs to " QUOTE(MAINTAINER) "."; + +/* Parts */ +#define FOOT \ + "\nType \"" QUOTE(BIN) " --help\" for other subcommands and general options." + +/* Sending help message */ +static const char help_send[] = +"Usage: " QUOTE(BIN) " send [-f] [-o ]\n" +" [-d ] [-#] \n" +"Send a file to the calculator.\n" +"\n" +"Options are:\n" +" -f, --force Overwrite without asking\n" +" -o The output filename on the calculator (by default, the same\n" +" as the local file)\n" +" -d The directory on-calc in which the file will be stored (by\n" +" default, the root directory)\n" +" -# Display a nice little loading bar\n" +FOOT; + +/* Getting help message */ +static const char help_get[] = +"Usage: " QUOTE(BIN) " get [-o ]\n" +" [-d ] \n" +"Request a file from the calculator.\n" +"\n" +"Options are:\n" +" -o The output filename (by default, the same as the on-calc file)\n" +" -d The directory on-calc in which to get the file (by default,\n" +" the root directory)\n" +" -# Display a nice little loading bar (if output isn't stdout)\n" +FOOT; + +/* Copying help message */ +static const char help_copy[] = +"Usage: p7 copy [-f] [-d ] \n" +"Copies a file into the other on the calculator.\n" +"\n" +"Options are:\n" +" -d The source directory (by default, the root directory)\n" +" -t The dest. directory (by default, the root directory)\n" +FOOT; + +/* Deleting help message */ +static const char help_del[] = +"Usage: p7 del [-d \n" +"Delete a file on the calculator.\n" +"\n" +"Options are:\n" +" -d The directory on-calc in which to remove the file (by default,\n" +" the root directory)\n" +FOOT; + +/* Listing help message */ +static const char help_ls[] = +"Usage: p7 ls\n" +"List files on the distant filesystem.\n" +FOOT; + +/* Resetting help message */ +static const char help_reset[] = +"Usage: p7 reset\n" +"Reset the distant filesystem.\n" +FOOT; + +/* Optimizing help message */ +static const char help_optimize[] = +"Usage: p7 optimize\n" +"Optimize the distant filesystem.\n" +FOOT; + +/* Dumping help message */ +static const char help_info[] = +"Usage: p7 info\n" +"Dump information about the calculator.\n" +FOOT; + +/* ************************************************************************** */ +/* Main function */ +/* ************************************************************************** */ +/* useful macros */ +#define sub_init(CMD, NARGS) \ + args->menu = mn_##CMD; \ + if (help || aac != 1 + (NARGS)) { \ + puts(help_##CMD); \ + return (0); \ + } + +/** + * parse_args: + * Args parsing main function. + * + * Was my very first experiment with getopt. + * Then I took an arrow in the knee. + * + * @arg ac the arguments count + * @arg av the arguments values + * @arg args the parsed args pointer + * @return if it was successfully parsed + */ + +int parse_args(int ac, char **av, args_t *args) +{ + /* initialize args */ + *args = (args_t){ + .menu = 0, + .nicedisp = 0, + .dirname = NULL, .filename = NULL, + .newdir = NULL, .newname = NULL, + .local = NULL, .force = 0, + .com = 0, + .storage = QUOTE(DEFAULT_STORAGE), + .initflags = P7_ACTIVE | P7_CHECK | P7_TERM}; + + /* define options */ + char short_options[] = "hvfo:d:t:#"; + struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {"com", required_argument, NULL, 'c'}, + {"storage", required_argument, NULL, 's'}, + {"force", no_argument, NULL, 'f'}, + {"output", required_argument, NULL, 'o'}, + {"directory", required_argument, NULL, 'd'}, + {"to", required_argument, NULL, 't'}, + {"no-init", no_argument, NULL, 'i'}, + {"no-start", no_argument, NULL, 'i'}, + {"no-exit", no_argument, NULL, 'e'}, + {"no-term", no_argument, NULL, 'e'}, + {NULL, 0, NULL, 0} + }; + + /* get all options */ + int c; opterr = 0; + int help = 0; + const char *s_out = NULL, *s_dir = NULL, *s_todir = NULL, *s_com = NULL; + while ((c = getopt_long(ac, av, short_options, long_options, NULL)) != -1) { + switch (c) { + /* help */ + case 'h': help = 1; break; + /* version */ + case 'v': puts(version_message); return (0); break; + /* force */ + case 'f': args->force = 1; break; + /* nice display */ + case '#': args->nicedisp = 1; break; + + /* output file (on calc or local) */ + case 'o': s_out = optarg; break; + /* directory name */ + case 'd': s_dir = optarg; break; + /* destination directory name */ + case 't': s_todir = optarg; break; + + /* com port */ + case 'c': s_com = optarg; break; + /* storage */ + case 's': args->storage = optarg; break; + /* force no initialization */ + case 'i': args->initflags &= ~P7_CHECK; break; + /* force no exit */ + case 'e': args->initflags &= ~P7_TERM; break; + + /* in case of error */ + case '?': + if (optopt == 'o') + log("-o, --output: expected an argument\n"); + else if (optopt == 'd') + log("-d, --directory: expected an argument\n"); + else if (optopt == 't') + log("-t, --to: expected an argument\n"); + else if (optopt == 'c') + log("--com: expected an argument\n"); + else if (optopt == 's') + log("--storage: expected an argument\n"); + else + break; + return (0); + break; + } + } + + /* check com port */ + if (s_com) { + if (!isdigit(s_com[0])) { + log("-c, --com: expected a number\n"); + return (0); + } + args->com = atoi(s_com); + if (args->com < 1 || args->com > 20) { + log("-c, --com: COM port number should be between 1 and 20\n"); + return (0); + } + } + + /* get non-option arguments (subcommand and parameters) */ + int aac = ac - optind; + char **aav = &av[optind]; + + /* get subcommand and things to check */ + char fpmode[2] = " "; + args->localpath = NULL; + /* - all subcommands - */ + if (!aac || !strcmp(aav[0], "help")) { + puts(help_main); + return (0); + } else if (!strcmp(aav[0], "version")) { + puts(version_message); + return (0); + } else if (!strcmp(aav[0], "info")) { + sub_init(info, 0) + } else if (!strcmp(aav[0], "ls")) { + sub_init(ls, 0) + } else if (!strcmp(aav[0], "reset")) { + sub_init(reset, 0) + } else if (!strcmp(aav[0], "optimize")) { + sub_init(optimize, 0) + } else if (!strcmp(aav[0], "send")) { + sub_init(send, 1) + + /* put arguments to check */ + fpmode[0] = 'r'; + args->localpath = aav[1]; + args->dirname = s_dir ? s_dir : NULL; + if (s_out) args->filename = s_out; + else { + char *rs = strrchr(args->localpath, '/'); + args->filename = rs ? rs + 1 : args->localpath; + } + } else if (!strcmp(aav[0], "get")) { + sub_init(get, 1) + + /* put arguments to check */ + fpmode[0] = 'w'; + args->filename = aav[1]; + args->dirname = s_dir ? s_dir : NULL; + args->localpath = s_out ? s_out : args->filename; + } else if (!strcmp(aav[0], "copy")) { + sub_init(copy, 2) + + /* get filename */ + args->filename = aav[1]; + args->dirname = s_dir ? s_dir : NULL; + args->newname = aav[2]; + args->newdir = s_todir ? s_todir : NULL; + } else if (!strcmp(aav[0], "del") || !strcmp(aav[0], "delete")) { + sub_init(del, 1) + + /* get filename */ + args->filename = aav[1]; + args->dirname = s_dir ? s_dir : NULL; + } else { + /* unknown subcommand ! */ + log("Unknown subcommand '%s'.\n", aav[0]); + return (0); + } + + /* check string lengths */ + int noerror = 0; + if (args->filename && strnlen(args->filename, 13) == 13) + log("On-calc filename must have 12 chars or less!\n"); + else if (args->newname && strnlen(args->newname, 13) == 13) + log("Destination filename must have 12 chars or less!\n"); + else if (args->dirname && strnlen(args->dirname, 9) == 9) + log("On-calc directory name must have 8 chars or less!\n"); + else if (args->newdir && strnlen(args->newdir, 9) == 9) + log("Destination directory name must have 8 chars or less!\n"); + else if (strnlen(args->storage, 5) != 4) + log("Storage device (%s) should be 4 chars long!\n", args->storage); + else + noerror = 1; + if (!noerror) return (0); + + /* check local path */ + if (args->localpath) { + if (fpmode[0] == 'w' && !strcmp(args->localpath, "-")) + args->local = stdout; + else if (!(args->local = fopen(args->localpath, fpmode))) { + log("Could not open local file : %s\n", strerror(errno)); + if (fpmode[0] == 'w') + remove(args->localpath); + return (0); + } + } + + /* everything went well */ + return (1); +} diff --git a/src/p7/dump.c b/src/p7/dump.c new file mode 100644 index 0000000..4ba3c00 --- /dev/null +++ b/src/p7/dump.c @@ -0,0 +1,83 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* p7/dump.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 23:55:54 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#include +#define numformat "%" PRIuP7INT +#define addrformat "0x%08" PRIxP7INT + +/** + * dump: + * Dump calculator information. + * + * @arg handle the libp7 handle + * @return the error code (0 if ok). + */ + +int dump(p7_handle_t *handle) +{ + /* get server info */ + const p7_server_t *info = p7_get_info(handle); + + /* Wiped out things */ + if (info->preprog_rom_wiped) + log("Warning: Preprogrammed ROM information looks wiped out !\n"); + if (info->bootcode_wiped) + log("Warning: Bootcode information looks wiped out !\n"); + if (info->os_wiped) + log("Warning: OS information looks wiped out!\n"); + if (!info->username[0]) + log("Warning: Username is not set.\n"); + + /* main information */ + printf("CPU ID (probably out of date): %s\n", info->cpuid); + printf("Environnement ID: %s\n", info->hwid); + printf("Product ID: %s\n", info->product_id); + + /* Preprogrammed ROM */ + if (!info->preprog_rom_wiped) { + printf("Preprogrammed ROM version: %02u.%02u", + info->preprog_rom_version.major, info->preprog_rom_version.minor); + if (info->preprog_rom_version.rev) + printf(" (%u)", info->preprog_rom_version.rev); + printf("\nPreprogrammed ROM capacity: " numformat "o\n", + info->preprog_rom_capacity); + } + + /* ROM and RAM */ + printf("ROM capacity: " numformat "KiB\n", info->flash_rom_capacity / 1024); + printf("RAM capacity: " numformat "KiB\n", info->ram_capacity / 1024); + + /* Bootcode */ + if (!info->bootcode_wiped) { + printf("Bootcode version: %02u.%02u", + info->bootcode_version.major, info->bootcode_version.minor); + if (info->bootcode_version.rev) + printf(" (%u)", info->bootcode_version.rev); + printf("\nBootcode offset: " addrformat "\n", info->bootcode_offset); + printf("Bootcode size: " numformat "KiB\n", info->bootcode_size / 1024); + } + + /* OS */ + if (!info->os_wiped) { + printf("OS version: %02u.%02u", + info->os_version.major, info->os_version.minor); + if (info->os_version.rev) + printf(" (%u)", info->os_version.rev); + printf("\nOS offset: " addrformat "\n", info->os_offset); + printf("OS size: " numformat "KiB\n", info->os_size / 1024); + } + + /* Miscallenous information */ + if (info->username[0]) + printf("Username: %s\n", info->username); + + return (0); +} diff --git a/src/p7/main.c b/src/p7/main.c new file mode 100644 index 0000000..4d225e5 --- /dev/null +++ b/src/p7/main.c @@ -0,0 +1,304 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* p7/main.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 23:55:54 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#include + +/* ************************************************************************** */ +/* Error messages */ +/* ************************************************************************** */ +/* Couldn't initialize connexion with the calculator. */ +static const char error_noconnexion[] = +"Could not connect to the calculator.\n" +"- Is it plugged in and in receive mode?\n" +"- Have you tried changing the cable?\n"; + +/* Calculator was disconnected. */ +static const char error_disconnected[] = +"Lost connexion to the calculator!\n" +"Please reconnect the calculator, rerun receive mode and try again.\n"; + +/* Calculator was found but program wasn't allowed to communicate with it. */ +static const char error_noaccess[] = +"Could not get access to the calculator.\n" +"Install the appropriate udev rule, or run as root.\n"; + +/* Command was unsupported. */ +static const char error_unsupported[] = +"The command is unsupported by the calculator.\n" +"- Does the calculator have mass storage?\n" +"- Does its OS allow the use of it?\n" +"- Is it in Receive Mode (and not in OS Update)?\n"; + +/* The device didn't exist. */ +static const char error_unsupported_device[] = +"Device '%s' is not supported by the device.\n"; + +/* The calculator acted in an unplanned way. */ +static const char error_unplanned[] = +"The calculator didn't act as planned.\n" +"Stop receive mode on calculator and start it again before re-running " \ + QUOTE(BIN) ".\n" +"Error was: %s\n"; + +/* Requested file didn't exist. */ +static const char error_noexists[] = +"Requested file didn't exist.\n"; + +/* Sent file cannot be empty. */ +static const char error_empty[] = +"Can't send an empty file!\n"; + +/* Not enough space left on the calculator. */ +static const char error_nospace[] = +"Not enough space on the calculator for the file you're trying to send.\n" +"If you believe there should be, try optimizing (OPT) on the calculator\n" +"(in MEMORY menu) and try again.\n"; + +/* ************************************************************************** */ +/* Auxiliary functions */ +/* ************************************************************************** */ +/** + * sendfile_confirm: + * Confirm file sending. + * + * @return if the file overwriting is confirmed + */ + +static int sendfile_confirm(void) +{ + char line[10]; + + /* Print stuff */ + printf("It looks like the file already exists on the calculator.\n"); + printf("Overwrite ? ([n]/y) "); + + /* Get the line */ + if (!fgets(line, 10, stdin)) + return (0); + + /* Check if should overwrite */ + return (*line == 'y'); +} + +/** + * sendfile_display: + * File sending nice display. + * + * "Initialization" is when id > total (called in main). + * + * @arg id data packet ID + * @arg total total number of data packets + */ + +static int sendfile_display_initialized = 0; +static void sendfile_display(p7ushort_t id, p7ushort_t total) +{ + /* here's the buffer */ + static char buf[50] = + "\r|---------------------------------------| 00.00%"; + static char *bar = &buf[2]; + + /* initialize */ + static int pos; + + /* if is initialize, fill */ + if (id > total) { + pos = 0; + /* indicate that is has been initialized */ + sendfile_display_initialized = 1; + /* put initial buffer */ + fputs(buf, stdout); + /* save cursor position */ + fputs("\x1B[s", stdout); + /* we're done */ + return ; + } + + /* id and total start from 1, let them start from zero */ + id--; total--; + + /* modify buffer */ + /* - # - */ + int current = 38 * id / total; + while (pos <= current) bar[pos++] = '#'; + /* - % - */ + unsigned int percent = 10000 * id / total; + sprintf(&buf[43], "%02u.%02u", percent / 100, percent % 100); + + /* put it */ + fputs(buf, stdout); + /* force cursor position */ + fputs("\x1B""8", stdout); +} + +/** + * print_file_info: + * File listing callback. + * + * @arg cookie (unused) + * @arg dir the directory in which the file is stored (NULL if root) + * @arg name the filename + * @arg size the filesize + */ + +static void print_file_info(void *cookie, const char *dir, const char *name, + p7uint_t size) +{ + (void)cookie; + /* initialize buffer */ + static char buf[45]; + + /* clean buffer */ + memset(buf, ' ', 28); + /* put path in buffer */ + char *b = buf; + if (dir) b += sprintf(b, "%s/", dir); + if (name) b[sprintf(b, "%s", name)] = ' '; + /* put size */ + sprintf(&buf[28], "%10uo", (unsigned)size); + + /* put the string */ + puts(buf); +} + +/* ************************************************************************** */ +/* Main function */ +/* ************************************************************************** */ +/** + * main: + * User entry point of the program. + * + * @arg ac arguments count + * @arg av arguments values + * @return return code (0 if ok) + */ + +int main(int ac, char **av) +{ + /* Parse args */ + args_t args; + if (!parse_args(ac, av, &args)) + return (0); + + /* Initialize libp7 and communication */ + p7_handle_t *handle = NULL; int err; + if (args.com) err = p7_cominit(&handle, args.initflags, args.com); + else err = p7_init(&handle, args.initflags); + if (err) { + /* display error */ + switch (err) { + case p7_error_nocalc: log(error_noconnexion); break; + case p7_error_noaccess: log(error_noaccess); break; + default: log(error_unplanned, p7_strerror(err)); break; + } + + /* closing, removing if necessary */ + if (args.menu == mn_send) + fclose(args.local); + if (args.menu == mn_get && args.local != stdout) { + fclose(args.local); + remove(args.localpath); + } + return (1); + } + + /* Check according to menu */ + switch (args.menu) { + case mn_send: + /* get file size */ + fseek(args.local, 0, SEEK_END); + size_t filesize = (p7uint_t)ftell(args.local); + rewind(args.local); + + /* get capacity */ + p7uint_t capacity; + err = p7_getfreemem(handle, args.storage, &capacity); + if (err) break; + + /* optimize if required */ + if (filesize > (size_t)capacity) { + printf("Not enough space on the device. Let's optimize!\n"); + err = p7_optimize(handle, args.storage); + if (err) break; + } + + /* send the file */ + err = p7_sendfile(handle, args.local, + args.dirname, args.filename, + args.storage, 1, args.force ? NULL : &sendfile_confirm, + args.nicedisp ? &sendfile_display : NULL); + break; + case mn_get: + err = p7_reqfile(handle, args.local, args.dirname, args.filename, + args.storage, args.nicedisp && args.local != stdout + ? &sendfile_display : NULL); + break; + case mn_copy: + err = p7_copy(handle, args.dirname, args.filename, + args.newdir, args.newname, args.storage); + break; + case mn_del: + err = p7_delete(handle, args.dirname, args.filename, + args.storage); + break; + case mn_ls: + err = p7_list(handle, args.storage, &print_file_info, NULL); + break; + case mn_reset: + err = p7_reset(handle, args.storage); + break; + case mn_optimize: + err = p7_optimize(handle, args.storage); + break; + case mn_info: + err = dump(handle); + break; + } + + /* put error */ + if (err && err != p7_error_denied_overwrite) { + if (sendfile_display_initialized) + puts("\b\b\b\b\b\bError !"); + + /* close the file */ + if (args.local) fclose(args.local); + if (args.menu == mn_get && args.local != stdout) + remove(args.localpath); + + /* put the error string */ + switch (err) { + case p7_error_fullmem: log(error_nospace); break; + case p7_error_empty: log(error_empty); break; + case p7_error_notfound: log(error_noexists); break; + case p7_error_nocalc: log(error_disconnected); break; + case p7_error_unsupported: log(error_unsupported); break; + case p7_error_unsupported_device: + log(error_unsupported_device, args.storage); break; + default: log(error_unplanned, p7_strerror(err)); + } + + /* that doesn't mean you shouldn't exit, heh. */ + p7_exit(handle); + + /* return that an error has occured */ + return (1); + } + + if (sendfile_display_initialized) + puts("\b\b\b\b\b\bTransfer complete."); + if (args.local) fclose(args.local); + + /* terminate communication and de-initialize libp7 */ + p7_exit(handle); + + /* Then we're good */ + return (0); +} diff --git a/src/p7/main.h b/src/p7/main.h new file mode 100644 index 0000000..ac7be2b --- /dev/null +++ b/src/p7/main.h @@ -0,0 +1,47 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* p7/main.h |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 23:55:54 |___/ */ +/* */ +/* ************************************************************************** */ +#ifndef MAIN_H +# define MAIN_H +# define Q(x) #x +# define QUOTE(x) Q(x) +# include +# include +# define log(S, ...) fprintf(stderr, S, ##__VA_ARGS__) + +/* Menus */ +typedef enum { + mn_send, mn_get, mn_copy, mn_del, mn_ls, mn_reset, mn_optimize, + mn_info +} menu_t; + +/* Arguments */ +typedef struct { + /* basic things */ + menu_t menu; + int nicedisp; + + /* for file transferring menus */ + const char *dirname, *filename; + const char *newdir, *newname; + FILE *local; const char *localpath; + int force; + + /* other options */ + unsigned int initflags; + int com; const char *storage; +} args_t; + +/* Parsing function */ +int parse_args(int ac, char **av, args_t *args); + +/* Dumping function */ +int dump(p7_handle_t *handle); + +#endif /* MAIN_H */ diff --git a/src/p7/vars.mk b/src/p7/vars.mk new file mode 100755 index 0000000..c22ee31 --- /dev/null +++ b/src/p7/vars.mk @@ -0,0 +1,3 @@ +#!/usr/bin/make -f +libs: + @echo libp7 diff --git a/src/p7os/args.c b/src/p7os/args.c new file mode 100644 index 0000000..9ceb74a --- /dev/null +++ b/src/p7os/args.c @@ -0,0 +1,220 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* p7os/args.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 23:55:54 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#include +#include +#include +#include + +/* ************************************************************************** */ +/* Help and version messages */ +/* ************************************************************************** */ +/* The version message - that's when the President comes in */ +static const char version_message[] = +QUOTE(BIN) " - from " QUOTE(NAME) " v" QUOTE(VERSION) " (licensed under GPLv2)\n" +"Maintained by " QUOTE(MAINTAINER) ".\n" +"\n" +"This is free software; see the source for copying conditions.\n" +"There is NO warranty; not even for MERCHANTABILITY or\n" +"FITNESS FOR A PARTICULAR PURPOSE."; + +/* Main help message */ +static const char help_main[] = +"Usage: " QUOTE(BIN) " [--version|-v] [--help|-h] [--com ]\n" +" [--no-prepare] [--uexe ]\n" +" [options...]\n" +"\n" +"Subcommands you can use are :\n" +" prepare-only Set-up the update program, but leave it for other programs\n" +" to interact with it.\n" +" get Get the OS image.\n" +"\n" +"General options:\n" +" -h, --help Display the help page of the (sub)command and quit.\n" +" -v, --version Display the version message and quit.\n" +" --com The USB-serial port, if you want to communicate with a\n" +" calculator connected using a USB-to-serial cable. (1 to 20)\n" +" If this option isn't used, the program will look for a\n" +" directly connected USB calculator.\n" +" --no-prepare Use the current environment, instead of uploading one.\n" +" --uexe Use a custom update program.\n" +"\n" +"Type \"" QUOTE(BIN) " --help\" for some help about a subcommand.\n" +"Report bugs to " QUOTE(MAINTAINER) "."; + +/* Subcommands help messages footer */ +#define FOOT \ + "\nType \"" QUOTE(BIN) " --help\" for other subcommands and general options." + +/* Help message for prepare subcommand */ +static const char help_prepare_only[] = +"Usage: " QUOTE(BIN) " prepare-only\n" +"Send the P7 server on the calculator for further operations.\n" +"This must be used before any other p7os operation.\n" +FOOT; + +/* Help message for get subcommand */ +static const char help_get[] = +"Usage: " QUOTE(BIN) " get [-o ]\n" +"Get the calculator OS image.\n" +"You must have \"p7os prepare\"-ed before.\n" +"\n" +"Options are :\n" +" -o Where to store the image (default is \"os.bin\")\n" +FOOT; + +/* ************************************************************************** */ +/* Main function */ +/* ************************************************************************** */ +/* Help macro */ +#define sub_init(CMD, NARGS) { \ + args->menu = mn_##CMD; \ + if (help || pc != (NARGS)) { \ + puts(help_##CMD); \ + return (1); \ + }} + +/** + * parse_args: + * Args parsing main function. + * + * Based on my very first experiment with getopt. + * + * @arg ac the arguments count + * @arg av the arguments values + * @arg args the parsed args pointer + * @return if has been parsed successfully + */ + +int parse_args(int ac, char **av, args_t *args) +{ + /* initialize args */ + *args = (args_t){ + .menu = 0, + .com = 0, .noprepare = 0, + .uexe = NULL, + .local = NULL, .localpath = NULL + }; + + /* define options */ + const char shopts[] = "hvo:#"; + const struct option longopts[] = { + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {"com", required_argument, NULL, 'c'}, + {"no-prepare", no_argument, NULL, 'n'}, + {"uexe", required_argument, NULL, 'u'}, + {"output", required_argument, NULL, 'o'}, + {NULL, 0, NULL, 0} + }; + + /* get all options */ + int c; opterr = 0; + int help = 0, version = 0; + const char *s_out = "os.bin", *s_com = 0, *s_uexe = NULL; + while ((c = getopt_long(ac, av, shopts, longopts, NULL)) != -1) switch (c) { + /* help */ + case 'h': help = 1; break; + /* version */ + case 'v': version = 1; break; + /* com port */ + case 'c': s_com = optarg; break; + /* no prepare */ + case 'n': args->noprepare = 1; break; + /* uexe */ + case 'u': s_uexe = optarg; break; + /* output */ + case 'o': s_out = optarg; break; + + /* error */ + case '?': + if (optopt == 'o') + log("-o, --output: expected an argument\n"); + else if (optopt == 'c') + log("--com: expected an argument\n"); + else if (optopt == 'u') + log("--uexe: expected an argument\n"); + else + break; + return (1); + } + + /* check for version */ + if (version) { + puts(version_message); + return (1); + } + + /* get non-option arguments (subcommand and parameters) */ + int pc = ac - optind; + char **pv = &av[optind]; + char *sub = pc ? pv[0] : NULL; + pc--; pv++; + + /* subcommand. */ + char fpmode[2] = "r"; + if (!sub || !strcmp(sub, "help")) { + puts(help_main); + return (1); + } else if (!strcmp(sub, "version")) { + puts(version_message); + return (1); + } else if (!strcmp(sub, "prepare-only")) { + sub_init(prepare_only, 0) + + if (args->noprepare) { + log("So we should prepare but we should not prepare? Duh!\n"); + return (1); + } + } else if (!strcmp(sub, "get")) { + sub_init(get, 0) + args->localpath = s_out; + fpmode[0] = 'w'; + } else { + log("Unknown subcommand '%s'.\n", sub); + return (1); + } + + /* check com port */ + if (s_com) { + if (!isdigit(s_com[0])) { + log("-c, --com: expected a number\n"); + return (0); + } + args->com = atoi(s_com); + if (args->com < 1 || args->com > 20) { + log("-c, --com: COM port number should be between 1 and 20\n"); + return (0); + } + } + + /* open destination file */ + if (args->localpath) { + args->local = fopen(args->localpath, fpmode); + if (!args->local) { + log("Could not open local file: %s\n", strerror(errno)); + return (1); + } + } + + /* open update.exe file */ + if (s_uexe) { + args->uexe = fopen(s_uexe, "r"); + if (!args->uexe) { + log("Could not open update program: %s\n", strerror(errno)); + if (args->local) fclose(args->local); + return (1); + } + } + + /* everything went well :) */ + return (0); +} diff --git a/src/p7os/cake.exe/.gitignore b/src/p7os/cake.exe/.gitignore new file mode 100644 index 0000000..4fef74c --- /dev/null +++ b/src/p7os/cake.exe/.gitignore @@ -0,0 +1,6 @@ +/Makefile.cfg +/obj +/update.exe.elf +/update.exe.bin +/cake.exe.elf +/cake.exe.bin diff --git a/src/p7os/cake.exe/.gitmodules b/src/p7os/cake.exe/.gitmodules new file mode 100644 index 0000000..2e6b16d --- /dev/null +++ b/src/p7os/cake.exe/.gitmodules @@ -0,0 +1,3 @@ +[submodule "libgint"] + path = libgint + url = http://git.planet-casio.com/lephe/gint.git diff --git a/src/p7os/cake.exe/LICENSE.md b/src/p7os/cake.exe/LICENSE.md new file mode 100644 index 0000000..0daa041 --- /dev/null +++ b/src/p7os/cake.exe/LICENSE.md @@ -0,0 +1,336 @@ +GNU General Public License +========================== + +_Version 2, June 1991_ +_Copyright © 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. + +### 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/src/p7os/cake.exe/Makefile b/src/p7os/cake.exe/Makefile new file mode 100755 index 0000000..0d70b6f --- /dev/null +++ b/src/p7os/cake.exe/Makefile @@ -0,0 +1,136 @@ +#!/usr/bin/make -f +#******************************************************************************# +# Include variables and message subsystem # +#******************************************************************************# +include Makefile.vars Makefile.msg + +#******************************************************************************# +# General targets # +#******************************************************************************# +# Build everything. +all: all-bin + +# Mostly clean everything (remove everything but the end results). +mostlyclean: mostlyclean-bin + mclean: mostlyclean + +# Clean everything. +clean: clean-bin clean-gint + fclean: clean + +# Clean everything with configuration. +mrproper: clean + $(call rmsg,Removing configuration.) + $(call qcmd,$(RM) Makefile.cfg) + distclean: mrproper + +# Remake everything (clean and build). +re: mostlyclean all + +.PHONY: all mostlyclean mclean clean fclean distclean mrproper re +#******************************************************************************# +# Configuration (version) checking dependencies # +#******************************************************************************# +# Define the dependencies. + CHECKCFG := $(if $(shell test -f Makefile.cfg || echo y),check-config, \ + $(if $(shell [ "$(VERSION)" = "$(CONFIG_VERSION)" ] || echo y), \ + check-config-version)) + +# Define the rules. + check-config: + @printf "\033[1;31mNo configuration file found!\n" + @printf "You should configure before re-running this target.\033[0m\n" + @false + check-config-version: + @printf "\033[1;31mConfiguration version is incorrect!\n" + @printf "You should re-configure before re-running this target.\033[0m\n" + @false + +.PHONY: check-config check-config-version +#******************************************************************************# +# Information getting from the Makefile variables # +#******************************************************************************# +# Get the project name. + getname: + @echo $(NAME) + +# Get the project version. + getversion: + @echo $(VERSION) + +# Get the project maintainer. + getmaintainer: + @echo "$(MAINTAINER_NAME) <$(MAINTAINER_MAIL)>" + +.PHONY: getname getmaintainer getversion +#******************************************************************************# +# gint-related targets # +#******************************************************************************# +# Main gint target + all-gint: $(GLIBDIR)/libgint.a + +# Configure gint libraries. + $(GLIBDIR)/gcc.cfg: + -$(call qcmd,test -e .git && ! test -e $(GLIBDIR)/.git && \ + git submodule update --init $(GLIBDIR)) + $(call bmsg,Configuring gint.) + $(call qcmd,cd $(GLIBDIR) && ./configure --no-syscalls) + +# Make gint libraries. + $(GLIBDIR)/libgint.a $(GLIBDIR)/libc.a: $(GLIBDIR)/gcc.cfg + $(call bmsg,Making gint.) + $(call bcmd,make,gint,$(MAKE) $(GLIBDIR) libgint.a libc.a | sed 's/^/ /') + +# Clean gint libraries. + clean-gint: + $(call rmsg,Cleaning gint.) + -$(call qcmd,test -e $(GLIBDIR)/Makefile && \ + $(MAKE) $(GLIBDIR) distclean | sed 's/^/ /') + +.PHONY: all-gint clean-gint +#******************************************************************************# +# Binary-related targets # +#******************************************************************************# +# Make the binary. + all-bin: $(CHECKCFG) $(NAME).bin + +# Make the object directory. + $(OBJDIR): + $(call bcmd,mkdir,$@,$(MD) $@) + +# Make an object file out of an assembly source file. + $(OBJDIR)/%.o: $(SRCDIR)/%.s | $(OBJDIR) + $(call bcmd,as,$@,$(AS) -c -o $@ $<) + +# Make an object file out of a C source file. + $(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR) + $(call bcmd,cc,$@,$(CC) -c -o $@ $< $(CFLAGS)) + +# Make the ELF file. + $(NAME).elf: all-gint $(SRC:%=$(OBJDIR)/%.o) + $(call bcmd,ld,$@,$(LD) -o $@ $(SRC:%=$(OBJDIR)/%.o) $(LDFLAGS)) + +# Make the binary file. + $(NAME).bin: $(NAME).elf + $(call bcmd,objcopy,$@,$(OBJCOPY) -R .comment -R .bss -O binary $< $@) + +# Removing the objects directory. + mostlyclean-bin: + $(call rmsg,Removing the objects directory.) + $(call qcmd,$(RM) -r $(OBJDIR)) + $(call rmsg,Removing the ELF file.) + $(call qcmd,$(RM) *.elf) + + mclean-bin: mostlyclean-bin + +# Remove everything that was built. + clean-bin: mostlyclean-bin + $(call rmsg,Removing the final binary.) + $(call qcmd,$(RM) *.bin) + fclean-bin: clean-bin + +# Remake the binary. + re-bin: clean-bin all-bin + +.PHONY: all-bin mostlyclean-bin mclean-bin clean-bin fclean-bin re-bin +# End of file. diff --git a/src/p7os/cake.exe/Makefile.msg b/src/p7os/cake.exe/Makefile.msg new file mode 100755 index 0000000..6502666 --- /dev/null +++ b/src/p7os/cake.exe/Makefile.msg @@ -0,0 +1,63 @@ +#!/usr/bin/make -f +# The Makefile message subsystem. +# For nice logs. 5 dollars per log only. +#******************************************************************************# +# Colors and misc # +#******************************************************************************# +# Used colors ANSI modifiers escape codes + color_green := 32 + color_red := 31 + color_yellow := 33 + +# Newline - comes handy in some situations +define \n + + +endef + +#******************************************************************************# +# General messages # +#******************************************************************************# +# Command message - display basic info about the command, and run it. +define cmd +@$(if $(MAKE_FULL_LOG),,printf "\033[1;""$4""m>\033[0m \033[1m%s\033[0m %s\n" "$1" "$2";) + $(if $(MAKE_FULL_LOG),,@)$3 +endef + +# Quiet command - make it non-quiet if full log is enabled. +define qcmd +$(if $(MAKE_FULL_LOG),,@)$1 +endef + +# Normal message - display it. +define msg +$(if $(MAKE_FULL_LOG),,@printf "\033[1;""$2""m>\033[0m \033[1m%s\033[0m\n" "$1") +endef + +#******************************************************************************# +# Commands # +#******************************************************************************# +# Build command +define bcmd +$(call cmd,$1,$2,$3,$(color_green)) +endef + +#******************************************************************************# +# Messages # +#******************************************************************************# +# Build message +define bmsg +$(call msg,$1,$(color_green)) +endef + +# Remove message +define rmsg +$(call msg,$1,$(color_red)) +endef + +# Install message +define imsg +$(call msg,$1,$(color_yellow)) +endef + +# End of file. diff --git a/src/p7os/cake.exe/Makefile.vars b/src/p7os/cake.exe/Makefile.vars new file mode 100755 index 0000000..4d8c600 --- /dev/null +++ b/src/p7os/cake.exe/Makefile.vars @@ -0,0 +1,81 @@ +#!/usr/bin/make -f +#******************************************************************************# +# Include configuration # +#******************************************************************************# +-include Makefile.cfg + +#******************************************************************************# +# Project main information # +#******************************************************************************# +# Project name. + NAME := cake.exe + +# Maintainer information + MAINTAINER_NAME := Thomas \"Cakeisalie5\" Touhey + MAINTAINER_MAIL := thomas@touhey.fr + +# Project license + LICENSE := GPLv2 + +# Project version + VERSION_MAJOR := 0 + VERSION_MINOR := 1 + INDEV := yes + VERSION := $(VERSION_MAJOR).$(VERSION_MINOR)$(if $(INDEV),-indev) + +#******************************************************************************# +# Project directories # +#******************************************************************************# +# Headers directory - where all the headers are. + INCDIR := ./include + +# Sources directory - where all the source files are. + SRCDIR := ./src + +# Objects directory - where the objects will be put. + OBJDIR := ./obj + +# Gint lib directory + GLIBDIR := ./libgint + +# Gint include directory + GINCDIR := ./libgint/include + +#******************************************************************************# +# Binary utilities # +#******************************************************************************# +# C Compiler + CC := sh3eb-elf-gcc +# - Check flags (for warnings enabling) + CHKFLAGS := -Wall -Wextra +# - More flags (for profiling, ...) +#CMOREFLAGS := +# - All of the C compiler flags + CFLAGS := -m3 -mb -Os -ffreestanding -I $(INCDIR) -I $(GINCDIR) $(CHKFLAGS) \ + -D AUTHOR="$(AUTHOR_NAME)" -D AUTHOR_MAIL="$(AUTHOR_MAIL)" \ + -D LICENSE="$(LICENSE)" -D VERSION="$(VERSION)" \ + $(CMOREFLAGS) + +# Assembler + AS := sh3eb-elf-as +# Linker + LD := sh3eb-elf-gcc +# - Linker flags + LDFLAGS := -nostdlib -T osupd.ld -L $(GLIBDIR) -lgint -lc -lgcc + +# Maker. + MAKE := make --no-print-directory -C +# Object copier + OBJCOPY := sh3eb-elf-objcopy +# Directory maker + MD := mkdir -p +# File remover + RM := rm -f + +#******************************************************************************# +# Look for sources # +#******************************************************************************# +# SOURCES + SRC := $(basename $(notdir $(shell find $(SRCDIR) -name "*.[cs]"))) + +# END OF FILE diff --git a/src/p7os/cake.exe/README.md b/src/p7os/cake.exe/README.md new file mode 100644 index 0000000..f65b1d1 --- /dev/null +++ b/src/p7os/cake.exe/README.md @@ -0,0 +1,40 @@ +# cake.exe - communautary Update.Exe for CASIO calculators +## Introduction +There is a special command in CASIO's Communication Protocol 7.00: the 0x56 +command, considered by the community to be the "upload and run" command. + +CASIO uses it to modify the OS on the calculator: +- The tools uploads an UpdateExe kernel; +- The OS checks the UpdateExe, transfers it to RAM and transfers + full machine control to it; +- The kernel sets up a Protocol 7 server; +- The tool communicates with this server to make operations on the calculator + (mainly on flash memory): backup the OS, flash a new OS, ... + +Simon Lothar made his own for fxRemote, using bootcode functions for displaying +and communicating (USB, Protocol 7). +This project is a community-made update.exe to imitate proprietary CASIO ones +and Simon Lothar's one. + +## Restrictions +In order to be SH3 and SH4 compatible, the size of the kernel musn't be +greater than 64Kio. Also, a full independence from the OS and the bootcode +should be seeked, so that this update.exe can also serve for flash-erasure +operations - which may come in a very very long time. + +Also, the binary should finish with an identification block -- +see `src/endblock.c` for details. + +## Making dependencies +| Name | Version | +| -------------------------------------------------- | ------- | +| [sh3eb-elf-gcc](https://gcc.gnu.org/) | >= 4.9 | +| [binutils](https://www.gnu.org/software/binutils/) | >= 2.25 | + +## Building + +Just `make`. + +Other useful targets: +- `mostlyclean`, `clean`: remove built files. +- `re`: remake. diff --git a/src/p7os/cake.exe/TODO.md b/src/p7os/cake.exe/TODO.md new file mode 100644 index 0000000..fa13bec --- /dev/null +++ b/src/p7os/cake.exe/TODO.md @@ -0,0 +1,8 @@ +# TODO in Update.exe +## As soon as possible +- Integrate gint (with USB implemented) +- Make a P7 server + +## Later +- Find out update.exe-specific commands +- Implement flash commands diff --git a/src/p7os/cake.exe/configure b/src/p7os/cake.exe/configure new file mode 100755 index 0000000..af15630 --- /dev/null +++ b/src/p7os/cake.exe/configure @@ -0,0 +1,97 @@ +#!/bin/sh +cd "$(dirname "$0")" +#******************************************************************************# +# Defaults # +#******************************************************************************# +# Project variables +name="$(make -s getname)" +version="$(make -s getversion)" + +# Maintainer +maintainer="$(make -s getmaintainer)" + +# Make options +make_full_log= + +#******************************************************************************# +# Help message # +#******************************************************************************# +usage() { +cat </dev/null + +# Write +exec 3>&1 1>Makefile.cfg +cat <&3 3>&- +chmod +x Makefile.cfg + +# Finish +echo "Configuration loaded, you can make now." + +# End of file. diff --git a/src/p7os/cake.exe/include/main.h b/src/p7os/cake.exe/include/main.h new file mode 100644 index 0000000..a519344 --- /dev/null +++ b/src/p7os/cake.exe/include/main.h @@ -0,0 +1,10 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* main.h |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: cake.exe | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 18:05:44 |___/ */ +/* */ +/* ************************************************************************** */ + diff --git a/src/p7os/cake.exe/libgint/.gitignore b/src/p7os/cake.exe/libgint/.gitignore new file mode 100644 index 0000000..41fea35 --- /dev/null +++ b/src/p7os/cake.exe/libgint/.gitignore @@ -0,0 +1,20 @@ +# Build directory +build/** + +# Sublime Text files +*.sublime-project +*.sublime-workspace + +# Object files. +*.o + +# Some notes. +LIBC + +# Output files +libc.a +libgint.a +gintdemo.g1a + +# Configuration files +gcc.cfg diff --git a/src/p7os/cake.exe/libgint/Makefile b/src/p7os/cake.exe/libgint/Makefile new file mode 100755 index 0000000..e58aff7 --- /dev/null +++ b/src/p7os/cake.exe/libgint/Makefile @@ -0,0 +1,210 @@ +#! /usr/bin/make -f +#--- +# +# gint project Makefile. +# +#--- + + + +#--- +# Project variables. +#--- + +# Modules +modules-gint = core clock keyboard mmu mpu rtc screen timer \ + bopti display gray tales events +modules-libc = setjmp string stdio stdlib time + +# Targets +target-g1a = gintdemo.g1a +target-lib = libgint.a +target-std = libc.a + +# Tools +cc = sh3eb-elf-gcc +as = sh3eb-elf-as +ar = sh3eb-elf-ar +ob = sh3eb-elf-objcopy +wr = g1a-wrapper + +# Flags +cflags = -m3 -mb -nostdlib -I include -ffreestanding -std=c11 -Os \ + -W -Wall -Wextra -pedantic @gcc.cfg + +# Demo application (could be done better) +demo-src = $(notdir $(wildcard demo/*.[cs])) +demo-dep = $(wildcard demo/*.h) +demo-ld = demo/gintdemo.ld +demo-icon = demo/icon.bmp +demo-res = $(notdir $(wildcard demo/resources/*)) +demo-obj = $(patsubst %,build/demo_%.o,$(demo-src) $(demo-res)) +demo-elf = build/gintdemo.elf +demo-bin = build/gintdemo.bin +demo-libs = -L. -lgint -lc -lgcc + +# Specific objects +obj-lib-spec = build/display_font_system.bmp.o +obj-std-spec = + +# Configuration files +config = gcc.cfg + +#--- +# Automatic variables. +#--- + +# Modules are subfolders of src/. +modules = $(modules-gint) $(modules-libc) + +define n +# This is a newline character. + +endef + +ifeq ("$(wildcard $(config))","") +$(error "Configuration files are missing. Did you ./configure?") +endif + +# Module-scope variables. +$(foreach mod, $(modules), $(eval \ + mod-$(mod)-c = $(notdir $(wildcard src/$(mod)/*.c)) $n\ + mod-$(mod)-asm = $(notdir $(wildcard src/$(mod)/*.s)) $n\ + mod-$(mod)-src = $$(mod-$(mod)-c)$$(mod-$(mod)-asm) $n\ + mod-$(mod)-obj = $$(patsubst %,build/$(mod)_%.o,$$(mod-$(mod)-src)) \ +)) + +# Target-scope variables. +obj-std = $(foreach mod,$(modules-libc),$(mod-$(mod)-obj)) $(obj-std-spec) +obj-lib = $(foreach mod,$(modules-gint),$(mod-$(mod)-obj)) $(obj-lib-spec) + +# Dependencies +hdr-dep = $(wildcard include/*.h include/internals/*.h) + + + +#--- +# Rule templates. +#--- + +#ifndef VERBOSE +#$(note "default full log") +#VERBOSE = +#endif + +# C source file template: +# $1 module name +# $2 filename +# $3 dependencies +define rule-c-source +build/$1_$2.o: src/$1/$2 $3 $(config) + $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $$<\n') + $(if $(VERBOSE),,@) $(cc) -c $$< -o $$@ $(cflags) -I src/$1 +endef + +# asm source file template: +# $1 module name +# $2 filename +define rule-asm-source +build/$1_$2.o: src/$1/$2 $(config) + $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m as $$<\n') + $(if $(VERBOSE),,@) $(as) -c $$< -o $$@ +endef + + + +#--- +# Building. +#--- + +# Generic rules + +all: $(config) $(target-std) $(target-lib) $(target-g1a) + @ printf '\e[32;1mmsg \u00bb\e[0m All done!\n' + +build: + $(if $(VERBOSE),,@ printf '\e[35;1mdir \u00bb\e[0m mkdir $@\n') + $(if $(VERBOSE),,@) mkdir -p $@ + +$(obj-std) $(obj-lib) $(demo-obj): | build + +$(target-std): $(config) $(obj-std) + $(if $(VERBOSE),,@ printf '\e[35;1mlib \u00bb\e[0m ar $@\n') + $(if $(VERBOSE),,@) $(ar) rcs $@ $(obj-std) + @ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built libc (' + @ printf $$(stat -c %s $@) + @ printf ' bytes)\n\n' + +$(target-lib): $(config) $(target-std) $(obj-lib) + $(if $(VERBOSE),,@ printf '\e[35;1mlib \u00bb\e[0m ar $@\n') + $(if $(VERBOSE),,@) $(ar) rcs $@ $(obj-lib) + @ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built libgint (' + @ printf $$(stat -c %s $@) + @ printf ' bytes)\n\n' + +$(target-g1a): $(config) $(target-std) $(target-lib) $(demo-obj) + $(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m ld -o $(demo-elf)\n') + $(if $(VERBOSE),,@) $(cc) -o $(demo-elf) $(cflags) -T $(demo-ld) $(demo-obj) $(demo-libs) + $(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m objcopy -o $(demo-bin)\n') + $(if $(VERBOSE),,@) $(ob) -R .comment -R .bss -O binary $(demo-elf) $(demo-bin) + $(if $(VERBOSE),,@ printf '\e[35;1mexe \u00bb\e[0m g1a-wrapper -o $@\n') + $(if $(VERBOSE),,@) $(wr) $(demo-bin) -o $@ -i $(demo-icon) + @ printf '\e[32;1mmsg \u00bb\e[0m Succesfully built demo application (' + @ printf $$(stat -c %s $@) + @ printf ' bytes)\n\n' + +# Automated rules + +$(foreach mod,$(modules), \ + $(foreach source,$(mod-$(mod)-c), $(eval \ + $(call rule-c-source,$(mod),$(source),$(hdr-dep)))) \ + $(foreach source,$(mod-$(mod)-asm), $(eval \ + $(call rule-asm-source,$(mod),$(source)))) \ +) + +# Specific rules + +# This one should not be optimized. It makes __attribute__((interrupt_handler)) +# buggy... maybe. Anyway there's some bug in this file that I can't fix now. +build/core_gint.c.o: src/core/gint.c $(mod-core-dep) $(config) + $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $<\n') + $(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(cflags) -I src/core -O0 + +build/display_font_system.bmp.o: src/display/font_system.bmp + $(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n') + $(if $(VERBOSE),,@) fxconv $< -o $@ --font -n gint_font_system + +# Demo application + +build/demo_%.c.o: demo/%.c $(hdr-dep) $(demo-dep) $(config) + $(if $(VERBOSE),,@ printf '\e[34;1msrc \u00bb\e[0m cc $<\n') + $(if $(VERBOSE),,@) $(cc) -c $< -o $@ $(cflags) + +build/demo_font_%.bmp.o: demo/resources/font_%.bmp + $(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n') + $(if $(VERBOSE),,@) fxconv $< -o $@ --font -n $(patsubst demo/resources/%.bmp,res_%,$<) + +build/demo_%.bmp.o: demo/resources/%.bmp + $(if $(VERBOSE),,@ printf '\e[36;1mres \u00bb\e[0m fxconv $<\n') + $(if $(VERBOSE),,@) fxconv $< -o $@ -n $(patsubst demo/resources/%.bmp,res_%,$<) + + + +#--- +# Cleaning and others. +#--- + +clean: + @ rm -rf build + +mrproper: clean + @ rm -f $(target-g1a) $(target-lib) $(target-std) + @ rm -f $(config) + +distclean: mrproper + +install: + p7 send -f $(target-g1a) + + +.PHONY: all clean mrproper distclean install help diff --git a/src/p7os/cake.exe/libgint/README.md b/src/p7os/cake.exe/libgint/README.md new file mode 100644 index 0000000..f3b5fad --- /dev/null +++ b/src/p7os/cake.exe/libgint/README.md @@ -0,0 +1,72 @@ +gint project +============ + +gint (pronounce 'guin') is a low-level library for fx-9860G calculators. It +provides the tools needed to develop programs under Linux using the gcc +toolchain (sh3eb-elf). + +By the way, gint is free software; you may use it for any purpose, share it, +modify it and share you changes. No credit of any kind is needed, though +appreciated. + + + +Interrupt handler +----------------- + +The interrupt handler is the lowest-level part of the library. It directly +accesses the peripheral modules and performs keyboard analyzes, swaps screen +buffers, etc. + +gint does not allow user programs to use their own handlers. However, it is +possible to map interrupt-driven events to user callbacks using the public API +(which is not possible with the system's interrupt handler). This may be +particularly useful for timers and RTC (the 16 Hz interrupt can be used as a +basis for a physical engine). + + + +Public Interface +---------------- + +gint's API provides access to keyboard, timers, clock and more. It does some +powerful drawing and offers reliable multi-getkey, a gray engine, facilitates +register access and implements a few standard functions. + + + +Building and installing +----------------------- + +There are some dependencies: +* The `sh3eb-elf` toolchain somewhere in the PATH +* The fxSDK installed and available in the PATH + +The easiest way to build gint is simply to enter a terminal and execute `make`. +This will build the following components : +* `libgint.a`, the gint library +* `libc.a`, a (very) few standard procedures +* `gintdemo.g1a`, a test application + +The common `clean`, `mrproper`, and `distclean` rules will clean the directory. + + + +Source organization +------------------- + +gint is made of *modules*. Each module may have any of the following +components: +* A header file in `/include` +* An internal header file in `/include/internals` +* Single-function source files in `/src/module`: to avoid linking against the + whole library, some functions have their own object files. Their names are + those of the functions. +* Other source files in `/src/module`: contain multiple functions that always + work together, or are lightweight enough not to be separated. Their names + often begin with `module_`. +* Other files in `/src/module`: the `display` module contains a font, I think. + +The demo application is in the `demo` directory. + +The `doc` folder contains some documentation. diff --git a/src/p7os/cake.exe/libgint/TODO b/src/p7os/cake.exe/libgint/TODO new file mode 100644 index 0000000..70a42f7 --- /dev/null +++ b/src/p7os/cake.exe/libgint/TODO @@ -0,0 +1,33 @@ +Bugs to fix: +- Left-vram overflow when rendering text +- A few key hits ignored after leaving the application (could not reproduce) +- Lost keyboard control at startup (could not reproduce) +- Back-light issues (0xa400012c on SH3, 0xa4050138 on SH4) + +Simple improvements: +- bopti: Monochrome bitmaps blending modes +- bopti: Partial transparency +- demo: Try 284x124 at (-60, -28) (all disadvantages) +- display: Rectangle-based drawing functions +- tales: Test all font encodings +- time: Compute CLOCKS_PER_SEC +- timer: Add duration and frequency settings +- core: Add VBR handlers debugging information (if possible) +- core: Implement all callbacks and a complete user API + +Modules to implement: +- Serial communication +- Sound playback and synthesizing +- Handle errors within errno + +Things to investigate: +- Packed bit fields alignment +- Registers that may need to be saved within setjmp() +- Registers that may need to be saved and restored by gint +- Possible bug when optimizing __attribute__((interrupt_handler)) + +Configuration: +- ATEXIT_MAX (16) +- RTC_CB_ARRAY_SIZE (5) +- EVENTS_QUEUE_SIZE (64) +- GINT_NO_SYSCALLS (undefined) diff --git a/src/p7os/cake.exe/libgint/configure b/src/p7os/cake.exe/libgint/configure new file mode 100755 index 0000000..4f70807 --- /dev/null +++ b/src/p7os/cake.exe/libgint/configure @@ -0,0 +1,78 @@ +#! /bin/bash + +declare -A conf +conf[ATEXIT_MAX]=16 +conf[RTC_CB_ARRAY_SIZE]=5 +conf[EVENTS_QUEUE_SIZE]=64 +conf[GINT_NO_SYSCALLS]= +fail=false +output="gcc.cfg" + +help() +{ + cat << EOF +Configuration script for the gint library. + +Options that affect the behavior of the library: + --no-syscalls [default: false] + Never use syscalls. Expect some trouble with the malloc() function... + Do not trigger this option unless you know what you are doing. + +Options that customize size limits: + --atexit-max= [default: 16] + Number of exit handlers that can be registered by atexit(). + --rtc-callbacks= [default: 5] + Number of RTC callbacks that can be registered. + --events-queue-size= [default: 64] + Number of events simultaneously stored in the event queue. +EOF + + exit 0 +} + +for arg; do case "$arg" in + -h | --help) help;; + --no-syscalls) conf[GINT_NO_SYSCALLS]=true;; + + --atexit-max=*) + size=${arg#*=} + if [[ $size == +([0-9]) ]]; then + conf[ATEXIT_MAX]=$size + else echo "error: --atexit-max expects an integer value" + fail=true; fi;; + --rtc-callbacks=*) + size=${arg#*=} + if [[ $size == +([0-9]) ]]; then + conf[RTC_CB_ARRAY_SIZE]=$size + else echo "error: --rtc-callbacks expects an integer value" + fail=true; fi;; + --events-queue-size=*) + size=${arg#*=} + if [[ $size == +([0-9]) ]]; then + conf[EVENTS_QUEUE_SIZE]=$size + else echo "error: --events-queue-size expects an integer value" + fail=true; fi;; + + --atexit-max | --rtc-callbacks | --events-queue-size) + echo "error: syntax for $arg is $arg=";; + + *) + echo "error: unrecognized argument '$arg'"; fail=true;; +esac; done + +output_config() +{ + echo "-D ATEXIT_MAX=${conf[ATEXIT_MAX]}" + echo "-D RTC_CB_ARRAY_SIZE=${conf[RTC_CB_ARRAY_SIZE]}" + echo "-D EVENTS_QUEUE_SIZE=${conf[EVENTS_QUEUE_SIZE]}" + if [ "${conf[GINT_NO_SYSCALLS]}" != "" ]; then + echo "-D GINT_NO_SYSCALLS" + fi +} + +if $fail; then + echo "Configuration has not been modified." +else + output_config > $output + echo "Configuration details have been output to file $output." +fi diff --git a/src/p7os/cake.exe/libgint/demo/gintdemo.c b/src/p7os/cake.exe/libgint/demo/gintdemo.c new file mode 100644 index 0000000..7284c35 --- /dev/null +++ b/src/p7os/cake.exe/libgint/demo/gintdemo.c @@ -0,0 +1,531 @@ +#include "gintdemo.h" + +#include +#include +#include +#include +#include + +#include + + + +//--- +// A few procedures for displaying text aligned on a 21*8 grid. +// Not really beautiful... but this will do. +//--- + +void locate(int x, int y, const char *str) +{ + if(x < 1 || x > 21 || y < 1 || y > 8) return; + if(gray_runs()) gtext(x * 6 - 5, y * 8 - 8, str); + else dtext(x * 6 - 5, y * 8 - 8, str); +} + +void print(int x, int y, const char *format, ...) +{ + va_list args; + + va_start(args, format); + __printf(0, format, args); + va_end(args); + + locate(x, y, __stdio_buffer); +} + +/* + printf_test() + Tests formatting functions. + +void printf_test(void) +{ + dclear(); + locate(1, 1, "Formatted printing"); + + print(2, 3, "%%4.2d 5 :\"%4.2d\"", 5); + print(2, 4, "%%-3c '&':\"%-3c\"", '&'); + print(2, 5, "%%#05x 27 :\"%#05x\"", 27); + print(2, 6, "%%1s \"tr\":\"%1s\"", "tr"); + print(2, 7, "%%6p NULL :\"%6p\"", NULL); + + dupdate(); + while(getkey() != KEY_EXIT); +} +*/ + +/* +static const unsigned char screen[1024] = { +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 7, 159, 0, 0, 1, 192, 0, 0, 0, 0, 0, 121, 240, 0, 0, 0, +31, 191, 192, 0, 3, 224, 27, 216, 0, 0, 1, 251, 252, 0, 0, 0, 57, 247, 222, +30, 7, 240, 36, 36, 62, 25, 131, 159, 24, 255, 129, 224, 0, 227, 142, 126, 1, +192, 45, 172, 127, 127, 192, 14, 1, 255, 199, 224, 0, 227, 140, 240, 1, 192, +26, 88, 115, 127, 224, 14, 57, 221, 207, 0, 0, 227, 13, 192, 1, 192, 34, 68, +120, 30, 0, 14, 25, 156, 220, 0, 0, 227, 253, 252, 1, 192, 36, 36, 126, 28, +0, 14, 219, 156, 223, 192, 0, 227, 253, 252, 1, 192, 36, 36, 31, 12, 0, 46, +27, 140, 223, 192, 0, 227, 141, 193, 193, 192, 40, 20, 7, 140, 0, 206, 25, 140, +220, 28, 0, 227, 140, 225, 129, 199, 24, 24, 99, 156, 1, 14, 25, 204, 206, 24, +0, 227, 142, 127, 1, 195, 39, 228, 255, 156, 2, 14, 24, 237, 199, 240, 1, 247, +222, 62, 1, 198, 44, 44, 223, 30, 2, 31, 28, 237, 131, 224, 1, 224, 0, 0, 3, +254, 27, 216, 0, 0, 4, 30, 0, 0, 0, 0, 3, 192, 0, 0, 7, 252, 0, 0, 0, 0, 4, +60, 1, 249, 240, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 4, 0, 97, 240, 56, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 224, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +4, 0, 47, 192, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 32, 255, 128, 63, 128, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 32, 255, 0, 48, 78, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 15, 176, 255, 0, 112, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 8, 56, 255, 0, +96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, 8, 60, 255, 0, 224, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 130, 56, 126, 255, 3, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 192, +62, 255, 15, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 14, 191, 255, 192, 0, +0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 6, 129, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, +1, 0, 0, 6, 0, 255, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 7, 128, 63, 192, +0, 0, 96, 1, 224, 1, 0, 0, 0, 2, 0, 0, 7, 0, 31, 192, 0, 0, 95, 1, 11, 68, 88, +0, 0, 4, 0, 0, 7, 128, 31, 192, 0, 1, 192, 129, 204, 85, 100, 0, 0, 8, 0, 0, +15, 128, 63, 224, 0, 0, 95, 1, 8, 85, 68, 0, 1, 144, 0, 0, 31, 128, 143, 224, +64, 0, 96, 1, 232, 41, 68, 0, 2, 96, 0, 31, 255, 129, 7, 248, 96, 0, 0, 0, 0, +0, 0, 0, 4, 0, 0, 96, 254, 129, 7, 254, 96, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 128, +254, 131, 135, 255, 224, 0, 0, 1, 192, 64, 16, 0, 8, 0, 7, 0, 254, 131, 255, +63, 224, 0, 0, 1, 38, 113, 208, 0, 8, 0, 13, 0, 222, 147, 254, 31, 224, 0, 0, +1, 41, 74, 80, 0, 8, 0, 25, 0, 222, 67, 254, 31, 160, 0, 0, 1, 41, 74, 80, 0, +12, 0, 49, 0, 222, 19, 254, 62, 48, 0, 0, 1, 198, 113, 208, 0, 2, 0, 32, 128, +222, 195, 255, 252, 56, 0, 0, 0, 0, 0, 0, 0, 2, 0, 124, 64, 220, 151, 135, 248, +127, 0, 0, 0, 0, 0, 0, 0, 2, 0, 66, 32, 221, 223, 7, 240, 255, 0, 0, 0, 0, 0, +0, 0, 2, 0, 129, 23, 93, 159, 15, 241, 131, 0, 0, 0, 0, 0, 0, 0, 4, 0, 128, +136, 217, 95, 3, 226, 9, 0, 0, 1, 240, 0, 0, 0, 4, 0, 128, 72, 89, 95, 129, +228, 18, 0, 0, 0, 0, 0, 0, 0, 4, 1, 0, 72, 73, 127, 128, 224, 36, 0, 0, 0, 0, +0, 0, 0, 28, 1, 0, 76, 129, 127, 192, 96, 8, 0, 0, 0, 0, 0, 0, 0, 16, 1, 0, +231, 203, 124, 96, 64, 0, 0, 0, 0, 0, 0, 0, 0, 16, 1, 1, 28, 123, 240, 12, 64, +1, 0, 0, 0, 0, 0, 0, 0, 16, 1, 2, 28, 143, 128, 15, 192, 7, 0, 0, 0, 0, 0, 0, +0, 16, 1, 4, 17, 143, 24, 15, 192, 14, 0, 0, 0, 0, 0, 0, 0, 28, 1, 4, 1, 135, +24, 31, 192, 24, 0, 0, 0, 0, 0, 0, 0, 18, 1, 62, 1, 135, 248, 63, 224, 192, +0, 0, 0, 0, 0, 0, 0, 35, 1, 195, 1, 135, 128, 254, 126, 1, 0, 0, 0, 0, 0, 0, +0, 35, 193, 131, 195, 135, 255, 248, 112, 1, 0, 0, 0, 0, 0, 0, 0, 67, 241, 131, +14, 207, 255, 192, 224, 3, 0, 0, 0, 0, 0, 0, 3, 67, 15, 143, 56, 255, 7, 1, +224, 7, 0, 0, 0, 0, 0, 0, 28, 130, 7, 255, 112, 204, 7, 131, 224, 31, 0, 0, +0, 0, 0, 0, 32, 134, 30, 29, 120, 156, 7, 255, 224, 127, 0, 0, 0, 0, 0, 63, +197, 206, 60, 56, 192, 248, 15, 255, 248, 255, 0, 0, 0, 0, 0, 120, 5, 227, 248, +56, 195, 248, 127, 191, 254, 63, 0, 0, 0, 0, 7, 254, 255, 193, 255, 15, 193, +255, 15, 31, 252, 31 }; + +void ML_bmp_or_cl(const unsigned char *bmp, int x, int y, int width, int height) +{ + unsigned short line; + char shift, *screen, *p; + int i, j, real_width, begin_x, end_x, begin_y, end_y; + char bool1=1, bool2=1, bool3; + if(!bmp || x<1-width || x>127 || y<1-height || y>63 || height<1 || width<1) return; + p = (char*)&line; + real_width = (width-1>>3<<3)+8; + if(y < 0) begin_y = -y; + else begin_y = 0; + if(y+height > 64) end_y = 64-y; + else end_y = height; + shift = 8-(x&7); + if(x<0) + { + begin_x = -x>>3; + if(shift != 8) bool1 = 0; + } else begin_x = 0; + if(x+real_width > 128) end_x = 15-(x>>3), bool2 = 0; + else end_x = real_width-1>>3; + bool3 = (end_x == real_width-1>>3); + screen = display_getCurrentVRAM()+(y+begin_y<<4)+(x>>3); + + for(i=begin_y ; i>3)+begin_x] << shift; + if(bool1) screen[begin_x] |= *p; + if(shift!=8) screen[begin_x+1] |= *(p+1); + for(j=begin_x+1 ; j>3)+j] << shift; + screen[j] |= *p; + if(shift!=8) screen[j+1] |= *(p+1); + } + } + line = bmp[i*(real_width>>3)+end_x]; + if(bool3) line &= -1< +void debug(void) +{ + extern Image res_screen_start; + struct mod_tmu *timer; + int time1, time2; + int i; + + timer_get(TIMER_USER, &timer, NULL); + + dclear(); + ML_bmp_or_cl(screen, 1, 1, 128, 64); + dupdate(); + getkey(); + + dclear(); + dimage(&res_screen_start, 1, 1); + dupdate(); + getkey(); + + dclear(); + dtext("ML...", 2, 2); + dupdate(); + + timer_start(TIMER_USER, 0x0fffffff, TIMER_Po_4, NULL, 0); + for(i = 0; i < 1000; i++) ML_bmp_or_cl(screen, 1, 1, 128, 64); + time1 = timer->TCNT; + timer_stop(TIMER_USER); + time1 = 0x0fffffff - time1; + + dclear(); + dtext("gint...", 2, 2); + dupdate(); + + timer_start(TIMER_USER, 0x0fffffff, TIMER_Po_4, NULL, 0); + for(i = 0; i < 1000; i++) dimage(&res_screen_start, 1, 1); + time2 = timer->TCNT; + timer_stop(TIMER_USER); + time2 = 0x0fffffff - time2; + + dclear(); + print_hex(time1, 2, 2); + print_hex(time2, 2, 9); + dupdate(); + while(getkey() != KEY_EXIT); +} +*/ + +/* + tlb_debug() + Displays the TLB contents and some information. Only available for + SH7705, because the SH7305's TLB is much more complicated. + +void tlb_debug(void) +{ + // Entry address address (pointer in the address array), entry data + // address (pointer in the data address), and their contents. + unsigned int address, data, a, d; + // Virtual page number and physical page number. + unsigned int vpn, ppn; + // Contents of register MMUCR. + unsigned mmucr; + + int i, r, key = 0; + int way = 0, entry = 0; + int pointer_base; + + const char *protection[] = { "pr", "prw", "ar", "arw" }; + mmucr = *((volatile unsigned int *)gint_reg(Register_MMUCR)); + + dclear(); + locate("MMU register info", 1, 1); + locate("MMUCR.IX = ", 2, 3); + locate(mmucr & 0x02 ? "1" : "0", 13, 3); + dupdate(); + getkey(); + + while(key != KEY_EXIT && way < 4) + { + dclear(); + + print(1, 1, "TLB way=%d %d-%d", way, entry, + entry > 29 ? 31 : entry + 2); + + for(i = 0; i < 3 && entry < 32; i++, entry++) + { + address = 0xf2000000 | (entry << 12) | (way << 8); + data = 0xf3000000 | (entry << 12) | (way << 8); + + a = *((volatile unsigned int *)address); + d = *((volatile unsigned int *)data); + + ppn = (d >> 10) & 0x00007ffff; + // 4-kbyte page + if(d & 0x08) + { + vpn = (a >> 12) | entry; + pointer_base = vpn << 12; + } + // 1-kbyte page + else + { + vpn = (a >> 10) | (entry << 2); + pointer_base = vpn << 10; + } + + r = 2 * i + 3; + print(1, r, "%08x :%08x", pointer_base, ppn << 10); + + r++; + locate((d & 0x08) ? "4k" : "1k", 1, r); + print(5, r, "pr=%s", protection[(d >> 5) & 3]); + locate((d & 0x02) ? "shared" : "exclusive", 13, r); + } + + if(entry == 32) entry = 0, way++; + + dupdate(); + key = getkey(); + } +} +*/ + +/* + main_menu() + Displays the main menu and returns user's choice: 0 for [EXIT], + application numbers otherwise. Sets the ctaegory and application + number. +*/ +void main_menu(int *category, int *app) +{ + //--- + // Quite a few things to declare... + //--- + + extern Image res_opt_menu; + + const char *mpu, *mpu_names[] = { + "Unknown", + "SH7337", + "SH7355", + "SH7305", + "SH7724", + "[error]" + }; + + const char *list_tests[] = { + "Keyboard", + "Gray engine", + "Image rendering", + "Text rendering", + "Real-time clock", + "Clocks and timers", + NULL + }; + const char *list_perfs[] = { + "Image rendering", + "Text rendering", + NULL + }; + const char *list_debug[] = { + "View TLB (SH3 only)", + NULL + }; + const char **list = NULL; + int list_len = 0; + + extern unsigned int bgint, egint; + extern unsigned int romdata; + int gint_size = (char *)&egint - (char *)&bgint; + + + + static int tab = 0, index = 0, scroll = 0; + // Set to 1 when interface has to be redrawn. + int leave = 1; + int i; + + mpu = mpu_names[MPU_CURRENT < 5 ? MPU_CURRENT : 5]; + text_configure(NULL, Color_Black); + + while(1) + { + //--- + // Displaying the current tab. + //--- + + dclear(); + dupdate(); + + switch(tab) + { + case 0: + locate(1, 1, "Demo application"); + print(2, 3, "gint version: %5s", GINT_VERSION_STR); + print(2, 4, "handler size: %5d", gint_size); + print(2, 5, "mpu type: %7s", mpu); + print(2, 6, "romdata: %08x", &romdata); + + list = NULL; + break; + + case 1: + locate(1, 1, "Test list"); + list = list_tests; + break; + + case 2: + locate(1, 1, "Performance"); + list = list_perfs; + break; + + case 3: + locate(1, 1, "Debug"); + list = list_debug; + break; + + default: + print(1, 1, "Tab %d", tab); + break; + } + dimage(0, 56, &res_opt_menu); + + if(list) + { + list_len = 0; + while(list[list_len]) list_len++; + + for(i = scroll; list[i] && i < scroll + 6; i++) + locate(2, i - scroll + 2, list[i]); + + if(scroll > 0) locate(20, 2, "\x0d"); + if(scroll + 6 < list_len) locate(20, 7, "\x0e"); + + dreverse_area(0, 8 * (index - scroll) + 8, 127, + 8 * (index - scroll) + 15); + } + dupdate(); + + //--- + // Waiting for events. + //--- + + do + { + leave = 1; + + switch(getkey()) + { + case KEY_F1: + tab = 0; + index = 0; + break; + case KEY_F2: + tab = 1; + index = 0; + scroll = 0; + break; + case KEY_F3: + tab = 2; + index = 0; + scroll = 0; + break; + case KEY_F4: + tab = 3; + index = 0; + scroll = 0; + break; + + case KEY_UP: + if(list && list_len > 1) + { + if(index) + { + index--; + if(index < scroll) scroll--; + } + else + { + index = list_len - 1; + scroll = list_len - 6; + if(scroll < 0) scroll = 0; + } + } + else leave = 0; + break; + case KEY_DOWN: + if(list && list_len > 1) + { + if(list[index + 1]) + { + index++; + if(index >= scroll + 6) + scroll++; + } + else + { + index = 0; + scroll = 0; + } + } + else leave = 0; + break; + + case KEY_EXE: + if(!tab) break; + if(category) *category = tab; + if(app) *app = index + 1; + return; + + case KEY_MENU: + if(category) *category = 0; + if(app) *app = 0; + return; + + default: + leave = 0; + } + } + while(!leave); + } + + if(category) *category = 0; + if(app) *app = 0; + return; +} + +/* + main() + No need for description. +*/ +int main(void) +{ + int category, app; + + while(1) + { + main_menu(&category, &app); + if(!category) break; + + switch((category << 8) | app) + { + case 0x0101: + test_keyboard(); + break; + case 0x0102: + test_gray(); + break; + case 0x0103: + test_bopti(); + break; + case 0x0104: + test_tales(); + break; + case 0x0105: + test_rtc(); + break; + case 0x0106: + test_timer(); + break; + + case 0x0201: +// perf_bopti(); + break; + case 0x0202: +// perf_tales(); + break; + + case 0x0301: +// if(isSH3()) debug_tlb(); + break; + } + } + + return 0; +} diff --git a/src/p7os/cake.exe/libgint/demo/gintdemo.h b/src/p7os/cake.exe/libgint/demo/gintdemo.h new file mode 100644 index 0000000..1d32bcd --- /dev/null +++ b/src/p7os/cake.exe/libgint/demo/gintdemo.h @@ -0,0 +1,114 @@ +//--- +// +// gint demo application +// +// Displays some tests cases for many features of the library. +// +//--- + +#ifndef _GINTDEMO_H +#define _GINTDEMO_H + +//--- +// Main routines and common functions. +//--- + +/* + main() + No need for description. +*/ +int main(void); + +/* + main_menu() + Displays the main menu and returns user's choice by setting the + category and application. Category is 0 when the user leaves the + application. +*/ +void main_menu(int *category, int *app); + +/* + locate() + Displays text using a system-like monospaced font on a 21*8 grid. +*/ +void locate(int x, int y, const char *str); + +/* + print() + Locates a string using formatted printing. +*/ +void print(int x, int y, const char *format, ...); + + + +//--- +// Test applications. +//--- + +/* + test_keyboard() + Displays a real-time multigetkey() and the keyboard state. +*/ +void test_keyboard(void); + +/* + test_gray() + Lets the user set the gray delays and see the results. +*/ +void test_gray(void); + +/* + test_bopti() + Displays and moves many kinds of bitmaps. +*/ +void test_bopti(void); + +/* + test_tales() + Displays some text using different modes and clipping options. +*/ +void test_tales(void); + +/* + test_rtc() + Just a clock. +*/ +void test_rtc(void); + +/* + test_timer() + Clock timer and timer precision. +*/ +void test_timer(void); + + + +//--- +// Performance applications. +//--- + +/* + perf_bopti() + Compares bopti and MonochromeLib. +*/ +void perf_bopti(void); + +/* + perf_tales() + Compares tales and the system's text rendering functions. +*/ +void perf_tales(void); + + + +//--- +// Debug applications. +//--- + +/* + debug_tlb() + On SH7705, displays the TLB contents. Does nothing on SH7305. +*/ +void debug_tlb(void); + +#endif // _GINTDEMO_H diff --git a/src/p7os/cake.exe/libgint/demo/gintdemo.ld b/src/p7os/cake.exe/libgint/demo/gintdemo.ld new file mode 100644 index 0000000..49062c9 --- /dev/null +++ b/src/p7os/cake.exe/libgint/demo/gintdemo.ld @@ -0,0 +1,110 @@ +/* + This linker script links the object files when generating the ELF + output. Note how symbols romdata, bbss, ebss, bdata and edata are used + in the initialization routine (crt0.c) to initialize the application. + + Two ram areas are specified. The "real ram" is accessed direcly while + the other area is virtualized. It is not possible to execute code in + virtualized ram. +*/ + +OUTPUT_ARCH(sh3) +ENTRY(_start) + +MEMORY +{ + rom : o = 0x00300200, l = 512k + /* 0x0810000 is apparently mapped to 0x8801c0000. */ + ram : o = 0x08100000, l = 8k + realram : o = 0x8800d000, l = 12k +} + +SECTIONS +{ + /* + ROM sections : binary code and read-only data. + */ + + .text : { + /* Initialization code. */ + *(.pretext.entry) + *(.pretext) + + _bctors = . ; + *(.ctors) + _ectors = . ; + _bdtors = . ; + *(.dtors) + _edtors = . ; + + *(.text) + *(.text.*) + } > rom + + .rodata : { + *(.rodata.fxconv); + *(.rodata) + *(.rodata.*) + + _romdata = ALIGN(4) ; + } > rom + + + + /* + RAM sections : bss section and read/write data. + The BSS section is meant to be stripped from the ELF file (to + reduce the binary size) and initialized with zeros in the + initialization routine, therefore its location is undefined. + */ + + .bss : { + _bbss = . ; + *(.bss) + _ebss = . ; + } > ram + + .data : AT(_romdata) ALIGN(4) { + _bdata = . ; + *(.data) + *(.data.*) + _edata = . ; + } > ram + + .cc : AT(_romdata + SIZEOF(.data)) ALIGN(4) { + *(.eh_frame) + *(.jcr) + + _gint_data = _romdata + SIZEOF(.data) + SIZEOF(.cc) ; + } > ram + + + + /* + Real RAM : interrupt, exception and TLB miss handlers. + */ + + .gint : AT(_gint_data) ALIGN(4) { + /* The vbr needs to be 0x100-aligned because of an ld issue. */ + . = ALIGN(0x100) ; + _gint_vbr = . ; + _bgint = . ; + + /* Exception handler. */ + . = _gint_vbr + 0x100 ; + *(.gint.exc.entry) + *(.gint.exc) + + /* TLB miss handler. */ + . = _gint_vbr + 0x400 ; + *(.gint.tlb.entry) + *(.gint.tlb) + + /* Interrupt handler. */ + . = _gint_vbr + 0x600 ; + *(.gint.int.entry) + *(.gint.int) + + _egint = . ; + } > realram +} diff --git a/src/p7os/cake.exe/libgint/demo/icon.bmp b/src/p7os/cake.exe/libgint/demo/icon.bmp new file mode 100644 index 0000000..27f0e48 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/icon.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/bopti_thumbs.bmp b/src/p7os/cake.exe/libgint/demo/resources/bopti_thumbs.bmp new file mode 100644 index 0000000..923b77e Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/bopti_thumbs.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/clock_7305.bmp b/src/p7os/cake.exe/libgint/demo/resources/clock_7305.bmp new file mode 100644 index 0000000..83690f6 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/clock_7305.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/clock_7705.bmp b/src/p7os/cake.exe/libgint/demo/resources/clock_7705.bmp new file mode 100644 index 0000000..d711160 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/clock_7705.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/clock_chars.bmp b/src/p7os/cake.exe/libgint/demo/resources/clock_chars.bmp new file mode 100644 index 0000000..6edc348 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/clock_chars.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/font_modern.bmp b/src/p7os/cake.exe/libgint/demo/resources/font_modern.bmp new file mode 100644 index 0000000..0340f76 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/font_modern.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/isometric.bmp b/src/p7os/cake.exe/libgint/demo/resources/isometric.bmp new file mode 100644 index 0000000..5241b60 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/isometric.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/items.bmp b/src/p7os/cake.exe/libgint/demo/resources/items.bmp new file mode 100644 index 0000000..c57f934 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/items.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/opt_bitmap.bmp b/src/p7os/cake.exe/libgint/demo/resources/opt_bitmap.bmp new file mode 100644 index 0000000..c776021 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/opt_bitmap.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/opt_gray.bmp b/src/p7os/cake.exe/libgint/demo/resources/opt_gray.bmp new file mode 100644 index 0000000..87ba1c7 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/opt_gray.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/opt_menu.bmp b/src/p7os/cake.exe/libgint/demo/resources/opt_menu.bmp new file mode 100644 index 0000000..4d682e4 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/opt_menu.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/opt_rtc.bmp b/src/p7os/cake.exe/libgint/demo/resources/opt_rtc.bmp new file mode 100644 index 0000000..7fdd764 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/opt_rtc.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/opt_tales.bmp b/src/p7os/cake.exe/libgint/demo/resources/opt_tales.bmp new file mode 100644 index 0000000..8f34e47 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/opt_tales.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/opt_timer.bmp b/src/p7os/cake.exe/libgint/demo/resources/opt_timer.bmp new file mode 100644 index 0000000..1d7cb9c Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/opt_timer.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/rtc_segments.bmp b/src/p7os/cake.exe/libgint/demo/resources/rtc_segments.bmp new file mode 100644 index 0000000..958d83f Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/rtc_segments.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/screen.bmp b/src/p7os/cake.exe/libgint/demo/resources/screen.bmp new file mode 100644 index 0000000..050825a Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/screen.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/sprites.bmp b/src/p7os/cake.exe/libgint/demo/resources/sprites.bmp new file mode 100644 index 0000000..2cbe277 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/sprites.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/swords.bmp b/src/p7os/cake.exe/libgint/demo/resources/swords.bmp new file mode 100644 index 0000000..8aa6416 Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/swords.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/resources/zelda.bmp b/src/p7os/cake.exe/libgint/demo/resources/zelda.bmp new file mode 100644 index 0000000..03440dd Binary files /dev/null and b/src/p7os/cake.exe/libgint/demo/resources/zelda.bmp differ diff --git a/src/p7os/cake.exe/libgint/demo/test_bopti.c b/src/p7os/cake.exe/libgint/demo/test_bopti.c new file mode 100644 index 0000000..7942f39 --- /dev/null +++ b/src/p7os/cake.exe/libgint/demo/test_bopti.c @@ -0,0 +1,221 @@ +#include "gintdemo.h" +#include +#include +#include + +#include + +#include + +/* + test_bopti() + Displays and moves many kinds of bitmaps. Here are the images used: + + Name Size Color Alpha + --------------------------------------------------------- + items.bmp 266 * 124 Gray - + sprites.bmp 66 * 33 Gray - + swords.bmp 88 * 16 Gray Full + --------------------------------------------------------- + zelda.bmp 86 * 280 Mono - + isometric.bmp 37 * 27 Mono Full + Mono Greater + --------------------------------------------------------- +*/ + +static void getwh(Image *img, int *width, int *height) +{ + const unsigned char *data; + + if(!img) + { + *width = 0; + *height = 0; + return; + } + *width = img->width; + *height = img->height; + if(*width && *height) return; + + data = img->data; + *width = (data[0] << 8) | data[1]; + *height = (data[2] << 8) | data[3]; +} + +static void getxy(Image *img, int *x, int *y) +{ + int width, height; + + getwh(img, &width, &height); + *x = 64 - (width >> 1); + *y = 28 - (height >> 1); +} + +static Image *select(Image *current) +{ + extern Image res_bopti_thumbs; + extern Image + res_items, + res_sprites, + res_swords, + res_zelda, + res_isometric; + + struct { + Image *img; + const char *name; + const char *info; + } images[] = { + { &res_items, "Items", "Gray" }, + { &res_sprites, "Sprites", "Gray" }, + { &res_swords, "Swords", "Gray Alpha" }, + { &res_zelda, "Zelda", "Mono" }, + { &res_isometric, "Isometric", "Mono Alpha" }, + { NULL, NULL, NULL } + }; + + Image *thumbs = &res_bopti_thumbs; + int items = 0; + static int row = 0; + int leave = 1, i; + + while(images[items].img) items++; + + gray_start(); + + while(1) + { + gclear(); + locate(1, 1, "Select an image:"); + + for(i = 0; i < items && i < 7; i++) + { + locate(2, 2 + i + (i > row), images[i].name); + gimage_part(100, 8 + 8 * (i + (i > row)), thumbs, 0, + 8 * i, 7, 7); + if(i == row) + { + int width, height; + getwh(images[i].img, &width, &height); + print(2, 2 + i + 1, "%d\x04%d", width, height); + locate(10, 2 + i + 1, images[i].info); + } + } + + greverse_area(0, 8 * row + 8, 128, 8 * row + 23); + gupdate(); + + do + { + leave = 1; + + switch(getkey()) + { + case KEY_UP: + row = (row + items - 1) % items; + break; + case KEY_DOWN: + row = (row + 1) % items; + break; + case KEY_EXE: + return images[row].img; + case KEY_EXIT: + return current; + default: + leave = 0; + break; + } + } + while(!leave); + } + + gray_stop(); +} + +void test_bopti(void) +{ + extern Image res_opt_bitmap; + Image *img = NULL; + + int leave = 1; + int black_bg = 0; + int x = 0, y = 0; + + while(1) + { + if(img && (img->format & Channel_Light)) + { + gray_start(); + gclear(); + + if(black_bg) greverse_area(0, 0, 127, 63); + if(img) gimage(x, y, img); + + gclear_area(0, 55, 127, 63); + gimage(0, 56, &res_opt_bitmap); + gupdate(); + } + else if(img) + { + gray_stop(); + dclear(); + + if(black_bg) dreverse_area(0, 0, 127, 63); + if(img) dimage(x, y, img); + + dclear_area(0, 55, 127, 63); + dimage(0, 56, &res_opt_bitmap); + dupdate(); + } + else + { + gray_stop(); + + dclear(); + locate(3, 3, "No image selected"); + + dimage(0, 56, &res_opt_bitmap); + dupdate(); + } + + do + { + leave = 1; + + switch(getkey()) + { + case KEY_EXIT: + gray_stop(); + return; + + case KEY_F1: + img = select(img); + getxy(img, &x, &y); + break; + case KEY_F5: + black_bg = !black_bg; + break; + + case KEY_UP: + y--; + break; + case KEY_DOWN: + y++; + break; + case KEY_LEFT: + x--; + break; + case KEY_RIGHT: + x++; + break; + + default: + leave = 0; + } + } + while(!leave); + } + + gray_stop(); + return; +} diff --git a/src/p7os/cake.exe/libgint/demo/test_gray.c b/src/p7os/cake.exe/libgint/demo/test_gray.c new file mode 100644 index 0000000..b562f1f --- /dev/null +++ b/src/p7os/cake.exe/libgint/demo/test_gray.c @@ -0,0 +1,102 @@ +#include "gintdemo.h" +#include +#include +#include + +/* + test_gray() + Lets the user set the gray delays and see the results. +*/ + +static void draw(int delay1, int delay2, int selected) +{ + extern Image res_opt_gray; + unsigned int *vl = gray_lightVRAM(); + unsigned int *vd = gray_darkVRAM(); + + gclear(); + locate(1, 1, "Gray engine"); + + for(int i = 0; i < 36; i++) + { + int o = ((i + 12) << 2) + 2; + unsigned light = -((i % 24) < 12); + unsigned dark = -(i < 24); + vl[o] = light >> 8; + vl[o + 1] = light << 8; + vd[o] = dark >> 8; + vd[o + 1] = dark << 8; + } + + locate(3, 3, "light"); + print(4, 4, "%d", delay1); + + locate(3, 5, "dark"); + print(4, 6, "%d", delay2); + + locate(3, selected ? 6 : 4, "\x02"); + + gimage(0, 56, &res_opt_gray); + gupdate(); +} + +void test_gray(void) +{ + int delays[2]; // { light, dark } + int key, changed = 1; + int selected = 0; + + gray_getDelays(delays, delays + 1); + gray_start(); + + while(1) + { + if(changed) + { + gray_setDelays(delays[0], delays[1]); + draw(delays[0], delays[1], selected); + } + changed = 0; + + key = getkey_opt(Getkey_RepeatArrowKeys, 1); + if(key == KEY_EXIT) break; + + changed = 1; + + switch(key) + { + case KEY_F1: + selected = !selected; + break; + case KEY_F2: + delays[0] = 912; + delays[1] = 1343; + break; + case KEY_F3: + delays[0] = 993; + delays[1] = 1609; + break; + case KEY_F4: + delays[0] = 860; + delays[1] = 1298; + break; + case KEY_UP: + delays[selected] += 10; + break; + case KEY_DOWN: + if(delays[selected] >= 110) delays[selected] -= 10; + break; + case KEY_RIGHT: + delays[selected]++; + break; + case KEY_LEFT: + if(delays[selected] >= 101) delays[selected]--; + break; + default: + changed = 0; + break; + } + } + + gray_stop(); +} diff --git a/src/p7os/cake.exe/libgint/demo/test_keyboard.c b/src/p7os/cake.exe/libgint/demo/test_keyboard.c new file mode 100644 index 0000000..ab90268 --- /dev/null +++ b/src/p7os/cake.exe/libgint/demo/test_keyboard.c @@ -0,0 +1,82 @@ +#include "gintdemo.h" +#include +#include +#include + +/* + test_keyboard() + Displays a real-time multigetkey() and the keyboard state. +*/ + +static void draw(volatile unsigned char *state) +{ + int i, j, k, l; + int x, y; + + for(i = 0; i < 10; i++) for(j = 1; j < 8; j++) + { + // Eliminating keys that do not exist. + if(!i && j != 7) continue; + if(i && j == 7) continue; + if(i <= 4 && j == 6) continue; + if(i == 4 && j == 5) continue; + + x = 5 * j + 1; + y = 61 - 5 * i; + // Moving the [AC/ON] key. + if(!i) x = 5 * (5) + 1, y = 61 - 5 * (4); + + // Drawing a filled shape when the key is pressed. + if(state[i] & (128 >> j)) + { + for(k = -2; k <= 2; k++) for(l = -2; l <= 2; l++) + if(abs(k) + abs(l) <= 2) + dpixel(x + k, y + l, Color_Black); + } + // Drawing a square border otherwise. + else + { + for(k = -1; k <= 1; k++) for(l = -1; l <= 1; l++) + if(k || l) dpixel(x + k, y + l, Color_Black); + } + } +} + +void test_keyboard(void) +{ + const char *key_names[] = { + "F1", "F2", "F3", "F4", "F5", "F6", + "SHIFT", "OPTN", "VARS", "MENU", "Left", "Up", + "ALPHA", "x^2", "^", "EXIT", "Down", "Right", + "X,\x1d,T", "log", "ln", "sin", "cos", "tan", + "[frac]", "F\x0f\x09" "D", "(", ")", ",", "\x09", + "7", "8", "9", "DEL", "AC/ON", NULL, + "4", "5", "6", "\x04", "\x05", NULL, + "1", "2", "3", "+", "-", NULL, + "0", ".", "\x08", "(-)", "EXE", NULL + }; + + volatile unsigned char *state = keystate(); + int keys[4] = { 0 }; + int i; + + while(1) + { + dclear(); + locate(1, 1, "Keyboard driver"); + locate(8, 3, "Pressed keys:"); + draw(state); + + if(keys[0] == KEY_NONE) locate(9, 4, ":None"); + else for(i = 0; i < 4 && keys[i] != KEY_NONE; i++) + { + locate( 9, i + 4, ":"); + locate(10, i + 4, key_names[keyid(keys[i])]); + } + + dupdate(); + + multigetkey(keys, 4, 1); + if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break; + } +} diff --git a/src/p7os/cake.exe/libgint/demo/test_rtc.c b/src/p7os/cake.exe/libgint/demo/test_rtc.c new file mode 100644 index 0000000..2264f00 --- /dev/null +++ b/src/p7os/cake.exe/libgint/demo/test_rtc.c @@ -0,0 +1,262 @@ +#include "gintdemo.h" +#include +#include +#include + +#include +#include + +/* + test_rtc() + Just a clock. Of course using all this RTCTime conversion and this / 10 + is awfully un-optimized, but it's a test case so it's made to check the + values in the structure are correct. +*/ + +#include +#include + +static void draw(struct RTCTime time) +{ + extern Image res_rtc_segments; + + const char *days[7] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }, *months[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", + "Oct", "Nov", "Dec" + }; + int x[6] = { 20, 33, 52, 65, 84, 97 }; + int digits[6]; + int i; + + digits[0] = time.hours / 10; + digits[1] = time.hours % 10; + digits[2] = time.minutes / 10; + digits[3] = time.minutes % 10; + digits[4] = time.seconds / 10; + digits[5] = time.seconds % 10; + + // Drawing digits. + for(i = 0; i < 6; i++) dimage_part(x[i], 8, &res_rtc_segments, + 12 * digits[i], 0, 11, 19); + // Drawing ':' between pairs of digits. + for(i = 0; i < 16; i++) dpixel(47 + 32 * (i >= 8) + (i & 1), + 14 + 5 * !!(i & 4) + !!(i & 2), Color_Black); + + // This should print time.year + 1900 but for the sake of this demo we + // have tweaked the field so that it already contains time.year + 1900. + print(4, 6, "%s %s %02d %4d", days[time.week_day], + months[time.month], time.month_day, time.year); +} + +static void callback(void) +{ + extern Image res_opt_rtc; + struct RTCTime time = rtc_getTime(); + time.year += 1900; + + dclear(); + draw(time); + dimage_part(0, 56, &res_opt_rtc, 0, 0, 19, 8); + dupdate(); +} + +static void set_region(struct RTCTime *time, int region, int value) +{ + switch(region) + { + case 0: + time->hours = 10 * value + (time->hours % 10); + break; + case 1: + time->hours = time->hours - (time->hours % 10) + value; + break; + case 2: + time->minutes = 10 * value + (time->minutes % 10); + break; + case 3: + time->minutes = time->minutes - (time->minutes % 10) + value; + break; + case 4: + time->seconds = 10 * value + (time->seconds % 10); + break; + case 5: + time->seconds = time->seconds - (time->seconds % 10) + value; + break; + case 6: + time->week_day = value; + break; + case 7: + time->month = value; + break; + case 8: + time->month_day = 10 * value + (time->month_day % 10); + break; + case 9: + time->month_day = time->month_day - (time->month_day % 10) + + value; + break; + case 10: + time->year = 1000 * value + (time->year % 1000); + break; + case 11: + time->year = time->year - (time->year % 1000) + 100 * value + + (time->year % 100); + break; + case 12: + time->year = time->year - (time->year % 100) + 10 * value + + (time->year % 10); + break; + case 13: + time->year = time->year - (time->year % 10) + value; + break; + } +} + +static void set(void) +{ + extern Image res_opt_rtc; + Image *opt = &res_opt_rtc; + + struct { + int x, y; + int w, h; + } regions[] = { + { 19, 7, 13, 21 }, { 32, 7, 13, 21 }, { 51, 7, 13, 21 }, + { 64, 7, 13, 21 }, { 83, 7, 13, 21 }, { 96, 7, 13, 21 }, + { 18, 39, 19, 9 }, { 42, 39, 19, 9 }, { 66, 39, 7, 9 }, + { 72, 39, 7, 9 }, { 84, 39, 7, 9 }, { 90, 39, 7, 9 }, + { 96, 39, 7, 9 }, { 102, 39, 7, 9 }, + }; + struct RTCTime time = rtc_getTime(); + int region_count = 14; + int n = 0, slide = 0, key, leave; + + time.year += 1900; + + while(1) + { + dclear(); + draw(time); + dreverse_area(regions[n].x, regions[n].y, regions[n].x + + regions[n].w - 1, regions[n].y + regions[n].h - 1); + + if(n == 6) dimage_part(0, 56, opt, 0, 9 * (1 + slide), 128, 8); + if(n == 7) dimage_part(0, 56, opt, 0, 9 * (3 + slide), 128, 8); + else dimage_part(0, 56, opt, 22 + 22 * (n == region_count - 1), + 0, 19, 8); + + dupdate(); + + do + { + leave = 1; + key = getkey(); + if(key == KEY_EXIT) return; + + else if(key == KEY_F1 || key == KEY_EXE) + { + n++; + slide = 0; + if(n == region_count) + { + time.year -= 1900; + rtc_setTime(time); + return; + } + } + + else if(key == KEY_F6) + { + if(n == 6) slide = (slide + 1) % 2; + if(n == 7) slide = (slide + 1) % 3; + } + + else if((key & 0x0f) == 9) // Other F-keys + { + int k = 7 - (key >> 4); // Number of F-key + + if(n == 7) + { + int month = k + 4 * slide - 2; + set_region(&time, n, month); + n++; + slide = 0; + } + + else if(n == 6 && (slide != 1 || k != 5)) + { + int day = k + 4 * slide - 1; + set_region(&time, n, day); + n++; + slide = 0; + } + + else leave = 0; + } + + else if(isdigit(keychar(key))) // Numbers + { + int val = keychar(key) - '0'; + int ok = 1; + + if(n == 0) ok = (val <= 2); + if(n == 1) + { + int max = time.hours >= 20 ? 3 : 9; + ok = (val <= max); + } + if(n == 2 || n == 4) ok = (val <= 5); + if(n == 8) ok = (val <= 3); + if(n == 9) + { + int max = time.month_day >= 30 ? 1 : 9; + ok = (val <= max); + } + + if(ok) + { + set_region(&time, n, val); + n++; + if(n == region_count) + { + time.year -= 1900; + rtc_setTime(time); + return; + } + slide = 0; + } + else leave = 0; + } + + else leave = 0; + } while(!leave); + } + + while(getkey() != KEY_EXIT); +} + +void test_rtc(void) +{ + int key, cb_id; + + cb_id = rtc_cb_add(RTCFreq_1Hz, callback, 0); + callback(); + + while(1) + { + key = getkey(); + + if(key == KEY_EXIT) break; + if(key == KEY_F1) + { + rtc_cb_edit(cb_id, RTCFreq_None, NULL); + set(); + callback(); + rtc_cb_edit(cb_id, RTCFreq_1Hz, callback); + } + } + + rtc_cb_end(cb_id); +} diff --git a/src/p7os/cake.exe/libgint/demo/test_tales.c b/src/p7os/cake.exe/libgint/demo/test_tales.c new file mode 100644 index 0000000..644fc23 --- /dev/null +++ b/src/p7os/cake.exe/libgint/demo/test_tales.c @@ -0,0 +1,158 @@ +#include "gintdemo.h" +#include +#include +#include + +#include + +/* + test_tales() + Displays some text using different modes and clipping options. +*/ + +static Font *select(Font *current) +{ + extern Font res_font_modern; + struct { + Font *font; + const char *name; + } fonts[] = { + { NULL, "gint default" }, + { &res_font_modern, "Modern" }, + }; + int font_number = 2; + + static int row = 0; + int i, leave; + + while(1) + { + text_configure(NULL, Color_Black); + + dclear(); + locate(1, 1, "Select a font:"); + + for(i = 0; i < font_number && i < 6; i++) + { + if(fonts[i].font) + { + int height = fonts[i].font->line_height; + int y = (i + 2) * 8 - 8 + ((7 - height) >> 1); + + text_configure(fonts[i].font, Color_Black); + dtext(7, y, fonts[i].name); + } + else + { + text_configure(NULL, Color_Black); + locate(2, i + 2, fonts[i].name); + } + + } + + dreverse_area(0, 8 * row + 8, 128, 8 * row + 15); + dupdate(); + + do + { + leave = 1; + + switch(getkey()) + { + case KEY_UP: + row = (row + font_number - 1) % font_number; + break; + case KEY_DOWN: + row = (row + 1) % font_number; + break; + case KEY_EXE: + return fonts[row].font; + case KEY_EXIT: + return current; + default: + leave = 0; + break; + } + } + while(!leave); + } +} + +void test_tales(void) +{ + enum Color colors[] = { Color_Black, Color_Dark, Color_Light, + Color_White, Color_Invert }; + extern Image res_opt_tales; + Font *font = NULL; + + int black_bg = 0; + int color = 0; + int i, x, height; + int leave; + + gray_start(); + while(1) + { + gclear(); + if(black_bg) greverse_area(0, 0, 127, 54); + + if(font) + { + text_configure(font, colors[color]); + height = font->line_height + 1; + } + else + { + text_configure(NULL, colors[color]); + height = 8; + } + + for(i = 0; i < 6 && 2 + (i + 1) * height < 56; i++) + { + char str[17]; + for(int j = 0; j < 16; j++) str[j] = 32 + (i << 4) + j; + str[16] = 0; + + gtext(2, 2 + i * height, str); + } + + gimage(0, 56, &res_opt_tales); + + x = 45 + 8 * color; + gline(x, 57, x + 5, 57, Color_Black); + gline(x, 57, x, 62, Color_Black); + gline(x + 5, 57, x + 5, 62, Color_Black); + gline(x, 62, x + 5, 62, Color_Black); + + gupdate(); + + do + { + leave = 1; + + switch(getkey()) + { + case KEY_F1: + gray_stop(); + font = select(font); + gray_start(); + break; + case KEY_F2: + color = (color + 1) % 5; + break; + case KEY_F5: + black_bg = !black_bg; + break; + + case KEY_EXIT: + gray_stop(); + text_configure(NULL, Color_Black); + return; + default: + leave = 0; + break; + } + } + while (!leave); + } +} diff --git a/src/p7os/cake.exe/libgint/demo/test_timer.c b/src/p7os/cake.exe/libgint/demo/test_timer.c new file mode 100644 index 0000000..36ca64d --- /dev/null +++ b/src/p7os/cake.exe/libgint/demo/test_timer.c @@ -0,0 +1,272 @@ +#include "gintdemo.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static void draw(int new_tab); +static struct ClockConfig conf; + +//--- +// Timer-RTC comparison. +// The precision of the timer is measured by comparing it to the RTC. +//--- + +static volatile int elapsed_timer = -1; +static volatile int elapsed_rtc = -1; +static int cb_id = -1; + +static void timing_rtc(void) +{ + elapsed_rtc++; +} + +static void timing_timer(void) +{ + elapsed_timer++; +} + +static void timing_start(void) +{ + timer_start(TIMER_USER, clock_setting(16, Clock_Hz), TIMER_Po_4, + timing_timer, 0); + rtc_cb_edit(cb_id, RTCFreq_16Hz, timing_rtc); + + elapsed_timer = 0; + elapsed_rtc = 0; +} + + + +//--- +// Drawing. +//--- + +/* + small_text() + Renders small text using a minimalist bitmap-based font. +*/ +static void small_text(int x, int y, const char *text, int alignment) +{ + extern Image res_clock_chars; + Image *chars = &res_clock_chars; + const char *table = "0123456789kMHz*/"; + + if(alignment) x -= 2 * strlen(text) - 1, y -= 2; + int c; + + while(*text) + { + const char *ptr = strchr(table, *text++); + if(!ptr) continue; + c = ptr - table; + + dimage_part(x, y, chars, c << 2, 0, 3, 5); + x += 4; + } +} + +/* + getFreq() + Prints the given frequency in a string on the form: + 332kHz + There are 1, 2 or 3 characters for the value, and 2 or 3 + characters for the unit. The string is compacted. +*/ +void getFreq(char *str, int freq) +{ + if(freq < 1000) sprintf(str, "%dHz", freq); + else if(freq < 1000000) sprintf(str, "%dkHz", (freq + 500) / 1000); + else sprintf(str, "%dMHz", (freq + 500000) / 1000000); +} + +/* + dislay_freq() + Displays a frequency value a unit, in an simple form. +*/ +static void display_freq(int x, int y, int freq) +{ + int ratio, letter, dot, i; + char buffer[10]; + + if(freq <= 0) + { + dtext(x, y, "Unknown"); + return; + } + if(freq < 10000) + { + dprint(x, y, "%5d", freq); + small_text(x + 31, y + 2, "Hz", 0); + return; + } + + if(freq < 10000000) ratio = 1, letter = 'k'; + else ratio = 1000, letter = 'M'; + + dot = 1 + (freq >= 10000 * ratio) + (freq >= 100000 * ratio); + freq += (ratio * (1 + 9 * (dot >= 2) + 90 * (dot >= 3))) / 2; + snprintf(buffer, 6, "%d", freq); + + for(i = 4; i > dot; i--) buffer[i] = buffer[i - 1]; + buffer[dot] = '.'; + + dprint(x, y, buffer); + sprintf(buffer, "%cHz", letter); + small_text(x + 31, y + 2, buffer, 0); +} + +/* + draw() + Draws the test interface. +*/ +static void draw(int tab) +{ + extern Image res_opt_timer; + extern Image res_clock_7705; + extern Image res_clock_7305; + + char buffer[16]; + + dclear(); + dimage(0, 56, &res_opt_timer); + + if(!tab) + { + locate(1, 1, "Clock frequency"); + dtext(7, 20, "B\x1e"); + display_freq(24, 20, conf.Bphi_f); + dtext(7, 28, "I\x1e"); + display_freq(24, 28, conf.Iphi_f); + dtext(7, 36, "P\x1e"); + display_freq(24, 36, conf.Pphi_f); + + if(isSH3()) + { + dimage(64, 0, &res_clock_7705); + + getFreq(buffer, conf.CKIO_f); + small_text(84, 16, buffer, 1); + + sprintf(buffer, "*%d", conf.PLL1); + small_text(84, 34, buffer, 1); + + if(conf.Iphi_div1 == 1) + dline(85, 43, 99, 43, Color_Black); + else + { + sprintf(buffer, "/%d", conf.Iphi_div1); + small_text(89, 41, buffer, 0); + } + if(conf.Pphi_div1 == 1) + dline(85, 50, 99, 50, Color_Black); + else + { + sprintf(buffer, "/%d", conf.Pphi_div1); + small_text(89, 48, buffer, 0); + } + } + else + { + dimage(64, 0, &res_clock_7305); + + getFreq(buffer, conf.RTCCLK_f); + small_text(84, 14, buffer, 1); + + sprintf(buffer, "*%d", conf.FLL); + small_text(84, 25, buffer, 1); + + sprintf(buffer, "*%d", conf.PLL); + small_text(84, 36, buffer, 1); + + sprintf(buffer, "/%d", conf.Bphi_div1); + small_text(89, 43, buffer, 0); + sprintf(buffer, "/%d", conf.Iphi_div1); + small_text(89, 50, buffer, 0); + sprintf(buffer, "/%d", conf.Pphi_div1); + small_text(89, 57, buffer, 0); + } + } + else + { + int timer = elapsed_timer, rtc = elapsed_rtc; // just in case + + locate(1, 1, "Timer/RTC comparison"); + + locate(2, 3, "Timer"); + if(timer >= 0) print(12, 3, "%04x", timer); + else locate(12, 3, "..."); + + locate(2, 4, "RTC"); + if(rtc >= 0) print(12, 4, "%04x", rtc); + else locate(12, 4, "..."); + + // We define the accuracy of the timer as the ratio between the + // two counters. + locate(2, 5, "Accuracy"); + if(rtc > 0 && timer > 0) + { + int ratio; + if(timer <= rtc) ratio = (10000 * timer) / rtc; + else ratio = (10000 * rtc) / timer; + + print(12, 5, "%d.%02d %%", ratio / 100, ratio % 100); + } + else locate(12, 5, "..."); + } + + dupdate(); +} + + + +//--- +// Timer/clock test. +//--- + +/* + test_timer() + Clock timer and timer precision. +*/ +void test_timer(void) +{ + int tab = 0; + + clock_measure(); + clock_measure_end(); + + conf = clock_config(); + + elapsed_timer = -1; + elapsed_rtc = -1; + cb_id = rtc_cb_add(RTCFreq_16Hz, timing_start, 0); + + text_configure(NULL, Color_Black); + + while(1) + { + draw(tab); + + switch(getkey_opt(Getkey_NoOption, 1)) + { + case KEY_EXIT: + timer_stop(TIMER_USER); + rtc_cb_end(cb_id); + return; + + case KEY_F1: + tab = 0; + break; + case KEY_F2: + tab = 1; + break; + } + } +} diff --git a/src/p7os/cake.exe/libgint/doc/bopti.md b/src/p7os/cake.exe/libgint/doc/bopti.md new file mode 100644 index 0000000..b460253 --- /dev/null +++ b/src/p7os/cake.exe/libgint/doc/bopti.md @@ -0,0 +1,306 @@ + +# gint documentation: bitmap rendering # + + +*Warning: this is a draft. The current implementation of bopti is different* +*from this description, though similar.* + + + +## Basics + +The bitmap drawing module, *bopti*, is based on video-ram (vram) bitwise +operations. The images are made of layers that describe (more or less) which +pixels of the image an operation applies to. Rendering the image consists in +applying an operation function to the existing vram pixels. + +*bopti* makes an extensive use of longword operations and 4-alignment to take +advantage of the bit-based structure of the monochrome vram and enhance +performance. Among all possible optimizations, avoiding direct pixel access has +proven to be the most efficient. + + + +--- + + + +## Operations + +Operations are functions applied to update a vram longword in accordance with +an operation mask. Bits that are set in the mask indicate pixels which have to +be updated by the operation. Bits that are reset indicate pixels that must not +be changed. + +All the point is, the functions must not access the bit information in the mask +or the vram data individually. They must operate globally using longword +bitwise instructions, so that performance is maintained. + +Consider for instance a logical and operation (`(a, b) -> a & b`). +Operating on pixels would need to move some data, test the value of a bit in +the mask, edit the vram data, and eventually shift both the data and the mask, +for all of the 32 pixels. +One could not expect this from happening in less than 150 processor cycles +(in comparison, using generic-purpose `setPixel()`-like functions would be at +least 10 times as long). The smarter method operates directly on the longword +parameters, and performs `data = data & ~mask`, which is 2 processor cycles +long. + +The following operations are defined by *bopti*: + +- `Draw `: Draws black pixels. +- `Alpha `: Erases non-transparent pixels. +- `Change `: Changes the pixels' color. +- `Lighten `: Lightens gray pixels. +- `Lighten2`: Lightens gray pixels more. +- `Darken `: Darkens gray pixels. +- `Darken2 `: Darkens gray pixels more. + +To perform an operation, *bopti* uses the mask data, which is taken from a +layer, and calls the associated operation function. Every operation has its +default layer mask (except `change`), but this setting may be overridden. +*bopti* allows user programs to use any monochrome image as a mask for an +operation. For instance, a black rectangle may be drawn by any of the operation +functions, resulting in various results. + +An additional operation, `fill`, is defined by the library. It does all the job +necessary to render the full image, which often falls back to performing the +operations that correspond to the kind of image. + + + +--- + + + +## Operation on gray pixels + +*Detailed article: [Gray engine](gray-engine)* + +Gray pixels are made of four colors represented by pairs of bits. Arguments +`light` and `dark` of gray operation functions are longwords containing the +least significant and most significant of these bits, respectively. + + white = 0 [00] + lightgray = 1 [01] + darkgray = 2 [10] + black = 3 [11] + +The `Lighten` operation affects pixels as if decrementing their value (white +pixels are not changed), and `darken` does the opposite (black pixels are not +changed). +Operations `Lighten2` and `darken2` do the same two times. + +From this description, and considering two bits `light` and `dark`, it follows +that: + +```c +lighten2 (light, dark) = (0, light & dark) +lighten (light, dark) = (light & dark, light & ~dark) +darken (light, dark) = (light | dark, light | ~dark) +darken2 (light, dark) = (1, light | dark) +``` + +This does not take account of a possible operation mask. See section +[Operation functions](#operation-functions) for more flexible functions. + + + +--- + + + +## Partial transparency + +*bopti* allows monochrome images to have semi-transparent pixels. Consider for +example a white background. An opaque black pixel will render black, while a +1/3-transparent black pixel will render dark gray, and a 2/3-transparent black +pixel will render light gray. Which means that: + +* 1/3-transparent white pixels form the mask for `lighten2` +* 2/3-transparent white pixels form the mask for `lighten` +* 2/3-transparent black pixels form the mask for `darken` +* 1/3-transparent black pixels form the mask for `darken2` + +Partial transparency on gray pixels is not allowed. Apart from the complexity +of the generic partial transparency rendering operation, semi-transparent gray +pixels are not of any use. + + + +--- + + + +## Operation functions + +Operations on monochrome buffers are defined as functions of two parameters: +the vram data longword to update, `data`, and the operation mask, `x`. Every +of these functions must satisfy `f(data, 0) = data`. + +Operations on gray buffers take three arguments: `light` and `dark`, which are +longwords from the [gray buffers](gray-engine), and the operation mask `x`. +They update both longwords and return them. These functions must satisfy +`f(light, dark, 0) = (light, dark)`. + +The functions for each of the operations are the following: + +~~~c +# Draw function +draw(data, x) = data | x + +# Alpha function +alpha(data, x) = data & ~x + +# Change function +change(data, x) = data ^ x + +# Lighten function +lighten(light, dark, x) = (light & (dark | ~x), (light | ~x) & (x ^ dark)) + +# Lighten2 function +lighten2(light, dark, x) = (light & ~x, (light | ~x) & dark) + +# Darken function +darken(light, dark, x) = (light | (dark & x), (light & x) | (x ^ dark)) + +# Darken2 function +darken2(light, dark, x) = (light | x, (light & x) | dark) +~~~ + +One could easily check that these functions do their jobs when `x = 1` and +leave the data unchanged when `x = 0`. + + + +--- + + + +## Image format + +Images are made of *layers*, each of which describe the mask for an operation. +When an image is rendered, *bopti* draws some of those layers in the vram +using the operation functions. + +* Non-transparent monochrome images only have one layer, which describes the +mask for the `draw` operation. +* Transparent monochrome images have two layers. The first describes the mask +for the `draw` operation, while the other is the `alpha` operation mask (which +means that it indicates which pixels are not transparent). +* Non-transparent gray images also have two layers: one for each +[gray buffer](gray-engine). Both are for the `draw` operation. +* Transparent gray images have three layers. Two of them constitute the two-bit +color information for the `draw` operation, and the third is the `alpha` +operation mask. +* Semi-transparent monochrome images also have three layers. Two are used to +store the two-bit transparency level information (0 is opaque, 3 is fully +transparent), and the third indicates the color. + +Layers are encoded as a bit map. The image is split into a *grid*, which is +made of 32-pixel *columns*, and an *end*. + + 32 32 32 end + +------+------+------+---+ + | | | | | + | | | | | + | | | | | + +------+------+------+---+ + + Bitmap + +The first bytes of the layer data is the column data. Each column is encoded +as a 32-bit integer array from top to bottom. Columns are written from left to +right. The end is encoded as an 8-bit or 16-bit integer array depending on its +size, and written from top to bottom. Additionally, 0 to 3 NUL (0x00) bytes are +added to make the layer size a multiple of 4 (to allow 32-bit access to the +column data of the following layer). + +In case of big images (see the image structure below), the end is expanded to +a 32-pixel column to improve performance. + +The image itself is a structure of the following kind (in case of small +images): + +```c +struct Image +{ + unsigned char magic; + unsigned char format; + + unsigned char width; + unsigned char height; + + const uint32_t data[]; + +} __attribute__((aligned(4))); +``` + +For bigger images (`width` > 255 or `height` > 255), both `width` and `height` +are set to `0` and the actual size information is written on two shorts just +where the data resides: + +```c +struct BigImage +{ + unsigned char magic; + unsigned char format; + + unsigned char null_width; /* contains 0 */ + unsigned char null_height; /* contains 0 */ + + unsigned short width; + unsigned short height; + + const uint32_t data[]; + +} __attribute__((aligned(4))); +``` + +This does not create a memory loss because a two-byte gap was needed to make +the data 4-aligned. + +* The `magic` number, which is common to all the file formats of *gint*, +identifies the file type and version of the structure. *bopti* will not render +an image which is not encoded for its specific version. + +* The `format` attribute describes the layer distribution, as specified by the +following enum: + + ```c + enum ImageFormat + { + ImageFormat_Mono = 0x01, + ImageFormat_MonoAlpha = 0x09, + ImageFormat_Gray = 0x06, + ImageFormat_GrayAlpha = 0x0e, + ImageFormat_GreaterAlpha = 0x31, + + ImageFormat_ColorMask = 0x07, + ImageFormat_AlphaMask = 0x38, + }; + ``` + + `Alpha` refers to uniform transparency. The only format that supports + partial transparency is `GreaterAlpha`, and it is always encoded as + monochrome (because using gray pixels would lead to 9 different colors, + which is rather unoptimized). Gray images with partial transparency + will be refused by *fxconv*. + + +* The `width` and `height` attributes are exactly what you expect. + +* The `data` is simply made of all the layers put one after another. Layers are +put in the following order: + + [0] Monochrome `draw` layer + [1] Dark gray `draw` layer + [2] Light gray `draw` layer + [3] Uniform `alpha` layer + [4] First semi-`alpha` layer + [5] Second semi-`alpha` layer + + Not every format uses the six layers, of course. The layers used by + each format may be found by reading the position of the `1`'s in the + corresponding `enum ImageFormat` entry. Layers that are not needed are + skipped. diff --git a/src/p7os/cake.exe/libgint/include/7305.h b/src/p7os/cake.exe/libgint/include/7305.h new file mode 100644 index 0000000..a34420f --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/7305.h @@ -0,0 +1,673 @@ +#ifndef _7305_H +#define _7305_H 1 + +/* + Double-underscore prefixed structures (e.g. __st_rtc_counter) are used + internally but are not meant to be used in user programs. + + Underscore-prefixed names (e.g. _R64CNT) are used to avoid name + conflicts (e.g. STRUCTURE.RTC would expand to STRUCTURE.((T *)0x...)). +*/ + +#pragma pack(push, 1) +#define gap(n) unsigned: n << 3 + +//--- +// Interrupt controller, part 1. +//--- + +struct _st_intc +{ + union { + unsigned short WORD; + struct { + unsigned const NMIL :1; + unsigned MAI :1; + unsigned :4; + unsigned NMIB :1; + unsigned NMIE :1; + unsigned :2; + unsigned LVLMODE :1; + unsigned :5; + }; + } ICR0; + + char gap1[14]; + + union { + unsigned int LONG; + struct { + unsigned IRQ0 :4; + unsigned IRQ1 :4; + unsigned IRQ2 :4; + unsigned IRQ3 :4; + unsigned IRQ4 :4; + unsigned IRQ5 :4; + unsigned IRQ6 :4; + unsigned IRQ7 :4; + }; + } INTPRI00; + + char gap2[8]; + + union { + unsigned short WORD; + struct { + unsigned IRQ0S :2; + unsigned IRQ1S :2; + unsigned IRQ2S :2; + unsigned IRQ3S :2; + unsigned IRQ4S :2; + unsigned IRQ5S :2; + unsigned IRQ6S :2; + unsigned IRQ7S :2; + }; + } ICR1; + + char gap3[6]; + + union { + unsigned char BYTE; + struct { + unsigned IRQ0 :1; + unsigned IRQ1 :1; + unsigned IRQ2 :1; + unsigned IRQ3 :1; + unsigned IRQ4 :1; + unsigned IRQ5 :1; + unsigned IRQ6 :1; + unsigned IRQ7 :1; + }; + } INTREQ00; + + char gap4[31]; + + union { + unsigned char BYTE; + struct { + unsigned IRQ0 :1; + unsigned IRQ1 :1; + unsigned IRQ2 :1; + unsigned IRQ3 :1; + unsigned IRQ4 :1; + unsigned IRQ5 :1; + unsigned IRQ6 :1; + unsigned IRQ7 :1; + }; + } INTMSK00; + + char gap5[31]; + + union { + unsigned char BYTE; + struct { + unsigned _IRQ0 :1; + unsigned _IRQ1 :1; + unsigned _IRQ2 :1; + unsigned _IRQ3 :1; + unsigned _IRQ4 :1; + unsigned _IRQ5 :1; + unsigned _IRQ6 :1; + unsigned _IRQ7 :1; + }; + } INTMSKCLR00; + + char gap6[91]; + + union { + unsigned short WORD; + struct { + unsigned const NMIL :1; + unsigned :14; + unsigned NMIFL :1; + }; + } NMIFCR; + + char gap7[6029118]; + + union { + unsigned int LONG; + struct { + unsigned HEXA_A5 :8; + unsigned :16; + unsigned UIMASK :4; + unsigned :4; + }; + } USERIMSK; + +} __attribute__((packed)); + + + +//--- +// Interrupt controller, part 2. +//--- + +struct _st_intx +{ + union { + unsigned short WORD; + struct { + unsigned TMU0_0 :4; + unsigned TMU0_1 :4; + unsigned TMU0_2 :4; + unsigned IrDA :4; + }; + } IPRA; + gap(2); + + union { + unsigned short WORD; + struct { + unsigned JPU :4; + unsigned LCDC :4; + unsigned DMAC1A :4; + unsigned BEU2_1 :4; + }; + } IPRB; + gap(2); + + union { + unsigned short WORD; + struct { + unsigned TMU1_0 :4; + unsigned TMU1_1 :4; + unsigned TMU1_2 :4; + unsigned SPU :4; + }; + } IPRC; + gap(2); + + union { + unsigned short WORD; + struct { + unsigned :4; + unsigned MMCIF :4; + unsigned :4; + unsigned ATAPI :4; + }; + } IPRD; + gap(2); + + union { + unsigned short WORD; + struct { + unsigned DMAC0A :4; + unsigned VARIOUS :4; + unsigned SCIFA3 :4; + unsigned VPU5F :4; + }; + } IPRE; + gap(2); + + union { + unsigned short WORD; + struct { + unsigned _KEYSC :4; + unsigned DMAC0B :4; + unsigned USB01 :4; + unsigned CMT :4; + }; + } IPRF; + gap(2); + + union { + unsigned short WORD; + struct { + unsigned SCIF0 :4; + unsigned SCIF1 :4; + unsigned SCIF2 :4; + unsigned VEU3F0 :4; + }; + } IPRG; + gap(2); + + union { + unsigned short WORD; + struct { + unsigned MSIOF0 :4; + unsigned MSIOF1 :4; + unsigned I2C1 :4; + unsigned I2C0 :4; + }; + } IPRH; + gap(2); + + union { + unsigned short WORD; + struct { + unsigned SCIFA4 :4; + unsigned ICB :4; + unsigned TSIF :4; + unsigned _2DG_ICB :4; + }; + } IPRI; + gap(2); + + union { + unsigned short WORD; + struct { + unsigned CEU2_1 :4; + unsigned EtherMAC :4; + unsigned FSI :4; + unsigned SDHI1 :4; + }; + } IPRJ; + gap(2); + + union { + unsigned short WORD; + struct { + unsigned _RTC :4; + unsigned DMAC1B :4; + unsigned ICB :4; + unsigned SDHI0 :4; + }; + } IPRK; + gap(2); + + union { + unsigned short WORD; + struct { + unsigned SCIFA5 :4; + unsigned :4; + unsigned TPU :4; + unsigned _2DDMAC :4; + }; + } IPRL; + char gap1[82]; + + union + { + unsigned char BYTE; + struct { + unsigned :1; + unsigned TUNI2 :1; + unsigned TUNI1 :1; + unsigned TUNI0 :1; + unsigned SDHII3 :1; + unsigned SDHII2 :1; + unsigned SDHII1 :1; + unsigned SDHII0 :1; + }; + } IMR0; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned VOUI :1; + unsigned VEU1I :1; + unsigned BEU0I :1; + unsigned CEUOI :1; + unsigned DEI3 :1; + unsigned DEI2 :1; + unsigned DEI1 :1; + unsigned DEI0 :1; + }; + } IMR1; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :3; + unsigned VPUI :1; + unsigned ATAPI :1; + unsigned EtherMAC :1; + unsigned :1; + unsigned SCIFA0 :1; + }; + } IMR2; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned DEI3 :1; + unsigned DEI2 :1; + unsigned DEI1 :1; + unsigned DEI0 :1; + unsigned :3; + unsigned IRDAI :1; + }; + } IMR3; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :1; + unsigned TUNI2 :1; + unsigned TUNI1 :1; + unsigned TUNI0 :1; + unsigned JPUI :1; + unsigned :2; + unsigned LCDCI :1; + }; + } IMR4; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned KEYI :1; + unsigned DADERR :1; + unsigned DEI5 :1; + unsigned DEI4 :1; + unsigned VEU0I :1; + unsigned SCIF2 :1; + unsigned SCIF1 :1; + unsigned SCIF0 :1; + }; + } IMR5; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :2; + unsigned ICBI :1; + unsigned SCIFA4 :1; + unsigned CEU1I :1; + unsigned :1; + unsigned MSIOFI0 :1; + unsigned MSIOFI1 :1; + }; + } IMR6; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned DTE0I :1; + unsigned WAITOI :1; + unsigned TACK0I :1; + unsigned AL0I :1; + unsigned DTE1I :1; + unsigned WAIT1I :1; + unsigned TACK1I :1; + unsigned AL1I :1; + }; + } IMR7; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned SDHII3 :1; + unsigned SDHII2 :1; + unsigned SDHII1 :1; + unsigned SDHII0 :1; + unsigned :2; + unsigned SCFIA5 :1; + unsigned FSI :1; + }; + } IMR8; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :3; + unsigned CMTI :1; + unsigned :1; + unsigned USI1 :1; + unsigned USI0 :1; + unsigned :1; + }; + } IMR9; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :1; + unsigned DADERR :1; + unsigned DEI5 :1; + unsigned DEI4 :1; + unsigned :1; + unsigned ATI :1; + unsigned PRI :1; + unsigned CUI :1; + }; + } IMR10; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned BRK :1; + unsigned CEI :1; + unsigned INI :1; + unsigned TRI :1; + unsigned :1; + unsigned TPUI :1; + unsigned LMBI :1; + unsigned TSIFI :1; + }; + } IMR11; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :7; + unsigned _2DDMAC :1; + }; + } IMR12; + char gap2[15]; + + union + { + unsigned char BYTE; + struct { + unsigned :1; + unsigned TUNI2 :1; + unsigned TUNI1 :1; + unsigned TUNI0 :1; + unsigned SDHII3 :1; + unsigned SDHII2 :1; + unsigned SDHII1 :1; + unsigned SDHII0 :1; + }; + } _IMCR0; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned VOUI :1; + unsigned VEU1I :1; + unsigned BEU0I :1; + unsigned CEUOI :1; + unsigned DEI3 :1; + unsigned DEI2 :1; + unsigned DEI1 :1; + unsigned DEI0 :1; + }; + } _IMCR1; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :3; + unsigned VPUI :1; + unsigned ATAPI :1; + unsigned EtherMAC :1; + unsigned :1; + unsigned SCIFA0 :1; + }; + } _IMCR2; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned DEI3 :1; + unsigned DEI2 :1; + unsigned DEI1 :1; + unsigned DEI0 :1; + unsigned :3; + unsigned IRDAI :1; + }; + } _IMCR3; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :1; + unsigned TUNI2 :1; + unsigned TUNI1 :1; + unsigned TUNI0 :1; + unsigned JPUI :1; + unsigned :2; + unsigned LCDCI :1; + }; + } _IMCR4; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned KEYI :1; + unsigned DADERR :1; + unsigned DEI5 :1; + unsigned DEI4 :1; + unsigned VEU0I :1; + unsigned SCIF2 :1; + unsigned SCIF1 :1; + unsigned SCIF0 :1; + }; + } _IMCR5; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :2; + unsigned ICBI :1; + unsigned SCIFA4 :1; + unsigned CEU1I :1; + unsigned :1; + unsigned MSIOFI0 :1; + unsigned MSIOFI1 :1; + }; + } _IMCR6; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned DTE0I :1; + unsigned WAITOI :1; + unsigned TACK0I :1; + unsigned AL0I :1; + unsigned DTE1I :1; + unsigned WAIT1I :1; + unsigned TACK1I :1; + unsigned AL1I :1; + }; + } _IMCR7; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned SDHII3 :1; + unsigned SDHII2 :1; + unsigned SDHII1 :1; + unsigned SDHII0 :1; + unsigned :2; + unsigned SCFIA5 :1; + unsigned FSI :1; + }; + } _IMCR8; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :3; + unsigned CMTI :1; + unsigned :1; + unsigned USI1 :1; + unsigned USI0 :1; + unsigned :1; + }; + } _IMCR9; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :1; + unsigned DADERR :1; + unsigned DEI5 :1; + unsigned DEI4 :1; + unsigned :1; + unsigned ATI :1; + unsigned PRI :1; + unsigned CUI :1; + }; + } _IMCR10; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned BRK :1; + unsigned CEI :1; + unsigned INI :1; + unsigned TRI :1; + unsigned :1; + unsigned TPUI :1; + unsigned LMBI :1; + unsigned TSIFI :1; + }; + } _IMCR11; + gap(3); + + union + { + unsigned char BYTE; + struct { + unsigned :7; + unsigned _2DDMAC :1; + }; + } _IMCR12; + +} __attribute__((packed)); + + + +#define INTC (*(volatile struct _st_intc *)0xa4140000) +#define INTX (*(volatile struct _st_intx *)0xa4080000) + +#pragma pack(pop) +#endif // _7305_H diff --git a/src/p7os/cake.exe/libgint/include/7705.h b/src/p7os/cake.exe/libgint/include/7705.h new file mode 100644 index 0000000..3282d34 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/7705.h @@ -0,0 +1,1099 @@ +#ifndef _7705_H +#define _7705_H 1 + + +// Internal Control Registers definition : + +struct st_cpg { /* struct CPG */ + union { /* FRQCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short :3; /* */ + unsigned short CKOEN:1; /* CKOEN */ + unsigned short :2; /* */ + unsigned short STC :2; /* STC */ + unsigned short :2; /* */ + unsigned short IFC :2; /* IFC */ + unsigned short :2; /* */ + unsigned short _PFC :2; /* PFC */ + } BIT; /* */ + } FRQCR; /* */ +}; /* */ +struct st_wdt { /* struct WDT */ + union { /* WTCNT */ + unsigned char READ; /* Read Access*/ + unsigned short WRITE; /* Write Access*/ + } WTCNT; /* */ + union { /* WTCSR */ + union { /* Read Access*/ + unsigned char BYTE; /* Byte Access*/ + struct { /* Bit Access*/ + unsigned char TME :1; /* TME */ + unsigned char WTIT:1; /* WT/IT */ + unsigned char RSTS:1; /* RSTS */ + unsigned char WOVF:1; /* WOVF */ + unsigned char IOVF:1; /* IOVF */ + unsigned char CKS :3; /* CKS */ + } BIT; /* */ + } READ; /* */ + unsigned short WRITE; /* Write Access*/ + } WTCSR; /* */ +}; + +struct st_pa { /* struct PA */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char B7:1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_pb { /* struct PB */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char B7:1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_pc { /* struct PC */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char B7:1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_pd { /* struct PD */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char B7:1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_pe { /* struct PE */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char B7:1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_pf { /* struct PF */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char B7:1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_pg { /* struct PG */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char B7:1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_ph { /* struct PH */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_pj { /* struct PJ */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char B7:1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_pk { /* struct PK */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char B7:1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_pl { /* struct PL */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :4; /* Bit 7-4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_scp { /* struct SCP */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :2; /* Bit 7,6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_pm { /* struct PM */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char :1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ +struct st_pn { /* struct PN */ + union { /* */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char B7:1; /* Bit 7 */ + unsigned char B6:1; /* Bit 6 */ + unsigned char B5:1; /* Bit 5 */ + unsigned char B4:1; /* Bit 4 */ + unsigned char B3:1; /* Bit 3 */ + unsigned char B2:1; /* Bit 2 */ + unsigned char B1:1; /* Bit 1 */ + unsigned char B0:1; /* Bit 0 */ + } BIT; /* */ + } DR; /* */ +}; /* */ + +struct st_usb { /* struct USB */ + union { /* UCLKCR */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char USSCS:2; /* USSCS */ + unsigned char USBEN:1; /* USBEN */ + } BIT; /* */ + } UCLKCR; /* */ + char wk1[4063223]; /* */ + unsigned char EPDR0i; /* EPDR0i */ + char wk2[3]; /* */ + unsigned char EPDR0o; /* EPDR0o */ + char wk3[3]; /* */ + unsigned char EPDR0s; /* EPDR0s */ + char wk4[3]; /* */ + unsigned char EPDR1; /* EPDR1 */ + char wk5[3]; /* */ + unsigned char EPDR2; /* EPDR2 */ + char wk6[3]; /* */ + unsigned char EPDR3; /* EPDR3 */ + char wk7[3]; /* */ + union { /* IFR0 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char BRST :1; /* BRST */ + unsigned char EP1FULL :1; /* EP1FULL */ + unsigned char EP2TR :1; /* EP2TR */ + unsigned char EP2EMPTY:1; /* EP2EMPTY */ + unsigned char SETUPTS :1; /* SETUPTS */ + unsigned char EP0oTS :1; /* EP0oTS */ + unsigned char EP0iTR :1; /* EP0iTR */ + unsigned char EP0iTS :1; /* EP0iTS */ + } BIT; /* */ + } IFR0; /* */ + char wk8[3]; /* */ + union { /* IFR1 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :4; /* */ + unsigned char VBUSMN:1; /* VBUSMN */ + unsigned char EP3TS :1; /* EP3TS */ + unsigned char EP3TR :1; /* EP3TR */ + unsigned char VBUS :1; /* VBUS */ + } BIT; /* */ + } IFR1; /* */ + char wk9[3]; /* */ + union { /* TRG */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :1; /* */ + unsigned char EP3PKTE :1; /* EP3PKTE */ + unsigned char EP1RDFN :1; /* EP1RDFN */ + unsigned char EP2PKTE :1; /* EP2PKTE */ + unsigned char :1; /* */ + unsigned char EP0sRDFN:1; /* EP0sRDFN */ + unsigned char EP0oRDFN:1; /* EP0oRDFN */ + unsigned char EP0iPKTE:1; /* EP0iPKTE */ + } BIT; /* */ + } TRG; /* */ + char wk10[3]; /* */ + union { /* FCLR */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :1; /* */ + unsigned char EP3CLR :1; /* EP3CLR */ + unsigned char EP1CLR :1; /* EP1CLR */ + unsigned char EP2CLR :1; /* EP2CLR */ + unsigned char :2; /* */ + unsigned char EP0oCLR:1; /* EP0oCLR */ + unsigned char EP0iCLR:1; /* EP0iCLR */ + } BIT; /* */ + } FCLR; /* */ + char wk11[3]; /* */ + unsigned char EPSZ0o; /* EPSZ0o */ + char wk12[3]; /* */ + union { /* DASTS */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :2; /* */ + unsigned char EP3DE :1; /* EP3DE */ + unsigned char EP2DE :1; /* EP2DE */ + unsigned char :3; /* */ + unsigned char EP0iDE:1; /* EP0iDE */ + } BIT; /* */ + } DASTS; /* */ + char wk13[3]; /* */ + union { /* EPSTL */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :4; /* */ + unsigned char EP3STL:1; /* EP3STL */ + unsigned char EP2STL:1; /* EP2STL */ + unsigned char EP1STL:1; /* EP1STL */ + unsigned char EP0STL:1; /* EP0STL */ + } BIT; /* */ + } EPSTL; /* */ + char wk14[3]; /* */ + union { /* IER0 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char BRST :1; /* BRST */ + unsigned char EP1FULL :1; /* EP1FULL */ + unsigned char EP2TR :1; /* EP2TR */ + unsigned char EP2EMPTY:1; /* EP2EMPTY */ + unsigned char SETUPTS :1; /* SETUPTS */ + unsigned char EP0oTS :1; /* EP0oTS */ + unsigned char EP0iTR :1; /* EP0iTR */ + unsigned char EP0iTS :1; /* EP0iTS */ + } BIT; /* */ + } IER0; /* */ + char wk15[3]; /* */ + union { /* IER1 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :5; /* */ + unsigned char EP3TS:1; /* EP3TS */ + unsigned char EP3TR:1; /* EP3TR */ + unsigned char VBUS :1; /* VBUS */ + } BIT; /* */ + } IER1; /* */ + char wk16[3]; /* */ + unsigned char EPSZ1; /* EPSZ1 */ + char wk17[3]; /* */ + union { /* DMAR */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :6; /* */ + unsigned char EP2DMAE:1; /* EP2DMAE */ + unsigned char EP1DMAE:1; /* EP1DMAE */ + } BIT; /* */ + } DMAR; /* */ + char wk18[3]; /* */ + union { /* ISR0 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char BRST :1; /* BRST */ + unsigned char EP1FULL :1; /* EP1FULL */ + unsigned char EP2TR :1; /* EP2TR */ + unsigned char EP2EMPTY:1; /* EP2EMPTY */ + unsigned char SETUPTS :1; /* SETUPTS */ + unsigned char EP0oTS :1; /* EP0oTS */ + unsigned char EP0iTR :1; /* EP0iTR */ + unsigned char EP0iTS :1; /* EP0iTS */ + } BIT; /* */ + } ISR0; /* */ + char wk19[3]; /* */ + union { /* ISR1 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :5; /* */ + unsigned char EP3TS:1; /* EP3TS */ + unsigned char EP3TR:1; /* EP3TR */ + unsigned char VBUS :1; /* VBUS */ + } BIT; /* */ + } ISR1; /* */ + char wk20[23]; /* */ + union { /* XVERCR */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :6; /* */ + unsigned char XVEROFF:1; /* XVEROFF */ + } BIT; /* */ + } XVERCR; /* */ +}; +struct st_intc { /* struct INTC */ + union { /* ICR0 */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short NMIL:1; /* NMIL */ + unsigned short :6; /* */ + unsigned short NMIE:1; /* NMIE */ + } BIT; /* */ + } ICR0; /* */ + union { /* IPRA */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short _TMU0:4; /* TMU0 */ + unsigned short _TMU1:4; /* TMU1 */ + unsigned short _TMU2:4; /* TMU2 */ + unsigned short _RTC :4; /* RTC */ + } BIT; /* */ + } IPRA; /* */ + union { /* IPRB */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short _WDT:4; /* WDT */ + unsigned short _REF:4; /* REF */ + } BIT; /* */ + } IPRB; /* */ + char wk[234]; /* */ + unsigned int TRA; /* TRA */ + unsigned int EXPEVT; /* EXPEVT */ + unsigned int INTEVT; /* INTEVT */ +}; +struct st_intx { /* struct INTX */ + unsigned int INTEVT2; /* INTEVT2 */ + union { /* IRR0 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char PINT0R:1; /* PINT0R */ + unsigned char PINT1R:1; /* PINT1R */ + unsigned char IRQ5R :1; /* IRQ5R */ + unsigned char IRQ4R :1; /* IRQ4R */ + unsigned char IRQ3R :1; /* IRQ3R */ + unsigned char IRQ2R :1; /* IRQ2R */ + unsigned char IRQ1R :1; /* IRQ1R */ + unsigned char IRQ0R :1; /* IRQ0R */ + } BIT; /* */ + } IRR0; /* */ + char wk1; /* */ + union { /* IRR1 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char TXI0R:1; /* TXI0R */ + unsigned char :1; /* */ + unsigned char RXI0R:1; /* RXI0R */ + unsigned char ERI0R:1; /* ERI0R */ + unsigned char DEI3R:1; /* DEI3R */ + unsigned char DEI2R:1; /* DEI2R */ + unsigned char DEI1R:1; /* DEI1R */ + unsigned char DEI0R:1; /* DEI0R */ + } BIT; /* */ + } IRR1; /* */ + char wk2; /* */ + union { /* IRR2 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :3; /* */ + unsigned char ADIR :1; /* ADIR */ + unsigned char TXI2R:1; /* TXI2R */ + unsigned char :1; /* */ + unsigned char RXI2R:1; /* RXI2R */ + unsigned char ERI2R:1; /* ERI2R */ + } BIT; /* */ + } IRR2; /* */ + char wk3[7]; /* */ + union { /* ICR1 */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short MAI :1; /* MAI */ + unsigned short IRQLVL:1; /* IRQLVL */ + unsigned short BLMSK :1; /* BLMSK */ + unsigned short :1; /* */ + unsigned short IRQ5S :2; /* IRQ5S */ + unsigned short IRQ4S :2; /* IRQ4S */ + unsigned short IRQ3S :2; /* IRQ3S */ + unsigned short IRQ2S :2; /* IRQ2S */ + unsigned short IRQ1S :2; /* IRQ1S */ + unsigned short IRQ0S :2; /* IRQ0S */ + } BIT; /* */ + } ICR1; /* */ + union { /* ICR2 */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PINT15S:1; /* PINT15S */ + unsigned short PINT14S:1; /* PINT14S */ + unsigned short PINT13S:1; /* PINT13S */ + unsigned short PINT12S:1; /* PINT12S */ + unsigned short PINT11S:1; /* PINT11S */ + unsigned short PINT10S:1; /* PINT10S */ + unsigned short PINT9S :1; /* PINT9S */ + unsigned short PINT8S :1; /* PINT8S */ + unsigned short PINT7S :1; /* PINT7S */ + unsigned short PINT6S :1; /* PINT6S */ + unsigned short PINT5S :1; /* PINT5S */ + unsigned short PINT4S :1; /* PINT4S */ + unsigned short PINT3S :1; /* PINT3S */ + unsigned short PINT2S :1; /* PINT2S */ + unsigned short PINT1S :1; /* PINT1S */ + unsigned short PINT0S :1; /* PINT0S */ + } BIT; /* */ + } ICR2; /* */ + union { /* PINTER */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PINT15E:1; /* PINT15E */ + unsigned short PINT14E:1; /* PINT14E */ + unsigned short PINT13E:1; /* PINT13E */ + unsigned short PINT12E:1; /* PINT12E */ + unsigned short PINT11E:1; /* PINT11E */ + unsigned short PINT10E:1; /* PINT10E */ + unsigned short PINT9E :1; /* PINT9E */ + unsigned short PINT8E :1; /* PINT8E */ + unsigned short PINT7E :1; /* PINT7E */ + unsigned short PINT6E :1; /* PINT6E */ + unsigned short PINT5E :1; /* PINT5E */ + unsigned short PINT4E :1; /* PINT4E */ + unsigned short PINT3E :1; /* PINT3E */ + unsigned short PINT2E :1; /* PINT2E */ + unsigned short PINT1E :1; /* PINT1E */ + unsigned short PINT0E :1; /* PINT0E */ + } BIT; /* */ + } PINTER; /* */ + union { /* IPRC */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short _IRQ3:4; /* IRQ3 */ + unsigned short _IRQ2:4; /* IRQ2 */ + unsigned short _IRQ1:4; /* IRQ1 */ + unsigned short _IRQ0:4; /* IRQ0 */ + } BIT; /* */ + } IPRC; /* */ + union { /* IPRD */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short _PINT0_7 :4; /* PINT0-7 */ + unsigned short _PINT8_15:4; /* PINT8-15 */ + unsigned short _IRQ5 :4; /* IRQ5 */ + unsigned short _IRQ4 :4; /* IRQ4 */ + } BIT; /* */ + } IPRD; /* */ + union { /* IPRE */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short _DMAC :4; /* DMAC */ + unsigned short _SCIF0:4; /* SCIF0 */ + unsigned short _SCIF2:4; /* SCIF2 */ + unsigned short _ADC :4; /* ADC */ + } BIT; /* */ + } IPRE; /* */ + char wk4[524260]; /* */ + union { /* IPRF */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short :8; /* */ + unsigned short _USB:4; /* USB */ + } BIT; /* */ + } IPRF; /* */ + union { /* IPRG */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short _TPU0:4; /* TPU0 */ + unsigned short _TPU1:4; /* TPU1 */ + } BIT; /* */ + } IPRG; /* */ + union { /* IPRH */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short _TPU2:4; /* TPU2 */ + unsigned short _TPU3:4; /* TPU3 */ + } BIT; /* */ + } IPRH; /* */ +}; +struct st_scif { /* struct SCIF */ + union { /* SCSMR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short :5; /* */ + unsigned short SRC :3; /* SRC */ + unsigned short CA :1; /* CA */ + unsigned short CHR :1; /* CHR */ + unsigned short _PE :1; /* PE */ + unsigned short OE :1; /* O/E */ + unsigned short STOP:1; /* STOP */ + unsigned short :1; /* */ + unsigned short CKS :2; /* CKS */ + } BIT; /* */ + } SCSMR; /* */ + char wk1[2]; /* */ + unsigned char SCBRR; /* SCBRR */ + char wk2[3]; /* */ + union { /* SCSCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short :4; /* */ + unsigned short TSIE:1; /* TSIE */ + unsigned short ERIE:1; /* ERIE */ + unsigned short BRIE:1; /* BRIE */ + unsigned short DRIE:1; /* DRIE */ + unsigned short TIE :1; /* TIE */ + unsigned short RIE :1; /* RIE */ + unsigned short TE :1; /* TE */ + unsigned short RE :1; /* RE */ + unsigned short :2; /* */ + unsigned short CKE :2; /* CKE */ + } BIT; /* */ + } SCSCR; /* */ + char wk3[2]; /* */ + unsigned char SCTDSR; /* SCTDSR */ + char wk4[3]; /* */ + union { /* SCFER */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short :2; /* */ + unsigned short PER:6; /* PER */ + unsigned short :2; /* */ + unsigned short FER:6; /* FER */ + } BIT; /* */ + } SCFER; /* */ + char wk5[2]; /* */ + union { /* SCSSR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short :6; /* */ + unsigned short ORER:1; /* ORER */ + unsigned short TSF :1; /* TSF */ + unsigned short ER :1; /* ER */ + unsigned short TEND:1; /* TEND */ + unsigned short TDFE:1; /* TDFE */ + unsigned short BRK :1; /* BRK */ + unsigned short FER :1; /* FER */ + unsigned short PER :1; /* PER */ + unsigned short RDF :1; /* RDF */ + unsigned short DR :1; /* DR */ + } BIT; /* */ + } SCSSR; /* */ + char wk6[2]; /* */ + union { /* SCFCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short TSE :1; /* TSE */ + unsigned short TCRST:1; /* TCRST */ + unsigned short :3; /* */ + unsigned short RSTRG:3; /* RSTRG */ + unsigned short RTRG :2; /* RTRG */ + unsigned short TTRG :2; /* TTRG */ + unsigned short MCE :1; /* MCE */ + unsigned short TFRST:1; /* TFRST */ + unsigned short RFRST:1; /* RFRST */ + unsigned short LOOP :1; /* LOOP */ + } BIT; /* */ + } SCFCR; /* */ + char wk7[2]; /* */ + union { /* SCFDR */ + unsigned short WORD; /* Word Access */ + struct { /* Byte Access */ + unsigned short :1; /* */ + unsigned short T:7; /* T */ + unsigned short :1; /* */ + unsigned short R:7; /* R */ + } BIT; /* */ + } SCFDR; /* */ + char wk8[2]; /* */ + unsigned char SCFTDR; /* SCFTDR */ + char wk9[3]; /* */ + unsigned char SCFRDR; /* SCFRDR */ +}; /* */ +union un_stbcr3 { /* union STBCR3 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char _USB :1; /* USB */ + unsigned char :1; /* */ + unsigned char _CMT :1; /* CMT */ + unsigned char _TPU :1; /* TPU */ + unsigned char _ADC :1; /* ADC */ + unsigned char _IrDA :1; /* IrDA */ + unsigned char _SCIF2:1; /* SCIF2 */ + unsigned char _SCIF0:1; /* SCIF0 */ + } BIT; /* */ +}; /* */ +struct st_pfc { /* struct PFC */ + union { /* PACR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PA7MD:2; /* PA7MD */ + unsigned short PA6MD:2; /* PA6MD */ + unsigned short PA5MD:2; /* PA5MD */ + unsigned short PA4MD:2; /* PA4MD */ + unsigned short PA3MD:2; /* PA3MD */ + unsigned short PA2MD:2; /* PA2MD */ + unsigned short PA1MD:2; /* PA1MD */ + unsigned short PA0MD:2; /* PA0MD */ + } BIT; /* */ + } PACR; /* */ + union { /* PBCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PB7MD:2; /* PB7MD */ + unsigned short PB6MD:2; /* PB6MD */ + unsigned short PB5MD:2; /* PB5MD */ + unsigned short PB4MD:2; /* PB4MD */ + unsigned short PB3MD:2; /* PB3MD */ + unsigned short PB2MD:2; /* PB2MD */ + unsigned short PB1MD:2; /* PB1MD */ + unsigned short PB0MD:2; /* PB0MD */ + } BIT; /* */ + } PBCR; /* */ + union { /* PCCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PC7MD:2; /* PC7MD */ + unsigned short PC6MD:2; /* PC6MD */ + unsigned short PC5MD:2; /* PC5MD */ + unsigned short PC4MD:2; /* PC4MD */ + unsigned short PC3MD:2; /* PC3MD */ + unsigned short PC2MD:2; /* PC2MD */ + unsigned short PC1MD:2; /* PC1MD */ + unsigned short PC0MD:2; /* PC0MD */ + } BIT; /* */ + } PCCR; /* */ + union { /* PDCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PD7MD:2; /* PD7MD */ + unsigned short PD6MD:2; /* PD6MD */ + unsigned short PD5MD:2; /* PD5MD */ + unsigned short PD4MD:2; /* PD4MD */ + unsigned short PD3MD:2; /* PD3MD */ + unsigned short PD2MD:2; /* PD2MD */ + unsigned short PD1MD:2; /* PD1MD */ + unsigned short PD0MD:2; /* PD0MD */ + } BIT; /* */ + } PDCR; /* */ + union { /* PECR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PE7MD:2; /* PE7MD */ + unsigned short PE6MD:2; /* PE6MD */ + unsigned short PE5MD:2; /* PE5MD */ + unsigned short PE4MD:2; /* PE4MD */ + unsigned short PE3MD:2; /* PE3MD */ + unsigned short PE2MD:2; /* PE2MD */ + unsigned short PE1MD:2; /* PE1MD */ + unsigned short PE0MD:2; /* PE0MD */ + } BIT; /* */ + } PECR; /* */ + union { /* PFCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PF7MD:2; /* PF7MD */ + unsigned short PF6MD:2; /* PF6MD */ + unsigned short PF5MD:2; /* PF5MD */ + unsigned short PF4MD:2; /* PF4MD */ + unsigned short PF3MD:2; /* PF3MD */ + unsigned short PF2MD:2; /* PF2MD */ + unsigned short PF1MD:2; /* PF1MD */ + unsigned short PF0MD:2; /* PF0MD */ + } BIT; /* */ + } PFCR; /* */ + union { /* PGCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PG7MD:2; /* PG7MD */ + unsigned short PG6MD:2; /* PG6MD */ + unsigned short PG5MD:2; /* PG5MD */ + unsigned short PG4MD:2; /* PG4MD */ + unsigned short PG3MD:2; /* PG3MD */ + unsigned short PG2MD:2; /* PG2MD */ + unsigned short PG1MD:2; /* PG1MD */ + unsigned short PG0MD:2; /* PG0MD */ + } BIT; /* */ + } PGCR; /* */ + union { /* PHCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short :2; /* */ + unsigned short PH6MD:2; /* PH6MD */ + unsigned short PH5MD:2; /* PH5MD */ + unsigned short PH4MD:2; /* PH4MD */ + unsigned short PH3MD:2; /* PH3MD */ + unsigned short PH2MD:2; /* PH2MD */ + unsigned short PH1MD:2; /* PH1MD */ + unsigned short PH0MD:2; /* PH0MD */ + } BIT; /* */ + } PHCR; /* */ + union { /* PJCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PJ7MD:2; /* PJ7MD */ + unsigned short PJ6MD:2; /* PJ6MD */ + unsigned short PJ5MD:2; /* PJ5MD */ + unsigned short PJ4MD:2; /* PJ4MD */ + unsigned short PJ3MD:2; /* PJ3MD */ + unsigned short PJ2MD:2; /* PJ2MD */ + unsigned short PJ1MD:2; /* PJ1MD */ + unsigned short PJ0MD:2; /* PJ0MD */ + } BIT; /* */ + } PJCR; /* */ + union { /* PKCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PK7MD:2; /* PK7MD */ + unsigned short PK6MD:2; /* PK6MD */ + unsigned short PK5MD:2; /* PK5MD */ + unsigned short PK4MD:2; /* PK4MD */ + unsigned short PK3MD:2; /* PK3MD */ + unsigned short PK2MD:2; /* PK2MD */ + unsigned short PK1MD:2; /* PK1MD */ + unsigned short PK0MD:2; /* PK0MD */ + } BIT; /* */ + } PKCR; /* */ + union { /* PLCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short :8; /* */ + unsigned short PL3MD:2; /* PL3MD */ + unsigned short PL2MD:2; /* PL2MD */ + unsigned short PL1MD:2; /* PL1MD */ + unsigned short PL0MD:2; /* PL0MD */ + } BIT; /* */ + } PLCR; /* */ + union { /* SCPCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short :4; /* */ + unsigned short SCP5MD:2; /* SCP5MD */ + unsigned short SCP4MD:2; /* SCP4MD */ + unsigned short SCP3MD:2; /* SCP3MD */ + unsigned short SCP2MD:2; /* SCP2MD */ + unsigned short SCP1MD:2; /* SCP1MD */ + unsigned short SCP0MD:2; /* SCP0MD */ + } BIT; /* */ + } SCPCR; /* */ + union { /* PMCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short :2; /* */ + unsigned short PM6MD:2; /* PM6MD */ + unsigned short :2; /* */ + unsigned short PM4MD:2; /* PM4MD */ + unsigned short PM3MD:2; /* PM3MD */ + unsigned short PM2MD:2; /* PM2MD */ + unsigned short PM1MD:2; /* PM1MD */ + unsigned short PM0MD:2; /* PM0MD */ + } BIT; /* */ + } PMCR; /* */ + union { /* PNCR */ + unsigned short WORD; /* Word Access */ + struct { /* Bit Access */ + unsigned short PN7MD:2; /* PN7MD */ + unsigned short PN6MD:2; /* PN6MD */ + unsigned short PN5MD:2; /* PN5MD */ + unsigned short PN4MD:2; /* PN4MD */ + unsigned short PN3MD:2; /* PN3MD */ + unsigned short PN2MD:2; /* PN2MD */ + unsigned short PN1MD:2; /* PN1MD */ + unsigned short PN0MD:2; /* PN0MD */ + } BIT; /* */ + } PNCR; /* */ + char wk1[327724]; /* */ + union { /* PECR2 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :1; /* */ + unsigned char PE6MD:1; /* PE6MD */ + unsigned char PE5MD:1; /* PE5MD */ + unsigned char PE4MD:1; /* PE4MD */ + } BIT; /* */ + } PECR2; /* */ + char wk2; /* */ + union { /* PFCR2 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :4; /* */ + unsigned char PF3MD:1; /* PF3MD */ + unsigned char PF2MD:1; /* PF2MD */ + unsigned char PF1MD:1; /* PF1MD */ + unsigned char PF0MD:1; /* PF0MD */ + } BIT; /* */ + } PFCR2; /* */ + char wk3[15]; /* */ + union { /* PNCR2 */ + unsigned char BYTE; /* Byte Access */ + struct { /* Bit Access */ + unsigned char :1; /* */ + unsigned char PN6MD:1; /* PN6MD */ + unsigned char PN5MD:1; /* PN5MD */ + unsigned char PN4MD:1; /* PN4MD */ + unsigned char PN3MD:1; /* PN3MD */ + unsigned char PN2MD:1; /* PN2MD */ + unsigned char PN1MD:1; /* PN1MD */ + unsigned char PN0MD:1; /* PN0MD */ + } BIT; /* */ + } PNCR2; /* */ +}; /* */ + +struct st_mmu { + union { + unsigned int LONG; + struct { + unsigned int :23; + unsigned char SV :1; + unsigned char :2; + unsigned char RC :2; + unsigned char :1; + unsigned char TF :1; + unsigned char IX :1; + unsigned char AT :1; + } BIT; + } MMUCR; + + char wk1[12]; + union { + unsigned int LONG; + struct { + unsigned int VPN :22; + unsigned char :2; + unsigned char ASID :8; + } BIT; + } PTEH; + + union { + unsigned int LONG; + struct { + unsigned char :3; + unsigned int :19; + unsigned char :1; + unsigned char V :1; + unsigned char :1; + unsigned char PR :2; + unsigned char SZ :1; + unsigned char C :1; + unsigned char D :1; + unsigned char SH :1; + unsigned char :1; + } BIT; + } PTEL; + + unsigned int TTB; +}; + + +struct st_ubc { + unsigned int BDRB; + + unsigned int BDMRB; + + union { + unsigned int LONG; + struct { + unsigned short :10; + unsigned int BASMA :1; + unsigned int BASMB :1; + unsigned int :4; + unsigned int SCMFCA :1; + unsigned int SCMFCB :1; + unsigned int SCMFDA :1; + unsigned int SCMFDB :1; + unsigned int PCTE :1; + unsigned int PCBA :1; + unsigned int :2; + unsigned int DBEB :1; + unsigned int PCBB :1; + unsigned int :2; + unsigned int SEQ :1; + unsigned int :2; + unsigned int ETBE :1; + } BIT; + } BRCR; + + unsigned short BETR; + + char wk1[2]; + + unsigned int BARB; + + unsigned int BAMRB; + + union { + unsigned short WORD; + struct { + unsigned short :8; + unsigned short CDB :2; + unsigned short IDB :2; + unsigned short RWB :2; + unsigned short SZB :2; + } BIT; + } BBRB; + + char wk2[2]; + + union { + unsigned int LONG; + struct { + unsigned int SVF :1; + unsigned char :3; + unsigned int BSA :28; + } BIT; + } BRSR; + + unsigned int BARA; + + unsigned int BAMRA; + + union { + unsigned short WORD; + struct { + unsigned short :8; + unsigned short CDA :2; + unsigned short IDA :2; + unsigned short RWA :2; + unsigned short SZA :2; + } BIT; + } BBRA; + + char wk3[2]; + + union { + unsigned int LONG; + struct { + unsigned int DVF :1; + unsigned char :3; + unsigned int BDA :28; + } BIT; + } BRDR; + + char wk4[36]; + + unsigned char BASRA; + + char wk5[3]; + + unsigned char BASRB; +}; + + +union un_stbcr2 { + unsigned char BYTE; + struct { + unsigned char _UDI :1; + unsigned char _UBC :1; + unsigned char _DMAC :1; + unsigned char :1; + unsigned char _TLB :1; + unsigned char _CACHE :1; + unsigned char :2; + } BIT; +}; + + + +#define CPG (*(volatile struct st_cpg *)0xffffff80) +#define WDT (*(volatile struct st_wdt *)0xffffff84) +#define INTC (*(volatile struct st_intc *)0xfffffee0) +#define INTX (*(volatile struct st_intx *)0xa4000000) +#define PA (*(volatile struct st_pa *)0xa4000120) +#define PB (*(volatile struct st_pb *)0xa4000122) +#define PC (*(volatile struct st_pc *)0xa4000124) +#define PD (*(volatile struct st_pd *)0xa4000126) +#define PE (*(volatile struct st_pe *)0xa4000128) +#define PF (*(volatile struct st_pf *)0xa400012a) +#define PG (*(volatile struct st_pg *)0xa400012c) +#define PH (*(volatile struct st_ph *)0xa400012e) +#define PJ (*(volatile struct st_pj *)0xa4000130) +#define PK (*(volatile struct st_pk *)0xa4000132) +#define PL (*(volatile struct st_pl *)0xa4000134) +#define SCP (*(volatile struct st_scp *)0xa4000136) +#define PM (*(volatile struct st_pm *)0xa4000138) +#define PN (*(volatile struct st_pn *)0xa400013a) +#define USB (*(volatile struct st_usb *)0xa40a0008) +#define SCIF0 (*(volatile struct st_scif *)0xa4400000) +#define SCIF2 (*(volatile struct st_scif *)0xa4410000) +#define STBCR3 (*(volatile union un_stbcr3 *)0xa40a0000) +#define PFC (*(volatile struct st_pfc *)0xa4000100) +#define TEA (*(volatile unsigned int *)0xfffffffc) +#define MMU (*(volatile struct st_mmu *)0xffffffe0) +#define UBC (*(volatile struct st_ubc *)0xffffff90) +#define STBCR2 (*(volatile union un_stbcr2 *)0xffffff88) + +#endif // _7705_H diff --git a/src/p7os/cake.exe/libgint/include/alloca.h b/src/p7os/cake.exe/libgint/include/alloca.h new file mode 100644 index 0000000..37c88e7 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/alloca.h @@ -0,0 +1,23 @@ +//--- +// +// standard library module: alloca +// +// Allows dynamic memory allocation on the stack. Memory is automatically +// freed when the calling function exits. +// +//--- + +#ifndef _ALLOCA_H +#define _ALLOCA_H 1 + +#include + +/* + alloca() + Allocates a memory block on the stack. +*/ +void *alloca(size_t size); + +#define alloca(size) __builtin_alloca(size) + +#endif // _ALLOCA_H diff --git a/src/p7os/cake.exe/libgint/include/clock.h b/src/p7os/cake.exe/libgint/include/clock.h new file mode 100644 index 0000000..58e5c30 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/clock.h @@ -0,0 +1,128 @@ +//--- +// +// gint core module: clock +// +// Measures the frequency of the MPU clocks. This module assumes that the +// clock mode is 3 on SH7305 (as does FTune). +// +//--- + +#ifndef _CLOCK_H +#define _CLOCK_H + +//--- +// Some type declarations. +//--- + +enum Clock +{ + Clock_CKIO = 0, // SH7705 + Clock_RTCCLK = 1, // SH7305 + Clock_Bphi = 2, + Clock_Iphi = 3, + Clock_Pphi = 4, +}; + +enum ClockUnit +{ + Clock_us = 0, + Clock_ms = 1, + Clock_s = 2, + + Clock_Hz = 10, + Clock_kHz = 11, + Clock_MHz = 12, +}; + +struct ClockConfig +{ + union + { + int PLL1; // SH7705 + int FLL; // SH7305 + }; + union + { + int PLL2; // SH7705 + int PLL; // SH7305 + }; + + int Bphi_div1; + int Iphi_div1; + int Pphi_div1; + + union + { + int CKIO_f; // SH7705 + int RTCCLK_f; // SH7305 + }; + + int Bphi_f; + int Iphi_f; + int Pphi_f; +}; + +//--- +// Public API. +//--- + +/* + clock_frequency() + Returns the approximate frequency, in Hz, of the given clock. The + measurements need to have been done. Returns a negative number on + error. +*/ +int clock_frequency(enum Clock clock); + +/* + clock_setting() + Returns the P_phi / 4 timer setting that will last for the given time. + Several units can be used. Be aware that the result is approximate, and + very high frequencies or very short delays will yield important errors. +*/ +int clock_setting(int duration, enum ClockUnit unit); + +/* + clock_config() + Returns a copy of the clock configuration. +*/ +struct ClockConfig clock_config(void); + +/* + sleep() + Sleeps until an interrupt is accepted. +*/ +void sleep(void); + +/* + sleep_us() + Sleeps for the given number of us using the user timer. The result will + always be slightly less than required. +*/ +void sleep_us(int us_delay); + + + +//--- +// Internal API. +// Referenced for documentation purposes only. Do not use. +//--- + +/* + clock_measure() + Begins the frequency measurements. The measurements will end + automatically. While doing measurements, do not use the RTC interrupt + or the user timer. + Call clock_measure_end() to wait until the measurements are finished. + It is possible to execute code during the measurements, so that less + time is spent. +*/ +void clock_measure(void); + +/* + clock_measure_end() + Waits until the measurements are finished. This may be immediate. +*/ +void clock_measure_end(void); + +#endif // _CLOCK_H diff --git a/src/p7os/cake.exe/libgint/include/ctype.h b/src/p7os/cake.exe/libgint/include/ctype.h new file mode 100644 index 0000000..8c7ee2d --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/ctype.h @@ -0,0 +1,35 @@ +//--- +// +// standard library module: ctype +// +// Some character manipulation. +// +//--- + +#ifndef _CTYPE_H +#define _CTYPE_H 1 + +// Character definition macros. +#define isalnum(c) (isdigit(c) || isalpha(c)) +#define isalpha(c) (islower(c) || isupper(c)) + +#define iscntrl(c) ((c) <= 0x1f || (c) == 0x7f) +#define isdigit(c) ((c) >= '0' && (c) <= '9') +#define isgraph(c) ((c) > ' ' && (c) < 0x7f) +#define islower(c) ((c) >= 'a' && (c) <= 'z') +#define isprint(c) ((c) >= ' ' && (c) < 0x7f) +#define ispunct(c) (((c) >= '!' && (c) <= '/') || \ + ((c) >= ':' && (c) <= '@') || \ + ((c) >= '[' && (c) <= '`') || \ + ((c) >= '{' && (c) <= '~')) +#define isspace(c) (((c) >= '\t' && (c) <= '\r') || (c) == ' ') +#define isupper(c) ((c) >= 'A' && (c) <= 'Z') +#define isxdigit(c) (((c) >= '0' && (c) <= '9') || \ + ((c) >= 'A' && (c) <= 'F') || \ + ((c) >= 'a' && (c) <= 'f')) + +// Character manipulation macros. +#define tolower(c) (isupper(c) ? (c) | 32 : (c)) +#define toupper(c) (islower(c) ? (c) & ~32 : (c)) + +#endif // _CTYPE_H diff --git a/src/p7os/cake.exe/libgint/include/display.h b/src/p7os/cake.exe/libgint/include/display.h new file mode 100644 index 0000000..a7167a4 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/display.h @@ -0,0 +1,161 @@ +//--- +// +// gint drawing module: display +// +// Handles vram manipulation and drawing for plain monochrome display. +// +//--- + +#ifndef _DISPLAY_H +#define _DISPLAY_H 1 + + +//--- +// Heading declarations. +//--- + +enum Color +{ + Color_White = 0, + Color_Light = 1, + Color_Dark = 2, + Color_Black = 3, + Color_None = 4, + Color_Invert = 5, +}; + +// This header needs enum Color to be defined. +#include + +/* + struct Image + This structure holds information about a bitmap encoded with fxconv. + Data is accessed using longword operations, which *requires* many + sizes to be multiples of 4 (structure alignment, data alignment, layer + size, ...). +*/ +struct Image +{ + unsigned char magic; + unsigned char format; + + unsigned char width; + unsigned char height; + + const unsigned char __attribute__((aligned(4))) data[]; + +} __attribute__((aligned(4))); +// Useful shorthand for user code. +typedef struct Image Image; + + + +// A few other constants. +#define DISPLAY_WIDTH 128 +#define DISPLAY_HEIGHT 64 + + + +//--- +// Generic functions. +//--- + +/* + display_getLocalVRAM() + Returns the local video ram address. This function always return the + same address. + The buffer returned by this function should not be used directly when + running the gray engine. +*/ +void *display_getLocalVRAM(void); + +/* + display_getCurrentVRAM() + Returns the current video ram. This function usually returns the + parameter of the last call to display_useVRAM(), unless the gray engine + is running (in which case the result is undefined). Returns the local + vram address by default. +*/ +void *display_getCurrentVRAM(void); + +/* + display_useVRAM() + Changes the current video ram address. The argument MUST be a 4- + aligned 1024-byte buffer; otherwise any drawing operation will crash + the program. + This function will most likely have no effect when running the gray + engine. +*/ +void display_useVRAM(void *vram); + + + +//--- +// Global drawing functions. +//--- + +/* + dupdate() + Displays the vram on the physical screen. Does nothing when the gray + engine is running. +*/ +void dupdate(void); + +/* + dclear() + Clears the whole video ram. +*/ +void dclear(void); + +/* + dclear_area() + Clears an area of the video ram. Both (x1, y1) and (x2, y2) are + cleared. +*/ +void dclear_area(int x1, int y1, int x2, int y2); + +/* + dreverse_area() + Reverses an area of the vram. (x1, y1) and (x2, y2) are reversed as + well. +*/ +void dreverse_area(int x1, int y1, int x2, int y2); + + + +//--- +// Local drawing functions. +//--- + +/* + dpixel() + Puts a pixel in the vram. +*/ +void dpixel(int x, int y, enum Color color); + +/* + dline() + Draws a line in the vram. Automatically optimizes horizontal and + vertical lines. + + Uses an algorithm written by PierrotLL for MonochromeLib. +*/ +void dline(int x1, int y1, int x2, int y2, enum Color color); + +/* + dimage() + Displays a monochrome image in the vram. Does a real lot of + optimization. +*/ +void dimage(int x, int y, struct Image *image); + +/* + dimage_part() + Draws a portion of an image, defined by its bounding rectangle. + Point (left, top) is included, but (left + width, top + height) is + excluded. +*/ +void dimage_part(int x, int y, struct Image *img, int left, int top, + int width, int height); + +#endif // _DISPLAY_H diff --git a/src/p7os/cake.exe/libgint/include/events.h b/src/p7os/cake.exe/libgint/include/events.h new file mode 100644 index 0000000..01e5277 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/events.h @@ -0,0 +1,84 @@ +//--- +// +// gint core module: events +// +// Finally some user-friendly API. +// +//--- + +#ifndef _EVENTS_H +#define _EVENTS_H + +//--- +// Type definitions. +//--- + +/* + enum EventType + Something user programs will surely use most often. +*/ +enum EventType +{ + EventType_None = 0, + ET_None = EventType_None, + + EventType_User = 1, + ET_User = EventType_User, + + EventType_KeyPressed = 2, + ET_KeyPress = EventType_KeyPressed, + + EventType_KeyReleased = 3, + ET_KeyRel = EventType_KeyReleased, +}; + +/* + struct Event + Wake up, something's going on. The union member that holds information + about the event is implicitly defined by the type attribute. +*/ +struct Event +{ + enum EventType type; + + union + { + // For ET_User. + void *data; + // For ET_KeyPress and ET_KeyRel. + int key; + }; +}; + + + +//--- +// Event management. +//--- + +/* + event_push() + Queues a user-defined event, allowing it to be retrieved by getevent() + or pollevent() later. Most often you will not need to use this, as + system events are automatically queued. Pushing ET_None events is not + allowed. + Returns non-zero on error. +*/ +int event_push(struct Event event); + +/* + getevent() + Returns the next event. If no one is available, waits for something to + happen. This function uses low-level sleep and should be preferred to + active waiting using loops. +*/ +struct Event getevent(void); + +/* + pollevent() + Returns the next event. If no one is available, returns an event whose + type is ET_None. This function always returns immediately. +*/ +struct Event pollevent(void); + +#endif // _EVENTS_H diff --git a/src/p7os/cake.exe/libgint/include/gint.h b/src/p7os/cake.exe/libgint/include/gint.h new file mode 100644 index 0000000..c49cb5f --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/gint.h @@ -0,0 +1,192 @@ +//--- +// +// gint core module: interrupt handler +// +// Central point of the library. Controls the interrupt handler and +// defines a few functions to configure callbacks for some interrupts. +// +//--- + +#ifndef _GINT_H +#define _GINT_H 1 + +#define GINT_VERSION 0x01000000 +#define GINT_VERSION_STR "01.00" + +//--- +// Interrupt handler control. +//--- + +/* + gint_getVBR() + Returns the current vbr address. +*/ +unsigned int gint_getVBR(void); + +/* + gint_systemVBR() + Returns the vbr address used by the system (saved when execution + starts). +*/ +unsigned int gint_systemVBR(void); + +/* + gint_setDefaultHandler() + In case gint receives an interrupt it doesn't recognize, it can fall + back to a user-provided interrupt handler. Set it to NULL to disable + this feature. + Be aware that the event code passed to the default handler will either + be INTEVT2 (SH7705) or INTEVT (SH7305), but its value for each + interrupt source is completely platform-dependent. Remember to handle + both platforms for increased portability, if possible. +*/ +void gint_setDefaultHandler(void (*default_handler)(int event_code)); + + + +//--- +// Register access. +//--- + +/* + enum Register + Represents common registers. Used as identifiers to retrieve their + values using gint_register(). +*/ +enum Register +{ + Register_EXPEVT, + Register_MMUCR, + Register_TEA, +}; + +/* + gint_register() + Returns the address of a common register. All common registers exist + on both platforms but they may hold different values for the same + information (f.i. EXPEVT may not return the same value for a given + exception on both 7705 and 7305). +*/ +volatile void *gint_reg(enum Register reg); + +/* + gint_strerror() + Returns a string that describe the error set in EXPEVT in case of + general exception of TLB miss exception. This string is platform- + independent. + Some exception codes represent different errors when invoked inside the + general exception handler and the TLB error handler. Parameter 'is_tlb' + should be set to zero for general exception meanings, and anything non- + zero for TLB error meanings. +*/ +const char *gint_strerror(int is_tlb); + + + +//--- +// Internal API. +// Referenced here for documentation purposes only. +// Do NOT call these functions, you'll most probably screw up the whole +// interrupt handling system. +//--- + +/* + gint_setVBR() + Sets the vbr address and calls the configuration function while + interrupts are disabled. +*/ +void gint_setVBR(unsigned int new_vbr_address, void (*setup)(void)); + +/* + gint_callDefaultHandler() + Calls the user-provided default interrupt handler. +*/ +void gint_callDefaultHandler(int event_code); + +/* + gint_init() + Initializes gint. Loads the interrupt handler into the memory and sets + the new vbr address. +*/ +void gint_init(void); + +/* + gint_quit() + Stops gint. Restores the system's configuration and vbr address. +*/ +void gint_quit(void); + +/* + gint_setup() + Configures interrupt priorities and some parameters to allow gint to + take control of the interrupt flow. +*/ +void gint_setup_7705(void); +void gint_setup_7305(void); + +/* + gint_stop() + Un-configures the interrupt flow to give back the interrupt control to + the system. +*/ +void gint_stop_7705(void); +void gint_stop_7305(void); + +/* + gint_reg() + gint_strerror() + See "Register access" section. +*/ +volatile void *gint_reg_7705(enum Register reg); +volatile void *gint_reg_7305(enum Register reg); +const char *gint_strerror_7705(int is_tlb); +const char *gint_strerror_7305(void); + + +//--- +// Exception handling. +//--- + +/* + gint_exc() + Handles exceptions. +*/ +void gint_exc(void) __attribute__((section(".gint.exc.entry"), + interrupt_handler)); +void gint_exc_7705(void) __attribute__((section(".gint.exc"))); +void gint_exc_7305(void) __attribute__((section(".gint.exc"))); + +/* + gint_tlb() + Handles TLB misses. +*/ +void gint_tlb(void) __attribute__((section(".gint.tlb.entry"), + interrupt_handler)); +void gint_tlb_7705(void) __attribute__((section(".gint.tlb"))); +void gint_tlb_7305(void) __attribute__((section(".gint.tlb"))); + +/* + gint_int() + Handles interrupts. +*/ +void gint_int(void) __attribute__((section(".gint.int.entry"), + interrupt_handler)); +void gint_int_7705(void) __attribute__((section(".gint.int"))); +void gint_int_7305(void) __attribute__((section(".gint.int"))); + + + +//--- +// Internal platform-independent definitions. +//--- + +#define GINT_INTP_WDT 4 +#define GINT_INTP_RTC 12 + +#define GINT_INTP_GRAY 15 +#define GINT_INTP_KEY 8 +#define GINT_INTP_TIMER 10 + + + +#endif // _GINT_H diff --git a/src/p7os/cake.exe/libgint/include/gray.h b/src/p7os/cake.exe/libgint/include/gray.h new file mode 100644 index 0000000..e18a20a --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/gray.h @@ -0,0 +1,160 @@ +//--- +// +// gint core/drawing module: gray +// +// Runs the gray engine and handles drawing for the dual-buffer system. +// +//--- + +#ifndef _GRAY_H +#define _GRAY_H 1 + +#include + +//--- +// Engine control. +//--- + +/* + gray_runs() + Returns 1 if the gray engine is running, 0 otherwise. +*/ +int gray_runs(void); + +/* + gray_start() + Starts the gray engine. The control of the screen is transferred to the + gray engine. +*/ +void gray_start(void); + +/* + gray_stop() + Stops the gray engine. The monochrome display system takes control of + the video ram. +*/ +void gray_stop(void); + +/* + gray_lightVRAM() + Returns the module's light gray vram address. +*/ +void *gray_lightVRAM(void); + +/* + gray_darkVRAM() + Returns the module's dark gray vram address. +*/ +void *gray_darkVRAM(void); + +/* + gray_getDelays() + Returns the gray engine delays. Pointers are not set if NULL. +*/ +void gray_getDelays(int *light, int *dark); + +/* + gray_setDelays() + Changes the gray engine delays. Usually you don't need to call this, + because the engine has its default values. + Finding values that give proper grays is quite the hard part of the + gray engine. Usual values are about 1000, with light being between 75 + and 90% of dark. + + Typical values: + + values stability stripes colors + --------------------------------------------------------- + 860, 1298 excellent worst static good + 912, 1343 bad none very good (default) + 993, 1609 medium light fast good + 1325, 1607 bad light fast excellent + --------------------------------------------------------- +*/ +void gray_setDelays(int light, int dark); + + + +//--- +// Global drawing functions. +//--- + +/* + gupdate() + Swaps the vram buffer sets. +*/ +void gupdate(void); + +/* + gclear() + Clears the video ram. +*/ +void gclear(void); + +/* + gclear_area() + Clears an area of the video ram. End points (x1, y1) and (x2, y2) are + included. +*/ +void gclear_area(int x1, int y1, int x2, int y2); + +/* + greverse_area() + Reverses an area of the vram. End points (x1, y1) and (x2, y2) are + included. +*/ +void greverse_area(int x1, int y1, int x2, int y2); + + + +//--- +// Local drawing functions. +//--- + +/* + gpixel() + Puts a pixel in the vram. +*/ +void gpixel(int x, int y, enum Color color); + +/* + gline() + Draws a line in the vram. Automatically optimizes special cases. +*/ +void gline(int x1, int y1, int x2, int y2, enum Color color); + +/* + gimage() + Displays a gray image in the vram. +*/ +void gimage(int x, int y, struct Image *image); + +/* + gimage_part() + Draws a portion of a gray image, defined by its bounding rectangle. + Point (left, top) is included, but (left + width, top + height) is + excluded. +*/ +void gimage_part(int x, int y, struct Image *image, int left, int top, + int width, int height); + + + +//--- +// Internal API. +// Referenced here for documentation purposes only. Do not call. +//-- + +/* + gray_interrupt() + Answers a timer interrupt. Swaps the two buffers. +*/ +void gray_interrupt(void) __attribute__((section(".gint.int"))); + +/* + gray_init() + Initializes the gray engine. +*/ +void gray_init(void) __attribute__((constructor)); + +#endif // _GRAY_H diff --git a/src/p7os/cake.exe/libgint/include/internals/bopti.h b/src/p7os/cake.exe/libgint/include/internals/bopti.h new file mode 100644 index 0000000..7e0009c --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/internals/bopti.h @@ -0,0 +1,160 @@ +//--- +// +// gint drawing module: bopti +// +// bopti does every job related to display images. There is only one +// public function, but there are lots of internal optimizations. +// +// Some bit-manipulation expressions may look written out of nowhere. The +// idea is always the same: get a part of the image in an 'operator', +// which is a 32-bit variable, shift this operator so that its bits +// correspond to the desired position for the bitmap on the screen, and +// edit the video-ram long entry which correspond to this position using +// a 'mask' that indicates which bits of the operator contain information. +// +//--- + +#ifndef _INTERNALS_BOPTI_H +#define _INTERNALS_BOPTI_H 1 + +#include +#include + +/* + enum Channel + Determines the kind of information written into a layer. Every image is + made of one or more channels. +*/ +enum Channel +{ + Channel_FullAlpha = 0x01, + Channel_LightAlpha = 0x02, + Channel_DarkAlpha = 0x04, + + Channel_Mono = 0x08, + Channel_Light = 0x10, + Channel_Dark = 0x20, +}; + +/* + enum Format + Describes the various combination of channels allowed by bopti. +*/ +enum Format +{ + Format_Mono = Channel_Mono, + Format_MonoAlpha = Format_Mono | Channel_FullAlpha, + Format_Gray = Channel_Light | Channel_Dark, + Format_GrayAlpha = Format_Gray | Channel_FullAlpha, + Format_GreaterAlpha = Format_Mono | Channel_LightAlpha | + Channel_DarkAlpha +}; + +/* + struct Structure + Describes an image's structure. +*/ +struct Structure +{ + int width, height; + int layer_size; + + const unsigned char *data; + int columns; + int end_size, end_bytes; +}; + +/* + struct Command + Contains a drawing operation's parameters. +*/ +struct Command +{ + // Channel being drawn. + enum Channel channel; + // Operation used (whether bopti_op_mono() or bopti_op_gray()). + void (*op)(int offset, uint32_t operator, struct Command *command); + // Portion of the bitmap which is drawn. 'top' and 'bottom' refer to + // lines where 'left' and 'right' refer to column ids. + int left, right, top, bottom; + // Position of the bitmap on the screen. + int x, y; + // Rectangle masks. + uint32_t masks[4]; +}; + +// The video ram addresses are set by the public functions and used internally +// by the module. +// Monochrome video ram, light and dark buffers (in this order). +extern int *bopti_vram, *bopti_v1, *bopti_v2; + + + +//--- +// Some bopti routines. +//--- + +/* + bopti_op() + Operates on a vram long. The operator will often not contain 32 bits of + image information. Since neutral bits are not the same for all + operations, a mask is used to indicate which bits should be used for + the operation. This mask is taken for the image's rectangle masks (see + module display for more information on rectangle masks). + Which operation is performed is determined by the channel setting. +*/ +void bopti_op_mono(int offset, uint32_t operator, struct Command *c); +void bopti_op_gray(int offset, uint32_t operator, struct Command *c); + +/* + bopti_grid() -- general form + bopti_grid_a32() -- when x is a multiple of 32 + + Draws the grid at the beginning of a layer's data. The length of this + grid is always a multiple of 32. + The need for bopti_grid_a32() is not only linked to optimization, + because bopti_grid() will perform a 32-bit shift when x is a multiple + of 32, which is undefined behavior. + bopti_grid() calls bopti_grid_32() by default. +*/ +void bopti_grid_a32(const uint32_t *layer, int columns, int height, + struct Command *c); +void bopti_grid(const uint32_t *layer, int columns, int height, + struct Command *c); +/* + bopti_end_get() + Returns an operator for the end of a line, whose width is lower than 32 + (by design: otherwise, it would have been a column). The given pointer + is read and updated so that it points to the next line at the end of + the operation. +*/ +uint32_t bopti_end_get1(const unsigned char **data); +uint32_t bopti_end_get2(const unsigned char **data); + +/* + bopti_rest() -- general form + bopti_rest_nover() -- when the end does not overlap two vram longs + + Draws the end of a layer, which can be considered as a whole layer + whose with is lower than 32. (Actually is it lower or equal to 16; + otherwise it would have been a column and the end would be empty). The + 'size' arguments is in bytes. + Unlike bopti_grid_a32(), bopti_end_nover() is not called automatically + by bopti_end(). +*/ +void bopti_end_nover(const unsigned char *end, int size, struct Command *c); +void bopti_end(const unsigned char *end, int size, struct Command *c); + +/* + bopti() + Draws a layer in the video ram. +*/ +void bopti(const unsigned char *layer, struct Structure *s, struct Command *c); + +/* + getStructure() + Determines the image size and data pointer. +*/ +void getStructure(struct Image *img, struct Structure *structure); + +#endif // _INTERNALS_BOPTI_H diff --git a/src/p7os/cake.exe/libgint/include/internals/display.h b/src/p7os/cake.exe/libgint/include/internals/display.h new file mode 100644 index 0000000..d862f58 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/internals/display.h @@ -0,0 +1,56 @@ +//--- +// +// gint drawing module: display +// +// Handles vram manipulation and drawing. +// +//--- + +#ifndef _INTERNALS_DISPLAY_H +#define _INTERNALS_DISPLAY_H 1 + +#include + +extern int *vram; + +//--- +// Rectangle masks. +// +// The concept of 'rectangle masks' is used several times in this module. +// It is based on the fact that an operation that affects a rectangle acts +// the same on all its lines. Therefore the behavior of the operation is +// determined by its behavior on a single line, which is represented using +// 'masks' whose bits indicate whether a pixel is affected (1) or not (0). +// +// For example when clearing the screen rectangle (16, 16, 112, 48), the +// masks will represent information '16 to 112 on x-axis', and will hold +// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These +// masks can then be used by setting vram[offset] &= ~masks[i]. This +// appears to be very flexible : for instance, vram[offset] ^= masks[i] +// will reverse the pixels in the same rectangle. +// +// This technique can also be used in more subtle cases with more complex +// patterns, but within this module it is unlikely to happen. +// +//--- + +/* + adjustRectangle() + Adjusts the given rectangle coordinates to ensure that : + - the rectangle is entirely contained in the screen + - x1 < x2 + - y1 < y2 + which is needed when working with screen rectangles. + Returns non-zero if the rectangle is outside the screen. +*/ +int adjustRectangle(int *x1, int *y1, int *x2, int *y2); + +/* + getMasks() + Computes the rectangle masks needed to affect pixels located between x1 + and x2 (both included). The four masks are stored in the third argument + (seen as an array). +*/ +void getMasks(int x1, int x2, uint32_t *masks); + +#endif // _INTERNALS_DISPLAY_H diff --git a/src/p7os/cake.exe/libgint/include/internals/events.h b/src/p7os/cake.exe/libgint/include/internals/events.h new file mode 100644 index 0000000..976e352 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/internals/events.h @@ -0,0 +1,19 @@ +#ifndef _INTERNALS_EVENTS_H +#define _INTERNALS_EVENTS_H + +#include + +#ifndef EVENTS_QUEUE_SIZE +#define EVENTS_QUEUE_SIZE 64 +#endif + +/* + This module is just a circular-array queue that pushes and pops events + like any other queue. Trying to add an event when the queue is full + fails, and the operation is ignored. +*/ +extern volatile struct Event event_queue[]; +extern volatile int queue_start; +extern volatile int queue_size; + +#endif // _INTERNALS_EVENT_H diff --git a/src/p7os/cake.exe/libgint/include/internals/gint.h b/src/p7os/cake.exe/libgint/include/internals/gint.h new file mode 100644 index 0000000..4f038d2 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/internals/gint.h @@ -0,0 +1,30 @@ +#ifndef _INTERNALS_GINT_H +#define _INTERNALS_GINT_H 1 + +//--- +// Exception code strings. +//--- + +extern const char *gint_str[]; + + + +//--- +// Register access. +//--- + +/* + gint_spc() + Returns the saved program counter, which is the last state of execution + saved by interrupt processing. +*/ +unsigned int gint_spc(void); + +/* + gint_ssr() + Returns the saved status register, which is the last configuration + saved by interrupt processing. +*/ +unsigned int gint_ssr(void); + +#endif // _INTERNALS_GINT_H diff --git a/src/p7os/cake.exe/libgint/include/internals/keyboard.h b/src/p7os/cake.exe/libgint/include/internals/keyboard.h new file mode 100644 index 0000000..f982fcf --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/internals/keyboard.h @@ -0,0 +1,39 @@ +#ifndef _INTERNALS_KEYBOARD_H +#define _INTERNALS_KEYBOARD_H + +#include + +// Keyboard variables. +extern volatile unsigned char keyboard_state[10]; +extern volatile int interrupt_flag; + +// Key statistics. +extern int repeat_first, repeat_next; +extern int last_key, last_repeats, last_events; + +// RTC callback id. +extern unsigned cb_id; + +/* + sleep() + Puts the CPU into sleep until an interrupt request is accepted. +*/ +void sleep(void); + +/* + getPressedKey() + Finds a pressed key in the keyboard state and returns it. +*/ +int getPressedKey(volatile unsigned char *keyboard_state); + +/* + getPressedKeys() + Find 'count' pressed keys in the keyboard state and fills the 'keys' + array. Returns the number of keys found. + WARNING: keyboard artifacts make this function read as pressed keys + that aren't (typically, LEFT + DOWN + SHIFT => ALPHA). +*/ +int getPressedKeys(volatile unsigned char *keyboard_state, int *keys, + int count); + +#endif // _INTERNALS_KEYBOARD_H diff --git a/src/p7os/cake.exe/libgint/include/internals/mmu.h b/src/p7os/cake.exe/libgint/include/internals/mmu.h new file mode 100644 index 0000000..23aa121 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/internals/mmu.h @@ -0,0 +1,21 @@ +//--- +// +// gint core module: mmu +// +// A wise application should avoid tampering with the system's +// configuration of the MMU and the TLB. This module implicitly calls the +// system but does nothing by itself. +// +//--- + +#ifndef _MMU_H +#define _MMU_H 1 + +/* + mmu_pseudoTLBInit() + Tries to have the system load enough data into TLB to allow add-in to + execute. +*/ +void mmu_pseudoTLBInit(void); + +#endif // _MMU_H diff --git a/src/p7os/cake.exe/libgint/include/internals/rtc.h b/src/p7os/cake.exe/libgint/include/internals/rtc.h new file mode 100644 index 0000000..228ce59 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/internals/rtc.h @@ -0,0 +1,141 @@ +#ifndef _INTERNALS_RTC_H +#define _INTERNALS_RTC_H + +#include +#include + +#ifndef RTC_CB_ARRAY_SIZE +#define RTC_CB_ARRAY_SIZE 5 +#endif + +/* + struct rtc_cb + An RTC callback. +*/ +struct rtc_cb +{ + enum RTCFrequency freq; + int id; + + void (*callback)(void); + int repeats; +}; + +// The callback array. +struct rtc_cb cb_array[RTC_CB_ARRAY_SIZE]; + +/* + struct mod_rtc + This structure describes the arrangement of RTC register in the memory. + Curious thing, on SH7705, registers RYRAR and RCR3 are at a completely + different address than the other ones. This module does not use these + registers, so they were not included in the structure. +*/ +#pragma pack(push, 1) + +struct mod_rtc +{ + unsigned char const R64CNT; + unsigned char _1; + + union { + unsigned char BYTE; + struct { + unsigned :1; + unsigned TENS :3; + unsigned ONES :4; + }; + } RSECCNT; + unsigned char _2; + + union { + unsigned char BYTE; + struct { + unsigned :1; + unsigned TENS :3; + unsigned ONES :4; + }; + } RMINCNT; + unsigned char _3; + + union { + unsigned char BYTE; + struct { + unsigned :2; + unsigned TENS :2; + unsigned ONES :4; + }; + } RHRCNT; + unsigned char _4; + + // 0 = Sunday, 1 = Monday, ..., 6 = Saturday, 7 = prohibited setting. + unsigned char RWKCNT; + unsigned char _5; + + union { + unsigned char BYTE; + struct { + unsigned :2; + unsigned TENS :2; + unsigned ONES :4; + }; + } RDAYCNT; + unsigned char _6; + + union { + unsigned char BYTE; + struct { + unsigned :3; + unsigned TENS :1; + unsigned ONES :4; + }; + } RMONCNT; + unsigned char _7; + + union { + unsigned short WORD; + struct { + unsigned THOUSANDS :4; + unsigned HUNDREDS :4; + unsigned TENS :4; + unsigned ONES :4; + }; + } RYRCNT; + unsigned char _8[12]; + + union { + unsigned char BYTE; + struct { + unsigned CF :1; + unsigned :2; + unsigned CIE :1; + unsigned AIE :1; + unsigned :2; + unsigned AF :1; + }; + } RCR1; + unsigned char _9; + + union { + unsigned char BYTE; + struct { + unsigned PEF :1; + unsigned PES :3; + unsigned :1; + unsigned ADJ :1; + unsigned RESET :1; + unsigned START :1; + }; + } RCR2; +} __attribute__((packed)); + +#pragma pack(pop) + +/* + We don't need to access the registers in a complicated way like the + function of the timer module. Let's make it simple. +*/ +#define RTC_SH7705 ((volatile struct mod_rtc *)0xfffffec0) +#define RTC_SH7305 ((volatile struct mod_rtc *)0xa413fec0) + +#endif // _INTERNALS_RTC_H diff --git a/src/p7os/cake.exe/libgint/include/internals/stdio.h b/src/p7os/cake.exe/libgint/include/internals/stdio.h new file mode 100644 index 0000000..bf68b81 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/internals/stdio.h @@ -0,0 +1,32 @@ +//--- +// +// standard library module: stdio +// +// Handles most input/output for the program. This module does not +// interact with the file system directly. +// +//--- + +#ifndef _INTERNALS_STDIO_H +#define _INTERNALS_STDIO_H 1 + +#include +#include + +//--- +// Formatted printing. +//--- + +#ifndef __stdio_buffer_size +#define __stdio_buffer_size 256 +#endif + +extern char __stdio_buffer[]; + +/* + __printf() + Formatted printing to the stdio buffer. +*/ +int __printf(size_t size, const char *format, va_list args); + +#endif // _INTERNALS_STDIO_H diff --git a/src/p7os/cake.exe/libgint/include/internals/tales.h b/src/p7os/cake.exe/libgint/include/internals/tales.h new file mode 100644 index 0000000..40342c1 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/internals/tales.h @@ -0,0 +1,55 @@ +#ifndef _INTERNALS_TALES_H +#define _INTERNALS_TALES_H 1 + +#include +#include + +#define OPERATE_ARGS uint32_t *operators, int height, int x, int y + +extern struct Font *font; +extern enum Color color; + +/* + tales_init() + Configures tales with the default font (which is part of gint). +*/ +void tales_init(void) __attribute__((constructor)); + +/* + getCharacterIndex() + Returns the index of a character in a font data area depending on the + font format and the size of the characters. Returns the index in the + data area, as long array, or -1 when the character does not belong to + the font format set. +*/ +int getCharacterIndex(int c); + +/* + operate() + Operates on the vram using the given operators. The x-coordinate should + be a multiple of 32. There should be `height` operators. +*/ +void operate_mono(OPERATE_ARGS); +void operate_gray(OPERATE_ARGS); + +/* + update() + Updates the operators using the given glyph. The operation will not be + complete if there are not enough bits available in the operator data. + In this case the offset will become negative, which means that the + calling procedure has to call operate() and re-call update(). + `available` represents the number of free bits in the operators (lower + bits). + Returns the number of bits available after the operation. If it's + negative, call operate() and update() again. +*/ +int update(uint32_t *operators, int height, int available, uint32_t *glyph); + +/* + render() + Renders text without any formatting analysis, using the given operation + function. +*/ +void render(int x, int y, const char *str, void (*op)(OPERATE_ARGS)); + +#endif // _INTERNALS_TALES_H diff --git a/src/p7os/cake.exe/libgint/include/internals/time.h b/src/p7os/cake.exe/libgint/include/internals/time.h new file mode 100644 index 0000000..236dcf6 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/internals/time.h @@ -0,0 +1,16 @@ +#ifndef _INTERNALS_TIME_H +#define _INTERNALS_TIME_H 1 + +/* + isLeap() + Determines whether the given year is a leap year. +*/ +int isLeap(int year); + +/* + daysInMonth() + Returns number of days for the given month (between 0 and 11) and year. +*/ +int daysInMonth(int month, int year); + +#endif // _INTERNALS_TIME_H diff --git a/src/p7os/cake.exe/libgint/include/internals/timer.h b/src/p7os/cake.exe/libgint/include/internals/timer.h new file mode 100644 index 0000000..f15abc1 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/internals/timer.h @@ -0,0 +1,48 @@ +#ifndef _INTERNALS_TIMER_H +#define _INTERNALS_TIMER_H 1 + +/* + struct Timer + This structure holds information for a running timer. +*/ +struct Timer +{ + void (*callback)(void); + int repeats; +}; + +extern struct Timer timers[3]; + +/* + struct mod_tmu + This structure holds information about the timer unit (peripheral + module) registers. +*/ +struct mod_tmu +{ + unsigned int TCOR; // Timer constant register. + unsigned int TCNT; // Timer counter. + + union + { + unsigned short WORD; + struct + { + unsigned :7; + unsigned UNF :1; // Underflow flag. + unsigned :2; + unsigned UNIE :1; // Underflow interrupt enable. + unsigned CKEG :2; // Clock edge (SH7705 only). + unsigned TPSC :3; // Timer prescaler. + }; + } TCR; // Timer control register. +}; + +/* + timer_get() + Returns the timer and TSTR register addresses. +*/ +void timer_get(int timer, volatile struct mod_tmu **tmu, + volatile unsigned char **tstr); + +#endif // _INTERNALS_TIMER_H diff --git a/src/p7os/cake.exe/libgint/include/keyboard.h b/src/p7os/cake.exe/libgint/include/keyboard.h new file mode 100644 index 0000000..278d0d9 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/keyboard.h @@ -0,0 +1,303 @@ +//--- +// +// gint core module: keyboard analyzer +// +// Probably the most difficult hardware interaction. There is very few +// documentation on how the system actually analyzes the keyboard. While +// disassembling syscalls reveals the following procedure (which was +// already documented by SimonLothar), there is nothing about the +// detection problems of the multi-getkey system. +// +//--- + +#ifndef _KEYBOARD_H +#define _KEYBOARD_H 1 + +#include + +//--- +// Keycodes and related. +//--- + +// The following codes are gint matrix codes. They are not compatible with the +// system's. + +#define KEY_F1 0x69 +#define KEY_F2 0x59 +#define KEY_F3 0x49 +#define KEY_F4 0x39 +#define KEY_F4 0x39 +#define KEY_F5 0x29 +#define KEY_F6 0x19 + +#define KEY_SHIFT 0x68 +#define KEY_OPTN 0x58 +#define KEY_VARS 0x48 +#define KEY_MENU 0x38 +#define KEY_LEFT 0x28 +#define KEY_UP 0x18 + +#define KEY_ALPHA 0x67 +#define KEY_SQUARE 0x57 +#define KEY_POWER 0x47 +#define KEY_EXIT 0x37 +#define KEY_DOWN 0x27 +#define KEY_RIGHT 0x17 + +#define KEY_XOT 0x66 +#define KEY_LOG 0x56 +#define KEY_LN 0x46 +#define KEY_SIN 0x36 +#define KEY_COS 0x26 +#define KEY_TAN 0x16 + +#define KEY_FRAC 0x65 +#define KEY_FD 0x55 +#define KEY_LEFTP 0x45 +#define KEY_RIGHTP 0x35 +#define KEY_COMMA 0x25 +#define KEY_ARROW 0x15 + +#define KEY_7 0x64 +#define KEY_8 0x54 +#define KEY_9 0x44 +#define KEY_DEL 0x34 +#define KEY_AC_ON 0x24 + +#define KEY_4 0x63 +#define KEY_5 0x53 +#define KEY_6 0x43 +#define KEY_MUL 0x33 +#define KEY_DIV 0x23 + +#define KEY_1 0x62 +#define KEY_2 0x52 +#define KEY_3 0x42 +#define KEY_PLUS 0x32 +#define KEY_MINUS 0x22 + +#define KEY_0 0x61 +#define KEY_DOT 0x51 +#define KEY_EXP 0x41 +#define KEY_NEG 0x31 +#define KEY_EXE 0x21 + +// Key modifiers. +#define MOD_SHIFT 0x80 +#define MOD_ALPHA 0x100 +#define MOD_CLEAR ~(MOD_SHIFT | MOD_ALPHA) + +// Key events. +#define KEY_NONE 0x00 +#define KEY_NOEVENT 0xff + +/* + enum KeyboardFrequency + Possible values for the keyboard frequency. +*/ +enum KeyboardFrequency +{ + KeyboardFreq_500mHz = RTCFreq_500mHz, + KeyboardFreq_1Hz = RTCFreq_1Hz, + KeyboardFreq_2Hz = RTCFreq_2Hz, + KeyboardFreq_4Hz = RTCFreq_4Hz, + KeyboardFreq_16Hz = RTCFreq_16Hz, + KeyboardFreq_64Hz = RTCFreq_64Hz, + KeyboardFreq_256Hz = RTCFreq_256Hz, +}; + + + +//--- +// Keyboard configuration. +//--- + +/* + keyboard_setFrequency() + Sets the keyboard frequency. The default frequency is 16 Hz. Very few + applications will need to change this setting. + At low frequencies, you will miss key hits. At high frequencies, you + may lose execution power. +*/ +void keyboard_setFrequency(enum KeyboardFrequency frequency); + +/* + keyboard_setRepeatRate() + Sets the default repeat rate for key events. The delay before the first + repeat may have a different value (usually longer). The unit for the + argument is the keyboard period. For example at 32 Hz, values of + (20, 4) will imitate the system default. + Set to 0 to disable repetition. If first = 0, no repetition will be + allowed. If first != 0 and next = 0, only one repetition will be + allowed. +*/ +void keyboard_setRepeatRate(int first, int next); + + + +//--- +// Keyboard access. +//--- + +/* + enum GetKeyOpt + Options available for use with getkey_opt(). +*/ +enum GetkeyOpt +{ + Getkey_NoOption = 0x00, + + // Consider [SHIFT] and [ALPHA] as modifiers instead of returning + // KEY_SHIFT and KEY_ALPHA. + Getkey_ShiftModifier = 0x01, + Getkey_AlphaModifier = 0x02, + + // Key repetition. Notice that modifiers will never be repeated. + Getkey_RepeatArrowKeys = 0x10, + Getkey_RepeatCharKeys = 0x20, + Getkey_RepeatCtrlKeys = 0x40, + Getkey_RepeatFuncKeys = 0x80, + // Shorthand for the four previous properties. + Getkey_RepeatAllKeys = 0xf0, +}; + +/* + keylast() + Returns the matrix code of the last pressed key. If repeat_count is + non-NULL, it is set to the number of repetitions. +*/ +int keylast(int *repeat_count); + +/* + keystate() + Returns the address of the keyboard state array. The keyboard state + consists in 10 bytes, in which every key is represented as a bit. + The returned address is the original buffer address. You should avoid + editing the array. It wouldn't influence the behavior of the keyboard + functions, but the buffer data is very volatile. Therefore, data + written to the buffer could be replaced anytime. +*/ +volatile unsigned char *keystate(void); + +/* + getkey() + Blocking function with auto-repeat and SHIFT modifying functionalities. + Reproduces the behavior of the system's GetKey(). Returns the matrix + code with a possible MOD_SHIFT bit. +*/ +int getkey(void); + +/* + getkey_opt() + Enhances getkey() with most general functionalities. An OR-combination + of options may be given as second argument. + If max_cycles is non-zero and positive, getkey_opt() will return + KEY_NOEVENT if no event occurs during max_cycle analysis. + As getkey(), returns the pressed key matrix code, possibly with + modifiers depending on the options. +*/ +int getkey_opt(enum GetkeyOpt options, int max_cycles); + +/* + multigetkey() + + Listens the keyboard for simultaneous key hits. This functions fills + array `keys` with `count` keycodes, adding KEY_NONE at the end if + less than `count` keys are pressed. + If `max_cycles` is non-zero and nothing happens after `max_cycles` + cycles, this function returns an array of KEY_NONE. + + WARNING: + Because of hardware limitations, this function generally yields poor + results. Rectangle and column effects make it read unpressed keys as + pressed (see documentation for more information). The more pressed + keys, the more errors. + + The results are guaranteed to be exact if two keys or less are pressed. + With three keys or more, column effects (on SH4) and rectangle effects + (on both platforms) mess up the results by making this function think + that some keys, which are actually unpressed, are pressed. + + This function is designed to make combinations of one or two arrow keys + with another key as viable as possible. On SH4, this works pretty well + even if combinations like Left + Down + SHIFT trigger ALPHA sometimes. + On SH3, rectangle effects are *always* present, making it impossible to + use Left + Down or Up + Right with any other key in their rows without + having this function return junk. + + Any other combination of keys may quite randomly result in variably + incorrect results. Please do not expect multigetkey() to work as an + ideal multi-key analyzer. +*/ +void multigetkey(int *keys, int count, int max_cycles); + + + +//--- +// Key analysis. +//--- + +enum KeyType +{ + KeyType_Arrow = 1, + KeyType_Character = 2, + KeyType_Control = 4, + KeyType_Function = 8, +}; + +/* + keyid() + Returns a non-matrix key code that can be used for array subscript. + Ignores modifiers. +*/ +int keyid(int key); + +/* + keychar() + Returns the ASCII character associated with a character key; 0 for + other keys. +*/ +int keychar(int key); + +/* + keytype() + Returns a key's type. Ignores modifiers. +*/ +enum KeyType keytype(int key); + + + +//--- +// Internal API. +// Reference here for documentation purposes only. Do not call. +//--- + +/* + keyboard_interrupt() + Notifies the keyboard module that an interrupt request has been issued, + and updates the keyboard state. +*/ +void keyboard_interrupt(void) __attribute__((section(".gint.int"))); + +/* + keyboard_updateState() + Updates the keyboard state. +*/ +void keyboard_updateState_7705(volatile unsigned char *state) + __attribute__((section(".gint.int"))); +void keyboard_updateState_7305(volatile unsigned char *state) + __attribute__((section(".gint.int"))); + +/* + keyboard_init() + Starts the keyboard timer. +*/ +void keyboard_init(void) __attribute__((constructor)); + +/* + keyboard_quit() + Stops the keyboard timer. +*/ +void keyboard_quit(void) __attribute__((destructor)); + +#endif // _KEYBOARD_H diff --git a/src/p7os/cake.exe/libgint/include/mpu.h b/src/p7os/cake.exe/libgint/include/mpu.h new file mode 100644 index 0000000..fd4a498 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/mpu.h @@ -0,0 +1,76 @@ +//--- +// +// gint core module: mpu +// +// Determines which kind of MPU is running the program. This module +// provides macro tests isSH3(), isSH4(), and the identifier of the MPU, +// which is stored in a global variable MPU_CURRENT. +// +// If you need to do MPU-dependant jobs, prefer the following alternative: +// +// if(isSH3()) +// { +// ... +// } +// else +// { +// ... +// } +// +//--- + +#ifndef _MPU_H +#define _MPU_H 1 + +/* + enum MPU + This type holds information about the calculator's MPU. +*/ +enum MPU +{ + MPU_Unknown = 0, + // fx-9860G SH3. + MPU_SH7337 = 1, + // fx-9860G II SH3. + MPU_SH7355 = 2, + // fx-9860G II SH4. + MPU_SH7305 = 3, + // Just for reference. + MPU_SH7724 = 4 +}; + +// Global MPU variable, accessible for direct tests. Initialized at the +// beginning of execution. +extern enum MPU MPU_CURRENT; + +// Quick SH3 test. It is safer to assume that an unknown model is SH4 because +// SH3-based models are not produced anymore. +#define isSH3() (MPU_CURRENT == MPU_SH7337 || MPU_CURRENT == MPU_SH7355) +#define isSH4() !isSH3() + + + +//--- +// Public API. +//--- + +/* + getMPU() + Determines the MPU type and returns it. MPU_CURRENT is not updated. +*/ +enum MPU getMPU(void); + + + +//--- +// Internal API. +// Referenced here for documentation purposes only. Do not call. +//--- + +/* + mpu_init() + Determines the MPU type and stores the result into MPU_CURRENT. +*/ +void mpu_init(void) __attribute__((constructor)); + +#endif // _MPU_H diff --git a/src/p7os/cake.exe/libgint/include/rtc.h b/src/p7os/cake.exe/libgint/include/rtc.h new file mode 100644 index 0000000..805c91d --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/rtc.h @@ -0,0 +1,121 @@ +//--- +// +// gint core module: rtc +// +// Manages RTC. This module is used behind standard module time. +// +//--- + +#ifndef _RTC_H +#define _RTC_H 1 + +//--- +// Time access. +//--- + +/* + struct RTCTime + Defines a point in time. +*/ +struct RTCTime +{ + int seconds; // Seconds in range 0-59 + int minutes; // Minutes in range 0-59 + int hours; // Hours in range 0-23 + int month_day; // Day of month in range 1-31 + int month; // Month in range 0-11 + int year; // Years (full value) + int week_day; // Day of week in range 0(Sunday)-6(Saturday). +}; + +/* + rtc_getTime() + Reads the current time from the RTC. There is no guarantee that the + week day is correct (use the time API for that). +*/ +struct RTCTime rtc_getTime(void); + +/* + rtc_setTime() + Sets the time in the RTC registers. The week day is set to 0 if greater + than 6. Other fields are not checked. +*/ +void rtc_setTime(struct RTCTime time); + + + +//--- +// Callback API. +//--- + +/* + enum RTCFrequency + Describes the possible frequencies available for the real-time clock + interrupt. +*/ +enum RTCFrequency +{ + RTCFreq_500mHz = 7, + RTCFreq_1Hz = 6, + RTCFreq_2Hz = 5, + RTCFreq_4Hz = 4, + RTCFreq_16Hz = 3, + RTCFreq_64Hz = 2, + RTCFreq_256Hz = 1, + RTCFreq_None = 0, +}; + +/* + rtc_cb_add() + Registers a new callback for the RTC. Returns the callback id on + success (positive integer), or one of the following error codes: + -1 Array is full + -2 Invalid parameter + The number of repeats may be set to 0, in which case the callback is + called indefinitely unless the user calls rtc_cb_end(). +*/ +int rtc_cb_add(enum RTCFrequency freq, void (*function)(void), int repeats); + +/* + rtc_cb_end() + Removes the callback with the given id (as returned by rtc_cb_add()) + from the callback array. +*/ +void rtc_cb_end(int id); + +/* + rtc_cb_edit() + Changes information related to a callback. This function returns 0 on + success, or one of the following error codes: + -1 Callback does not exist + -2 Invalid parameters + This function never removes a callback. Call rtc_cb_end() for this. One + can set the function to NULL or the frequency to RTCFreq_None to + temporarily disable the callback. +*/ +int rtc_cb_edit(int id, enum RTCFrequency new_freq, + void (*new_function)(void)); + + + +//--- +// Internal API. +// Referenced here for documentation purposes only. Do not call. +//--- + +/* + rtc_interrupt() + Handles an RTC interrupt by calling the callback. +*/ +void rtc_interrupt(void) __attribute__((section(".gint.int"))); +void rtc_interrupt_7705(void) __attribute__((section(".gint.int"))); +void rtc_interrupt_7305(void) __attribute__((section(".gint.int"))); + +/* + rtc_cb_interrupt() + Handles an RTC interrupt. Calls the RTC callbacks if necessary, and + updates the repeat counts. +*/ +void rtc_cb_interrupt(void); + +#endif // _RTC_H diff --git a/src/p7os/cake.exe/libgint/include/screen.h b/src/p7os/cake.exe/libgint/include/screen.h new file mode 100644 index 0000000..175e983 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/screen.h @@ -0,0 +1,23 @@ +//--- +// +// gint display module: screen +// +// Interacts with the physical screen. See other display modules for video +// ram management and drawing. +// +// The screen basically has two input values, which are a register +// selector and the selected register's value. What this module does is +// essentially selecting registers by setting *selector and assigning them +// values by setting *data. +//--- + +#ifndef _SCREEN_H +#define _SCREEN_H 1 + +/* + screen_display() + Displays contents on the full screen. Expects a 1024-byte buffer. +*/ +void screen_display(const void *vram); + +#endif diff --git a/src/p7os/cake.exe/libgint/include/setjmp.h b/src/p7os/cake.exe/libgint/include/setjmp.h new file mode 100644 index 0000000..54dceea --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/setjmp.h @@ -0,0 +1,35 @@ +//--- +// +// gint standard module: setjmp +// +// Long jumps. The register contents are saved in a buffer when setjmp() +// is called and restored at any time when longjmp() performs the jump. +// +//--- + +#ifndef _SETJMP_H +#define _SETJMP_H 1 + +// There are 16 CPU registers that *must* be saved to ensure a basically +// safe jump. +typedef unsigned int jmp_buf[16]; + + + +//--- +// Long jump functions. +//--- + +/* + setjmp() O(1) + Configures a jump by saving data to the given jump buffer. +*/ +int setjmp(jmp_buf env); + +/* + longjmp() O(1) + Performs a long jump. +*/ +void longjmp(jmp_buf env, int value); + +#endif // _SETJMP_H diff --git a/src/p7os/cake.exe/libgint/include/stdio.h b/src/p7os/cake.exe/libgint/include/stdio.h new file mode 100644 index 0000000..f19ecdb --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/stdio.h @@ -0,0 +1,44 @@ +//--- +// +// standard library module: stdio +// +// Handles most input/output for the program. This module does not +// interact with the file system directly. +// +//--- + +#ifndef _STDIO_H +#define _STDIO_H 1 + +#include +#include + +//--- +// Formatted printing. +//--- + +/* + sprintf() + Prints to a string. +*/ +int sprintf(char *str, const char *format, ...); + +/* + snprintf() + Prints to a string with a size limit. +*/ +int snprintf(char *str, size_t size, const char *format, ...); + +/* + vsprintf() + Prints to a string from an argument list. +*/ +int vsprintf(char *str, const char *format, va_list args); + +/* + vsnprintf() + The most generic formatted printing function around there. +*/ +int vsnprintf(char *str, size_t size, const char *format, va_list args); + +#endif // _STDIO_H diff --git a/src/p7os/cake.exe/libgint/include/stdlib.h b/src/p7os/cake.exe/libgint/include/stdlib.h new file mode 100644 index 0000000..5904525 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/stdlib.h @@ -0,0 +1,149 @@ +//--- +// +// standard library module: stdlib +// +// Provides standard functionalities such as dynamic allocation, +// string/numeric conversion, and abort calls. +// +//--- + +#ifndef _STDLIB_H +#define _STDLIB_H 1 + +//--- +// Common definitions. +//--- + +#include +#include + +// Common exit codes. +#define EXIT_SUCCESS 1 +#define EXIT_FAILURE 0 + +// Number of atexit() registrations guaranteed. +#ifndef ATEXIT_MAX +#define ATEXIT_MAX 16 +#endif + +// Maximum value returned by rand(). +#define RAND_MAX INT_MAX + +// Integer division result. +typedef struct +{ + int quot, rem; +} div_t; +typedef struct +{ + long quot, rem; +} ldiv_t; + + + +//--- +// Program exit functions. +//--- + +/* + abort() + Aborts the program execution without calling the exit handlers. +*/ +void abort(void); + +/* + exit() + Stops the program execution with the given status code, after calling + the exit handlers. +*/ +void exit(int status); + +/* + atexit() + Registers a function to be called at normal program termination. +*/ +int atexit(void (*function)(void)); + + + +//--- +// Dynamic storage allocation. +//--- + +/* + malloc() + Allocates 'size' bytes and returns a pointer to a free memory area. + Returns NULL on error. +*/ +void *malloc(size_t size); + +/* + calloc() + Allocates 'n' elements of size 'size' and wipes the memory area. + Returns NULL on error. +*/ +void *calloc(size_t n, size_t size); + +/* + realloc() + Reallocates a memory block and moves its data. +*/ +void *realloc(void *ptr, size_t size); + +/* + free() + Frees a memory block allocated by malloc(), calloc() or realloc(). +*/ +void free(void *ptr); + + + +//--- +// Random number generation. +//--- + +/* + rand() + Returns a pseudo-random number. +*/ +int rand(void); + +/* + srand() + Changes the seed used by rand(). +*/ +void srand(unsigned int seed); + +//--- +// Integer arithmetic. +//--- + +/* + abs() + Returns the absolute value of an integer. +*/ +int abs(int x); +// Use a macro instead, when possible. +#define abs(x) ((x) < 0 ? -(x) : (x)) + +/* + labs() + Returns the absolute value of a long integer. +*/ +long labs(long x); +// Use a macro instead. +#define labs(x) ((x) < 0 ? -(x) : (x)) + +/* + div() + Computes the integer division of numerator by denominator. +*/ +div_t div(int numerator, int denominator); + +/* + ldiv() + Computes the integer division of two long integers. +*/ +ldiv_t ldiv(long numerator, long denominator); + +#endif // _STDLIB_H diff --git a/src/p7os/cake.exe/libgint/include/string.h b/src/p7os/cake.exe/libgint/include/string.h new file mode 100644 index 0000000..dc0ac1c --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/string.h @@ -0,0 +1,63 @@ +//--- +// +// standard library module: string +// +// String manipulation using NUL-terminated byte arrays, without extended +// characters. +// +//--- + +#ifndef _STRING_H +#define _STRING_H 1 + +#include + +//--- +// Memory manipulation. +//--- + +/* + memcpy() O(byte_number) + Copies a memory area. The two areas must not overlap (if they do, use + memmove()). A smart copy is performed when possible. To enhance + performance, make sure than destination and source are both 4-aligned. +*/ +void *memcpy(void *destination, const void *source, size_t byte_number); + +/* + memset() O(byte_number) + Sets the contents of a memory area. A smart copy is performed. +*/ +void *memset(void *destination, int byte, size_t byte_number); + + + +//--- +// String manipulation. +//--- + +/* + strlen() O(len(str)) + Returns the length of a string. +*/ +size_t strlen(const char *str); + +/* + strcpy() O(len(source)) + Copies a string to another. +*/ +char *strcpy(char *destination, const char *source); + +/* + strchr() O(len(str)) + Searches a character in a string. +*/ +const char *strchr(const char *str, int value); + +/* + strncpy() O(min(len(source), size)) + Copies part of a string to another. +*/ +char *strncpy(char *destination, const char *source, size_t size); + +#endif // _STRING_H diff --git a/src/p7os/cake.exe/libgint/include/tales.h b/src/p7os/cake.exe/libgint/include/tales.h new file mode 100644 index 0000000..e1304c3 --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/tales.h @@ -0,0 +1,123 @@ +//--- +// +// gint drawing module: tales +// +// Text displaying. Does some pretty good optimization, though requires +// dynamic allocation. The stack is used. +// +//--- + +#ifndef _TALES_H +#define _TALES_H 1 + +#include +#include + +//--- +// Types and constants. +//--- + +/* + enum ImageFormat + This type holds information about the characters in the font. Each bit + represents various characters, and the type itself is a combination of + several of those bits. + Bits represent the following characters (lsb right): + -- -- -- non-print | special capitals lower numbers +*/ +enum FontFormat +{ + FontFormat_Unknown = 0x00, + FontFormat_Numeric = 0x01, + FontFormat_LowerCase = 0x02, + FontFormat_UpperCase = 0x04, + FontFormat_Letters = 0x06, + FontFormat_Common = 0x07, + FontFormat_Print = 0x0f, + FontFormat_Ascii = 0x1f, +}; + +/* + struct FontGlyph + Holds a glyph's data. The width is used for spacing, and the raw data + is encoded line after line, from to to bottom, by appending bits + without consideration of the byte boundaries. + This structure is actually never used, because data is read directly + as a longword array (hence the 4-byte alignment). +*/ +struct FontGlyph +{ + unsigned char width; + + const unsigned char data[]; +} __attribute__((aligned(4))); + +/* + struct Font + Holds a font's data. Data is accessed using longword operations, hence + the 4-alignment attributes. The line height is the one given in the + font image header line, which may be used by applications that write + strings on several lines. The data height is the height of the biggest + glyph. Every glyph is encoded on 'data_height' lines, for optimization + considerations. + The index field is used to reduce character access time. + The name field may not be NUL-terminated when the name contains 28 + characters. When the name is shorter, the field is padded with zeros. +*/ +struct Font +{ + unsigned char magic; + + unsigned char format; + unsigned char line_height; + unsigned char data_height; + + // Warning : this field may not be NUL-terminated. + char name[28]; + + uint16_t index[16]; + + __attribute__((aligned(4))) const uint32_t glyphs[]; + +} __attribute__((aligned(4))); +// Useful shorthand for user code. +typedef struct Font Font; + + + +//--- +// Generic functions. +//--- + +/* + text_configure() + Sets the font and color to use for subsequent text operations. Pass + font = NULL to use the default font. +*/ +void text_configure(struct Font *font, enum Color color); + +/* + dtext() + Prints the given string, without any analysis. +*/ +void dtext(int x, int y, const char *str); + +/* + gtext() + Prints the given raw string. +*/ +void gtext(int x, int y, const char *str); + +/* + dprint() + Prints a formatted string. Works the same as printf(). +*/ +void dprint(int x, int y, const char *format, ...); + +/* + gprint() + Prints a formatted string. Works the same as printf(). +*/ +void gprint(int x, int y, const char *format, ...); + +#endif // _TALES_H diff --git a/src/p7os/cake.exe/libgint/include/time.h b/src/p7os/cake.exe/libgint/include/time.h new file mode 100644 index 0000000..107e4fc --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/time.h @@ -0,0 +1,126 @@ +//--- +// +// standard library module: time +// +// Provides time manipulation and representation functions. +// +//--- + +#ifndef _TIME_H +#define _TIME_H 1 + +#include + +//--- +// Some related types. +//--- + +/* + struct tm + Represents a point in time and gives some date information. +*/ +struct tm +{ + int tm_sec; // Seconds in range 0-59 + int tm_min; // Minutes in range 0-59 + int tm_hour; // Hours in range 0-23 + int tm_mday; // Day of month in range 1-31 + int tm_mon; // Month in range 0-11 + int tm_year; // Number of years since 1900 + int tm_wday; // Day of week in range 0(Sunday)-6(Saturday). + int tm_yday; // Day of the year in range 0-365. + int tm_isdst; // This will always be 0. +}; + +/* + clock_t + Only used by clock(). +*/ +typedef signed int clock_t; + +/* + time_t + Number of seconds elapsed since 1970-01-01 00:00:00. +*/ +typedef signed int time_t; + + + +//--- +// Time access. +//--- + +/* + clock() + Should return elapsed CPU time since beginning of program execution. + This is currently not implemented and returns -1. +*/ +clock_t clock(void); + +/* + time() + Returns the current time as calendar time. If you need a broken-down + time, either use the RTC API or gmtime(). However, this function is + already based on mktime() (for hardware reasons) so it would be much + faster to use the RTC API if possible. + If timeptr is not NULL, it is set to the current time, that is, the + value that is returned. +*/ +time_t time(time_t *timeptr); + +/* + difftime() + Returns the number of seconds between the given points. +*/ +double difftime(time_t end, time_t beginning); +// But this macro should do. +#define difftime(end, beginning) ((double)((end) - (beginning))) + + + +//--- +// Time representation. +//--- + +/* + asctime() + Converts broken-down time to string representation on the form + "Wed Jun 30 21:49:08 1993\n". The returned string is statically + allocated and may be overwritten by any subsequent call to a time + function. +*/ +char *asctime(const struct tm *time); + +/* + ctime() + Converts calendar time to string representation on the form + "Wed Jun 30 21:49:08 1993\n". The returned string is statically + allocated and may be overwritten by any subsequent call to a time + function. +*/ +char *ctime(const time_t *timer); + + + +//--- +// Time conversion. +//--- + +/* + mktime() + Converts broken-down time to calendar time. Computes structure fields + tm_wday and tm_yday using the other fields. Member structures outside + their range are normalized (e.g. 40 October becomes 9 November) and + tm_isdst is set. +*/ +time_t mktime(struct tm *time); + +/* + gmtime() + Converts calendar time to broken-down time. The returned pointer is + statically allocated and may be overwritten by any subsequent call to + a time function. +*/ +struct tm *gmtime(const time_t *t); + +#endif // _TIME_H diff --git a/src/p7os/cake.exe/libgint/include/timer.h b/src/p7os/cake.exe/libgint/include/timer.h new file mode 100644 index 0000000..f896c4a --- /dev/null +++ b/src/p7os/cake.exe/libgint/include/timer.h @@ -0,0 +1,89 @@ +//--- +// +// gint core module: timer +// +// Basic timer unit manipulation. Starts and stops timers with variable +// number of repeats, and allows timer reloads without pause. +// +//--- + +#ifndef _TIMER_H +#define _TIMER_H 1 + +#include + +//--- +// Constants. +//--- + +// Timer identifiers. +#define TIMER_0 0 +#define TIMER_TMU0 TIMER_0 +#define TIMER_1 1 +#define TIMER_TMU1 TIMER_1 +#define TIMER_2 2 +#define TIMER_TMU2 TIMER_2 +// Timer function identifiers. +#define TIMER_KEYBOARD TIMER_TMU0 +#define TIMER_GRAY TIMER_TMU1 +#define TIMER_USER TIMER_TMU2 + +// Timer prescalers. +#define TIMER_Po_4 0 +#define TIMER_Po_16 1 +#define TIMER_Po_64 2 +#define TIMER_Po_256 3 +#define TIMER_TCLK 5 + + + +//--- +// Public API. +//--- + +/* + timer_start() + Configures and starts a timer. The timer argument expects a timer name. + You can use TIMER_USER anytime. You may also use TIMER_GRAY if you're + not running the gray engine. + The delay is in clock counts unit. The possible values for the + prescaler are dividers of the peripheral clock frequency Po: + - TIMER_Po_4 + - TIMER_Po_16 + - TIMER_Po_64 + - TIMER_Po_256 + - TIMER_TCLK + The number of repeats may to set to 0. In this case, the timer will not + stop until timer_stop() is explicitly called. +*/ +void timer_start(int timer, int delay, int prescaler, void (*callback)(void), + int repeats); + +/* + timer_stop() + Stops the given timer. This function may be called even if the timer is + not running. +*/ +void timer_stop(int timer); + +/* + timer_reload() + Reloads the given timer with the given constant. Starts the timer if + it was stopped. The new delay uses the same unit as in timer_start(). +*/ +void timer_reload(int timer, int new_delay); + + + +//--- +// Internal API. +// Referenced for documentation purposes only. Do not call. +//--- + +/* + timer_interrupt() + Handles the interrupt for the given timer. +*/ +void timer_interrupt(int timer) __attribute__((section(".gint.int"))); + +#endif // _TIMER_H diff --git a/src/p7os/cake.exe/libgint/src/bopti/bopti_internals.c b/src/p7os/cake.exe/libgint/src/bopti/bopti_internals.c new file mode 100644 index 0000000..b8c08ce --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/bopti/bopti_internals.c @@ -0,0 +1,329 @@ +#include + +// Monochrome video ram, light and dark buffers (in this order). +int *bopti_vram, *bopti_v1, *bopti_v2; + +/* + bopti_op() + Operates on a vram long. The operator will often not contain 32 bits of + image information. Since neutral bits are not the same for all + operations, a mask is used to indicate which bits should be used for + the operation. This mask is taken for the image's rectangle masks (see + module display for more information on rectangle masks). + Which operation is performed is determined by the channel setting. +*/ +void bopti_op_mono(int offset, uint32_t operator, struct Command *c) +{ + operator &= c->masks[offset & 3]; + + switch(c->channel) + { + case Channel_FullAlpha: + bopti_vram[offset] &= ~operator; + break; + + case Channel_Mono: + bopti_vram[offset] |= operator; + break; + + default: + break; + } +} +void bopti_op_gray(int offset, uint32_t operator, struct Command *c) +{ + operator &= c->masks[offset & 3]; + + switch(c->channel) + { + case Channel_FullAlpha: + bopti_v1[offset] &= ~operator; + bopti_v2[offset] &= ~operator; + break; + + case Channel_LightAlpha: + case Channel_DarkAlpha: + break; + + case Channel_Mono: + bopti_v1[offset] |= operator; + bopti_v2[offset] |= operator; + break; + + case Channel_Light: + bopti_v1[offset] |= operator; + break; + + case Channel_Dark: + bopti_v2[offset] |= operator; + break; + } +} + +/* + bopti_grid() -- general form + bopti_grid_a32() -- when x is a multiple of 32 + + Draws the grid at the beginning of a layer's data. The length of this + grid is always a multiple of 32. + The need for bopti_grid_a32() is not only linked to optimization, + because bopti_grid() will perform a 32-bit shift when x is a multiple + of 32, which is undefined behavior. +*/ +void bopti_grid_a32(const uint32_t *layer, int column_count, int height, + struct Command *c) +{ + int vram_column_offset = (c->y << 2) + (c->x >> 5); + int vram_offset = vram_column_offset; + int column, row; + + for(column = 0; column < column_count; column++) + { + for(row = c->top; row < c->bottom; row++) + { + (*c->op)(vram_offset, layer[row], c); + vram_offset += 4; + } + + vram_column_offset++; + vram_offset = vram_column_offset; + layer += height; + } +} +void bopti_grid(const uint32_t *layer, int column_count, int height, + struct Command *c) +{ + if(!column_count) return; + if(!(c->x & 31)) + { + bopti_grid_a32(layer, column_count, height, c); + return; + } + + const uint32_t *p1, *p2; + uint32_t l1, l2, operator; + int right_column, line; + int actual_column_count; + + int vram_column_offset = (c->y << 2) + (c->x >> 5) + (c->x < 0); + int vram_offset = vram_column_offset; + + int shift1 = 32 - (c->x & 31); + int shift2 = (c->x & 31); + + // Initializing two pointers. They will read two adjacent columns at + // the same time (p2 is column ahead of p1). Since the columns are + // written one after another, incrementing them will suffice when + // reaching the end of two columns, to move them to the next ones. + p1 = layer - height; + p2 = layer; + + // We don't want to write the first vram column when x is negative + // because it's outside the screen. + if(c->x < 0) p1 += height, p2 += height; + right_column = (c->x < 0); + // For the same reason, we don't to draw the additional rightmost + // column when it begins after 96. + if(c->x + (column_count << 5) > 128) + actual_column_count = column_count - 1; + else + actual_column_count = column_count; + + // Drawing vram longwords, using pairs of columns. + while(right_column <= actual_column_count) + { + for(line = c->top; line < c->bottom; line++) + { + l1 = (right_column > 0) ? p1[line] : (0); + l2 = (right_column < column_count) ? p2[line] : (0); + + operator = (l1 << shift1) | (l2 >> shift2); + (*c->op)(vram_offset, operator, c); + vram_offset += 4; + } + + p1 += height; + p2 += height; + vram_column_offset++; + vram_offset = vram_column_offset; + right_column++; + } +} + +/* + bopti_end_get() + Returns an operator for the end of a line, whose width is lower than 32 + (by design: otherwise, it would have been a column). The given pointer + is read and updated so that it points to the next line at the end of + the operation. +*/ +uint32_t bopti_end_get1(const unsigned char **data) +{ + uint32_t operator = **data; + *data += 1; + return operator; +} +uint32_t bopti_end_get2(const unsigned char **data) +{ + uint32_t operator = *((uint16_t *)*data); + *data += 2; + return operator; +} + +/* + bopti_rest() -- general form + bopti_rest_nover() -- when the end does not overlap two vram longs + + Draws the end of a layer, which can be considered as a whole layer + whose with is lower than 32. (Actually is it lower or equal to 16; + otherwise it would have been a column and the end would be empty). +*/ +void bopti_end_nover(const unsigned char *end, int size, struct Command *c) +{ + uint32_t (*get)(const unsigned char **data) = + (size == 2) ? bopti_end_get2 : bopti_end_get1; + + // We *have* shift >= 0 because of this function's 'no overlap' + // requirement. + int shift = (32 - (size << 3)) - (c->x & 31); + int vram_offset = (c->y << 2) + (c->x >> 5); + uint32_t operator; + int row; + + // Skipping c->top lines (because get() function only allows sequential + // access). + end += c->top * size; + + for(row = c->top; row < c->bottom; row++) + { + operator = (*get)(&end); + operator <<= shift; + + (*c->op)(vram_offset, operator, c); + vram_offset += 4; + } +} +void bopti_end(const unsigned char *end, int size, struct Command *c) +{ + uint32_t (*get)(const unsigned char **data) = + (size == 2) ? (bopti_end_get2) : (bopti_end_get1); + + int vram_offset = (c->y << 2) + (c->x >> 5); + uint32_t row_data, operator; + int row; + + int shift_base = (32 - (size << 3)); + int shift1 = (c->x & 31) - shift_base; + int shift2 = shift_base + 32 - (c-> x & 31); + + // Skipping c->top lines (because get() function only allows sequential + // access). + end += c->top * size; + + for(row = c->top; row < c->bottom; row++) + { + row_data = (*get)(&end); + + operator = row_data >> shift1; + (*c->op)(vram_offset, operator, c); + + operator = row_data << shift2; + (*c->op)(vram_offset + 1, operator, c); + + vram_offset += 4; + } +} + + + +//--- +// Wrappers and various functions. +//--- + +/* + bopti() + Draws a layer in the video ram. +*/ +void bopti(const unsigned char *layer, struct Structure *s, struct Command *c) +{ + const unsigned char *grid, *end; + int grid_columns, has_end; + + // Skipping columns at the beginning. + grid = layer + ((c->left * s->height) << 2); + + // Updating the command arguments to eliminate some information about + // parts that are not being drawn. + c->x += (c->left << 5); + c->y += c->top; + + // Columns are identified by ids 0 to s->columns - 1, and the end has + // id s->columns. So the end is drawn if this last column is included. + has_end = (c->right == s->columns); + // Computing number of grid columns to draw. + grid_columns = c->right - c->left + 1 - has_end; + + bopti_grid((const uint32_t *)grid, grid_columns, s->height, c); + + if(has_end) + { + end = layer + ((s->columns * s->height) << 2); + c->x += (grid_columns << 5); + + if((c->x & 31) + s->end_size <= 32) + bopti_end_nover(end, s->end_bytes, c); + else + bopti_end(end, s->end_bytes, c); + } +} + +/* + getStructure() + Determines the image size and data pointer. +*/ +void getStructure(struct Image *img, struct Structure *s) +{ + int column_count, end, end_bytes, layer; + + // Large images. + if(!img->width && !img->height) + { + s->width = (img->data[0] << 8) | img->data[1]; + s->height = (img->data[2] << 8) | img->data[3]; + s->data = img->data + 4; + + column_count = (s->width + 31) >> 5; + end = 0; + end_bytes = 0; + } + else + { + s->width = img->width; + s->height = img->height; + s->data = img->data; + + column_count = img->width >> 5; + end = img->width & 31; + end_bytes = + !end ? 0 : + end <= 8 ? 1 : + end <= 16 ? 2 : + 4; + + if(end_bytes == 4) + { + column_count++; + end = 0; + end_bytes = 0; + } + } + + // The layer size must be rounded to a multiple of 4. + layer = s->height * ((column_count << 2) + end_bytes); + if(layer & 3) layer += 4 - (layer & 3); + + s->columns = column_count; + s->end_bytes = end_bytes; + s->end_size = end; + s->layer_size = layer; +} diff --git a/src/p7os/cake.exe/libgint/src/bopti/dimage.c b/src/p7os/cake.exe/libgint/src/bopti/dimage.c new file mode 100644 index 0000000..6b09ae5 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/bopti/dimage.c @@ -0,0 +1,57 @@ +#include +#include + +/* + dimage() + Displays a monochrome image in the video ram. +*/ +void dimage(int x, int y, struct Image *img) +{ + if(!img || img->magic != 0xb7) return; + + struct Structure s; + struct Command command; + int actual_width; + int format = img->format, i = 0; + + if(format != Format_Mono && format != Format_MonoAlpha) return; + getStructure(img, &s); + + //--- + // Adjusting image parameters. + //--- + + if(x + s.width < 0 || x > 127 || y + s.height < 0 || y > 63) return; + + command.top = (y < 0) ? (-y) : (0); + command.bottom = (y + s.height > 64) ? (64 - y) : (s.height); + command.left = ((x < 0) ? (-x) : (0)) >> 5; + actual_width = (x + s.width > 128) ? (128 - x) : (s.width); + command.right = ((actual_width + 31) >> 5) - 1; + + command.op = bopti_op_mono; + + if(x >= 0) getMasks(x, x + actual_width - 1, command.masks); + else getMasks(0, actual_width + x - 1, command.masks); + + bopti_vram = display_getCurrentVRAM(); + + while(format) + { + // Drawing every layer, in order of formats. + if(format & 1) + { + // These members are modified by bopti()! + command.x = x; + command.y = y; + command.channel = (1 << i); + + bopti(s.data, &s, &command); + s.data += s.layer_size; + } + + format >>= 1; + i++; + } + +} diff --git a/src/p7os/cake.exe/libgint/src/bopti/dimage_part.c b/src/p7os/cake.exe/libgint/src/bopti/dimage_part.c new file mode 100644 index 0000000..06ef43b --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/bopti/dimage_part.c @@ -0,0 +1,65 @@ +#include +#include + +/* + dimage_part() + Draws a portion of an image, defined by its bounding rectangle. + Point (left, top) is included, but (left + width, top + height) is + excluded. +*/ +void dimage_part(int x, int y, struct Image *img, int left, int top, + int width, int height) +{ + if(!img || img->magic != 0xb7) return; + + struct Structure s; + struct Command command; + int actual_width; + int format = img->format, i = 0; + + if(format != Format_Mono && format != Format_MonoAlpha) return; + getStructure(img, &s); + + //--- + // Adjusting the bounding rectangle. + //--- + + // This is what happens when the bounding rectangle overflows from the + // image... + if(left < 0) left = 0; + if(top < 0) top = 0; + if(left + width > s.width) width = s.width - left; + if(top + height > s.height) height = s.height - top; + + if(x + left + width <= 0 || x > 127 || y + top + height <= 0 || y > 63) + return; + + command.top = (y < 0) ? (top - y) : top; + command.bottom = top + ((y + height > 64) ? (64 - y) : height); + command.left = ((x < 0) ? (left - x) : left) >> 5; + actual_width = (x + width > 128) ? (128 - x) : width; + command.right = ((left + actual_width + 31) >> 5) - 1; + + command.op = bopti_op_mono; + + if(x >= 0) getMasks(x, x + actual_width - 1, command.masks); + else getMasks(0, actual_width + x - 1, command.masks); + + bopti_vram = display_getCurrentVRAM(); + + while(format) + { + if(format & 1) + { + command.x = x - left; + command.y = y - top; + command.channel = (1 << i); + + bopti(s.data, &s, &command); + s.data += s.layer_size; + } + + format >>= 1; + i++; + } +} diff --git a/src/p7os/cake.exe/libgint/src/bopti/gimage.c b/src/p7os/cake.exe/libgint/src/bopti/gimage.c new file mode 100644 index 0000000..4f8371e --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/bopti/gimage.c @@ -0,0 +1,57 @@ +#include +#include +#include + +/* + gimage() + Displays a gray image in the video ram. +*/ +void gimage(int x, int y, struct Image *img) +{ + if(!img || img->magic != 0xb7) return; + + struct Structure s; + struct Command command; + int actual_width; + int format = img->format, i = 0; + + getStructure(img, &s); + + //--- + // Adjusting image parameters. + //--- + + if(x + s.width <= 0 || x > 127 || y + s.height <= 0 || y > 63) return; + + command.top = (y < 0) ? (-y) : (0); + command.bottom = (y + s.height > 64) ? (64 - y) : (s.height); + command.left = ((x < 0) ? (-x) : (0)) >> 5; + actual_width = (x + s.width > 128) ? (128 - x) : (s.width); + command.right = ((actual_width + 31) >> 5) - 1; + + command.op = bopti_op_gray; + + if(x >= 0) getMasks(x, x + actual_width - 1, command.masks); + else getMasks(0, actual_width + x - 1, command.masks); + + bopti_v1 = gray_lightVRAM(); + bopti_v2 = gray_darkVRAM(); + + while(format) + { + // Drawing every layer, in order of formats. + if(format & 1) + { + // These members are modified by bopti()! + command.x = x; + command.y = y; + command.channel = (1 << i); + + bopti(s.data, &s, &command); + s.data += s.layer_size; + } + + format >>= 1; + i++; + } +} diff --git a/src/p7os/cake.exe/libgint/src/bopti/gimage_part.c b/src/p7os/cake.exe/libgint/src/bopti/gimage_part.c new file mode 100644 index 0000000..744a7c2 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/bopti/gimage_part.c @@ -0,0 +1,85 @@ +#include +#include +#include + +/* +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +struct Rect +{ + int top, bottom; + int left, right; +}; +struct Rect intersect(struct Rect r1, struct Rect r2) +{ + struct Rect result; + result.top = max(r1.top, r2.top); + result.bottom = min(r1.bottom, r2.bottom); + result.left = max(r1.left, r2.left); + result.right = min(r1.right, r2.right); +} +*/ + +/* + gimage_part() + Draws a portion of a gray image, defined by its bounding rectangle. + Point (left, top) is included, but (left + width, top + height) is + excluded. +*/ +void gimage_part(int x, int y, struct Image *img, int left, int top, + int width, int height) +{ + if(!img || img->magic != 0xb7) return; + + struct Structure s; + struct Command command; + int actual_width; + int format = img->format, i = 0; + + getStructure(img, &s); + + //--- + // Adjusting the bounding rectangle. + //--- + + // This is what happens when the bounding rectangle overflows from the + // image... + if(left < 0) left = 0; + if(top < 0) top = 0; + if(left + width > s.width) width = s.width - left; + if(top + height > s.height) height = s.height - top; + + if(x + left + width <= 0 || x > 127 || y + top + height <= 0 || y > 63) + return; + + command.top = (y < 0) ? (top - y) : top; + command.bottom = top + ((y + height > 64) ? (64 - y) : height); + command.left = ((x < 0) ? (left - x) : left) >> 5; + actual_width = (x + width > 128) ? (128 - x) : width; + command.right = ((left + actual_width + 31) >> 5) - 1; + + command.op = bopti_op_gray; + + if(x >= 0) getMasks(x, x + actual_width - 1, command.masks); + else getMasks(0, actual_width + x - 1, command.masks); + + bopti_v1 = gray_lightVRAM(); + bopti_v2 = gray_darkVRAM(); + + while(format) + { + if(format & 1) + { + command.x = x - left; + command.y = y - top; + command.channel = (1 << i); + + bopti(s.data, &s, &command); + s.data += s.layer_size; + } + + format >>= 1; + i++; + } +} diff --git a/src/p7os/cake.exe/libgint/src/clock/clock.c b/src/p7os/cake.exe/libgint/src/clock/clock.c new file mode 100644 index 0000000..bc16418 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/clock/clock.c @@ -0,0 +1,288 @@ +#include +#include +#include +#include +#include +#include + +static struct ClockConfig conf = { + .FLL = -1, .PLL = -1, + .Bphi_div1 = -1, .Iphi_div1 = -1, .Pphi_div1 = -1, + .CKIO_f = -1, + .Bphi_f = -1, .Iphi_f = -1, .Pphi_f = -1 +}; + +/* + clock_frequency() + Returns the approximate frequency, in Hz, of the given clock. The + measurements need to have been done. Returns a negative number on + error. +*/ +int clock_frequency(enum Clock clock) +{ + switch(clock) + { + case Clock_CKIO: + return conf.CKIO_f; + case Clock_RTCCLK: + return conf.RTCCLK_f; + case Clock_Bphi: + return conf.Bphi_f; + case Clock_Iphi: + return conf.Iphi_f; + case Clock_Pphi: + return conf.Pphi_f; + + default: + return -2; + } +} + +/* + clock_setting() + Returns the P_phi / 4 timer setting that will last for the given time. + Several units can be used. Be aware that the result is approximate, and + very high frequencies or very short delays will yield important errors. +*/ +int clock_setting(int duration, enum ClockUnit unit) +{ + if(conf.Pphi_f <= 0) return -1; + int f = conf.Pphi_f >> 2; + + switch(unit) + { + case Clock_us: + return (duration * f) / 1000000; + case Clock_ms: + return (duration * f) / 1000; + case Clock_s: + return (duration * f); + + case Clock_Hz: + return f / duration; + case Clock_kHz: + return f / (duration * 1000); + case Clock_MHz: + return f / (duration * 1000000); + + default: + return -1; + } +} + +/* + clock_config() + Returns a copy of the clock configuration. +*/ +struct ClockConfig clock_config(void) +{ + return conf; +} + +/* + sleep() + Sleeps until an interrupt is accepted. +*/ +void sleep(void) +{ + __asm__( + "sleep\n\t" + ); +} + +/* + sleep_us() + Sleeps for the given number of us using the user timer. The result will + always be slightly less than required. +*/ + +static volatile int sleep_us_done = 0; + +static void sleep_us_callback(void) +{ + sleep_us_done = 1; +} + +void sleep_us(int us_delay) +{ + sleep_us_done = 0; + timer_start(TIMER_USER, clock_setting(us_delay, Clock_us), TIMER_Po_4, + sleep_us_callback, 1); + do sleep(); + while(!sleep_us_done); +} + + + +//--- +// Clock frequency measurements -- Public API. +//--- + +// Indicates whether the measurements are finished. +static volatile int clock_measure_done = 0; +// Once again SH7705 and SH7305 need different methods... +static int cb_id_7705 = -1; +static void clock_measure_7705(); +static void clock_compute_7305(); + +/* + clock_measure() + Measures or computes the clock frequencies. +*/ +void clock_measure(void) +{ + // On SH7705 we cannot have the value of CKIO simply, so we measure + // P_phi using a timer/RTC combination, and we deduce CKIO. + if(isSH3()) + { + // We prepare the timer manually, without starting it, so that + // we only have to push the running bit to start it when the + // measurements begin. This might look of little effect but it + // makes the precision jump from ~97% to more than 99%. + volatile struct mod_tmu *tmu; + timer_get(TIMER_USER, &tmu, NULL); + + tmu->TCOR = 0xffffffff; + tmu->TCNT = tmu->TCOR; + tmu->TCR.TPSC = TIMER_Po_4; + + tmu->TCR.UNF = 0; + tmu->TCR.UNIE = 1; + tmu->TCR.CKEG = 0; + + timers[TIMER_USER].callback = NULL; + timers[TIMER_USER].repeats = 0; + + cb_id_7705 = rtc_cb_add(RTCFreq_256Hz, clock_measure_7705, 0); + } + + // On SH7305, assuming clock mode 3, we can compute the clock + // frequencies because we know that RTC_CLK oscillates at 32768 Hz. + else + { + clock_compute_7305(); + clock_measure_done = 1; + } +} + +/* + clock_measure_end() + Waits until the measurements are finished. This may be immediate. +*/ +void clock_measure_end(void) +{ + while(!clock_measure_done) sleep(); +} + +//--- +// Clock frequency measurements -- SH7305. +//--- + +/* + clock_compute_7305() + Computes the clock frequencies according to the CPG parameters. +*/ +static void clock_compute_7305(void) +{ + volatile unsigned int *FRQCRA = (void *)0xa4150000; + volatile unsigned int *PLLCR = (void *)0xa4150024; + volatile unsigned int *FLLFRQ = (void *)0xa4150050; + + // Surely the documentation of SH7724 does not meet the specification + // of SH7305 for the PLL setting, because the register accepts other + // values than the ones specified for SH7724. The relation given by + // Sentaro21 (thanks again!) yields good results. + int pll = (*FRQCRA >> 24) & 0x3f; // Raw setting + pll = pll + 1; // Resulting multiplier + conf.PLL = pll; + + // This one is simpler. The FLL ratio is actually the setting value. + int fll = *FLLFRQ & 0x7ff; // Raw setting = multiplier + if(*FLLFRQ & (1 << 14)) fll >>= 1; // Halve-output flag + conf.FLL = fll; + + // The divider1 ratios are NOT those of SH7724. The relation between + // the values below and the divider ratios is given by Sentaro21 + // (thanks to him!) and satisfies ratio = 1 / (2 ** (setting + 1)). + int div1_bphi = (*FRQCRA >> 8) & 0xf; + int div1_iphi = (*FRQCRA >> 20) & 0xf; + int div1_pphi = (*FRQCRA ) & 0xf; + + conf.Bphi_div1 = 1 << (div1_bphi + 1); + conf.Iphi_div1 = 1 << (div1_iphi + 1); + conf.Pphi_div1 = 1 << (div1_pphi + 1); + + // Computing the frequency of the signal, which is input to divider 1. + int base = 32768; + if(*PLLCR & (1 << 12)) base *= fll; + if(*PLLCR & (1 << 14)) base *= pll; + + conf.RTCCLK_f = 32768; + conf.Bphi_f = base >> (div1_bphi + 1); + conf.Iphi_f = base >> (div1_iphi + 1); + conf.Pphi_f = base >> (div1_pphi + 1); +} + +//--- +// Clock frequency measurements -- SH7705. +//--- + +/* + clock_measure_7705_finalize() + Given the number of P_phi / 4 timer ticks elapsed between two RTC + 256 Hz interrupts, determines the clock configuration. +*/ +static void clock_measure_7705_finalize(int elapsed) +{ + volatile unsigned int *FRQCR = (void *)0xffffff80; + + conf.Pphi_f = elapsed * 4 * 256; + if(conf.Pphi_f <= 0) return; + + conf.PLL1 = ((*FRQCR >> 8) & 0x03) + 1; + conf.PLL2 = -1; + + conf.Bphi_div1 = 0; + conf.Iphi_div1 = ((*FRQCR >> 4) & 0x03) + 1; + conf.Pphi_div1 = ((*FRQCR ) & 0x03) + 1; + + conf.CKIO_f = (conf.Pphi_f * conf.Pphi_div1) / conf.PLL1; + conf.Bphi_f = conf.CKIO_f; + conf.Iphi_f = (conf.CKIO_f * conf.PLL1) / conf.Iphi_div1; +} + +/* + clock_measure_7705_callback() + Starts measurements. Measurements will end automatically. Do not use + RTC interrupt or the user timer will doing measurements. + Call clock_measure_end() when you need to use those, to ensure + measurements are finished. +*/ +static void clock_measure_7705_callback(void) +{ + timer_stop(TIMER_USER); + rtc_cb_end(cb_id_7705); + + volatile struct mod_tmu *tmu; + timer_get(TIMER_USER, &tmu, NULL); + int elapsed = 0xffffffff - tmu->TCNT; + + clock_measure_7705_finalize(elapsed); + clock_measure_done = 1; +} + +/* + clock_measure_7705() + Programs the clock measurements. We need to have the user timer and the + RTC synchronized for this operation, so we wait for an RTC interrupt + and we prepare the timer beforehand to avoid losing processor time in + configuring the registers. +*/ +static void clock_measure_7705(void) +{ + volatile unsigned char *tstr; + timer_get(TIMER_USER, NULL, &tstr); + + *tstr |= (1 << TIMER_USER); + rtc_cb_edit(cb_id_7705, RTCFreq_256Hz, clock_measure_7705_callback); +} diff --git a/src/p7os/cake.exe/libgint/src/core/crt0.c b/src/p7os/cake.exe/libgint/src/core/crt0.c new file mode 100644 index 0000000..d22de28 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/core/crt0.c @@ -0,0 +1,168 @@ +#include +#include +#include + +#include +#include +#include + +int main(void); + +static void init(void); +static void fini(void); + +// Symbols imported from the linker script. +extern unsigned int + romdata, + bbss, ebss, + bdata, edata; + +// This variable should be overwritten before being returned, so the default +// value doesn't matter much. +static int exit_code = EXIT_SUCCESS; +static jmp_buf env; + +// Exit handlers. +void (*atexit_handlers[ATEXIT_MAX])(void); +int atexit_index = 0; + + + +/* + start() + Program entry point. Loads the data section into the memory and invokes + main(). Also prepares the execution environment by initializing all the + modules. +*/ + +int start(void) + __attribute__(( + section(".pretext.entry") + )); + +int start(void) +{ + // Linker symbols. + unsigned int *bss = &bbss; + unsigned int *data = &bdata, *src = &romdata; + int x; + + // Clearing the .bss section. + while(bss < &ebss) *bss++ = 0; + // Copying the .data section. + while(data < &edata) *data++ = *src++; + + mmu_pseudoTLBInit(); + + // Initializing gint. + gint_init(); + + // Measure clock frequencies. + clock_measure(); + clock_measure_end(); + + // Calling global constructors. + init(); + + + + // Saving the execution state there. + x = setjmp(env); + // If the program has just started, executing main(). Otherwise, the + // exit code has already been set by abort() or similar. + if(!x) exit_code = main(); + + + + // Remember to flush and close opened streams. + + // Calling exit handlers. + while(atexit_index > 0) (*atexit_handlers[--atexit_index])(); + + // Un-initializing everything. + fini(); + gint_quit(); + + return exit_code; +} + +/* + init() + Calls the constructors. +*/ +static void init(void) +{ + extern void + (*bctors)(void), + (*ectors)(void); + void (**func)(void) = &bctors; + + while(func < &ectors) + { + (*(*func))(); + func++; + } +} + +/* + fini() + Calls the destructors. +*/ +static void fini(void) +{ + extern void + (*bdtors)(void), + (*edtors)(void); + void (**func)(void) = &bdtors; + + while(func < &edtors) + { + (*(*func))(); + func++; + } +} + + + +/* + abort() + Immediately ends the program without invoking the exit handlers. +*/ +void abort(void) +{ + exit_code = EXIT_FAILURE; + + // Avoiding any exit handler call. + atexit_index = 0; + + longjmp(env, 1); +} + +/* + exit() + Ends the program and returns the given exit code status. Calls exit + handlers before returning. + Usually exit() would ask the operating system to stop the process but + the fx-9860G executes only one program at a time and calls it as a + function. Reaching the program end point is therefore an efficient way + of achieving this goal while minimizing interaction with the operating + system. +*/ +void exit(int status) +{ + exit_code = status; + longjmp(env, 1); +} + +/* + atexit() + Registers a function to be called at normal program termination. +*/ +int atexit(void (*function)(void)) +{ + if(atexit_index >= ATEXIT_MAX) return 1; + + atexit_handlers[atexit_index++] = function; + return 0; +} + diff --git a/src/p7os/cake.exe/libgint/src/core/gint.c b/src/p7os/cake.exe/libgint/src/core/gint.c new file mode 100644 index 0000000..28de9f2 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/core/gint.c @@ -0,0 +1,285 @@ +//--- +// +// gint core module: interrupt handler +// +// Central point of the library. Controls the interrupt handler and +// defines a few functions to configure callbacks for some interrupts. +// +//--- + +#include +#include +#include +#include + +static unsigned int + new_vbr, + sys_vbr; + +static void (*default_handler)(int event_code) = NULL; + + + +//--- +// Local functions. +//--- + +/* + gint_setup() + Configures interrupt priorities and some parameters to allow gint to + take control of the interrupt flow. +*/ +static void gint_setup(void) +{ + if(isSH3()) + gint_setup_7705(); + else + gint_setup_7305(); +} + +/* + gint_stop() + Un-configures the interrupt flow to give back the interrupt control to + the system. +*/ +static void gint_stop(void) +{ + if(isSH3()) + gint_stop_7705(); + else + gint_stop_7305(); +} + + + +//--- +// Public API. +//--- + +/* + gint_systemVBR() + Returns the vbr address used by the system (saved when execution + starts). +*/ +inline unsigned int gint_systemVBR(void) +{ + return sys_vbr; +} + +/* + gint_setDefaultHandler() + In case gint receives an interrupt it doesn't recognize, it can fall + back to a user-provided interrupt handler. Set it to NULL to disable + this feature. + Be aware that the event code passed to the default handler will either + be INTEVT2 (SH7705) or INTEVT (SH7305), but its value for each + interrupt case is completely platform-dependent. Remember to handle + both platforms for increased portability, if possible. +*/ +void gint_setDefaultHandler(void (*new_handler)(int event_code)) +{ + default_handler = new_handler; +} + +/* + gint_init() + Initializes gint. Loads the interrupt handler into the memory and sets + the new vbr address. +*/ +void gint_init(void) +{ + // Linker script symbols -- gint. + extern unsigned int + gint_vbr, + gint_data, + bgint, egint; + + unsigned int *ptr = &bgint; + unsigned int *src = &gint_data; + + // This initialization routine is usually called before any + // constructor. We want to ensure that the MPU type is detected, but + // mpu_init() hasn't been called yet. + mpu_init(); + + // Loading the interrupt handler into the memory. + while(ptr < &egint) *ptr++ = *src++; + + sys_vbr = gint_getVBR(); + new_vbr = (unsigned int)&gint_vbr; + + gint_setVBR(new_vbr, gint_setup); +} + +/* + gint_quit() + Stops gint. Restores the system's configuration and vbr address. +*/ +void gint_quit(void) +{ + gint_setVBR(sys_vbr, gint_stop); +} + + + +//--- +// VBR space. +//--- + +#include +#define print(str, x, y) dtext(6 * (x) - 5, 8 * (y) - 7, str) +#define hexdigit(n) ((n) + '0' + 39 * ((n) > 9)) + +static void hex(unsigned int x, int digits, char *str) +{ + str[0] = '0'; + str[1] = 'x'; + str[digits + 2] = 0; + + while(digits) + { + str[digits + 1] = hexdigit(x & 0xf); + x >>= 4; + digits--; + } +} + +static void reverse(void) +{ + int *vram = display_getCurrentVRAM(); + int i; + for(i = 0; i < 36; i++) vram[i] = ~vram[i]; +} + +/* + gint_exc() + Handles exceptions. +*/ +void gint_exc(void) +{ + volatile unsigned int *expevt = gint_reg(Register_EXPEVT); + volatile unsigned int *tea = gint_reg(Register_TEA); + unsigned int spc; + char str[11]; + + text_configure(NULL, Color_Black); + + __asm__("\tstc spc, %0" : "=r"(spc)); + + dclear(); + print("Exception raised!", 3, 1); + reverse(); + print(gint_strerror(0), 2, 3); + + print("expevt", 2, 4); + hex(*expevt, 3, str); + print(str, 16, 4); + + print("pc", 2, 5); + hex(spc, 8, str); + print(str, 11, 5); + + print("tea", 2, 6); + hex(*tea, 8, str); + print(str, 11, 6); + + print("Please reset.", 2, 7); + dupdate(); + while(1); +} + +/* + gint_tlb() + Handles TLB misses. +*/ +void gint_tlb(void) +{ + volatile unsigned int *expevt = gint_reg(Register_EXPEVT); + volatile unsigned int *tea = gint_reg(Register_TEA); + unsigned int spc; + char str[11]; + + text_configure(NULL, Color_Black); + + __asm__("\tstc spc, %0" : "=r"(spc)); + + dclear(); + print("TLB error!", 6, 1); + reverse(); + print(gint_strerror(1), 2, 3); + + print("expevt", 2, 4); + hex(*expevt, 3, str); + print(str, 16, 4); + + print("pc", 2, 5); + hex(spc, 8, str); + print(str, 11, 5); + + print("tea", 2, 6); + hex(*tea, 8, str); + print(str, 11, 6); + + print("Please reset.", 2, 7); + dupdate(); + while(1); +} + +/* + gint_int() + Handles interrupts. +*/ +void gint_int(void) +{ + if(isSH3()) + gint_int_7705(); + else + gint_int_7305(); +} + + + +//--- +// Internal API. +//--- + +/* + gint_callDefaultHandler() + Calls the user-provided default interrupt handler. +*/ +void gint_callDefaultHandler(int event_code) +{ + if(default_handler) default_handler(event_code); +} + +/* + gint_reg() + Returns the address of a common register. All common registers exist + on both platforms but they may hold different values for the same + information (f.i. EXPEVT may not return the same value for a given + exception on both 7705 and 7305). +*/ +inline volatile void *gint_reg(enum Register reg) +{ + if(isSH3()) + return gint_reg_7705(reg); + else + return gint_reg_7305(reg); +} + +/* + gint_strerror() + Returns a string that describe the error set in EXPEVT. This string is + not platform-dependent. + Some exception codes represent different errors when invoked inside the + general exception handler and the TLB error handler. Parameter 'is_tlb' + should be set to zero for general exception meanings, and anything non- + zero for TLB error meanings. +*/ +const char *gint_strerror(int is_tlb) +{ + if(isSH3()) + return gint_strerror_7705(is_tlb); + else + return gint_strerror_7305(); +} diff --git a/src/p7os/cake.exe/libgint/src/core/gint_str.c b/src/p7os/cake.exe/libgint/src/core/gint_str.c new file mode 100644 index 0000000..c7e9957 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/core/gint_str.c @@ -0,0 +1,37 @@ +#include + +const char *gint_str[] = { + "Unknown", + + // User breaks. + "User break (before)", + "User break (after)", + "User breakpoint", + + // General. + "Inst. address error", + "Data access error", + "Illegal instruction", + "Illegal slot", + "Data address (r)", + "Data address (w)", + + // Instruction TLB. + "Inst. TLB miss", + "Inst. TLB invalid", + "Inst. TLB protect.", + + // Data TLB. + "Data TLB miss", + "Data TLB miss (r)", + "Data TLB miss (w)", + "Data TLB protection", + "Data TLB prot. (r)", + "Data TLB prot. (w)", + "Data TLB invalid", + + // Others. + "Initial page write", + "Trap", + "DMA address error", +}; diff --git a/src/p7os/cake.exe/libgint/src/core/gint_vbr.s b/src/p7os/cake.exe/libgint/src/core/gint_vbr.s new file mode 100644 index 0000000..488be1b --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/core/gint_vbr.s @@ -0,0 +1,66 @@ +/* + gint_vbr + + Some of the work, especially related to setting and un-setting the vbr + address needs to be done in assembler. +*/ + + .global _gint_getVBR + .global _gint_setVBR + + + +/* + gint_getVBR() + Returns the current vbr address. +*/ +_gint_getVBR: + rts + stc vbr, r0 + + + +/* + gint_setVBR() + + This is quite the hard part when modifying the vbr. We need to set + immediately the interrupt priorities of our own handler, or restore + the ones used by the system ; otherwise we may receive interrupts + requests that the new handler doesn't handle, which will cause the + whole program to freeze. + + Therefore, we must set vbr *and* change interrupt priorities while + having disabled all the interrupts in the status register. That's why + this function takes as parameter the priority management function. +*/ +_gint_setVBR: + sts.l pr, @-r15 + + /* Blocking all interrupts. */ + mov.l sr_block, r0 + stc sr, r3 + or r0, r3 + ldc r3, sr + + /* Setting the vbr address. */ + ldc r4, vbr + + /* Calling the priority manager. */ + jsr @r5 + nop + + /* Activating interrupts again. */ + mov.l sr_block, r0 + not r0, r0 + stc sr, r3 + and r0, r3 + ldc r3, sr + + lds.l @r15+, pr + rts + nop + + .align 4 + +sr_block: + .long (1 << 28) diff --git a/src/p7os/cake.exe/libgint/src/core/syscalls.s b/src/p7os/cake.exe/libgint/src/core/syscalls.s new file mode 100644 index 0000000..e4dd817 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/core/syscalls.s @@ -0,0 +1,41 @@ +/* + gint core module: syscalls + + All the system calls used by the library. Somehow "the less, the + better". + We have finally gotten rid of every obscure system-related syscalls! + Looks like an important step towards being completely free-standing :) +*/ + + .global ___malloc + .global ___free + .global ___realloc + + + +___malloc: + mov.l syscall_table, r2 + mov.l 1f, r0 + jmp @r2 + nop +1: .long 0xacd + +___free: + mov.l syscall_table, r2 + mov.l 1f, r0 + jmp @r2 + nop +1: .long 0xacc + +___realloc: + mov.l syscall_table, r2 + mov.l 1f, r0 + jmp @r2 + nop +1: .long 0xe6d + + + .align 4 + +syscall_table: + .long 0x80010070 diff --git a/src/p7os/cake.exe/libgint/src/display/adjustRectangle.c b/src/p7os/cake.exe/libgint/src/display/adjustRectangle.c new file mode 100644 index 0000000..f46f9b2 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/display/adjustRectangle.c @@ -0,0 +1,29 @@ +#include + +/* + adjustRectangle() + Adjusts the given rectangle coordinates to ensure that : + - the rectangle is entirely contained in the screen + - x1 < x2 + - y1 < y2 + which is needed when working with screen rectangles. + Returns non-zero if the rectangle is outside the screen. +*/ +int adjustRectangle(int *x1, int *y1, int *x2, int *y2) +{ + #define swap(a, b) tmp = a, a = b, b = tmp + int tmp; + + if(*x2 < *x1) swap(*x1, *x2); + if(*y2 < *y1) swap(*y1, *y2); + + if(*x1 > 127 || *y1 > 63 || *x2 < 0 || *y2 < 0) return 1; + + if(*x1 < 0) *x1 = 0; + if(*y1 < 0) *y1 = 0; + if(*x2 > 127) *x2 = 127; + if(*y2 > 63) *y2 = 63; + + return 0; + #undef swap +} diff --git a/src/p7os/cake.exe/libgint/src/display/dclear.c b/src/p7os/cake.exe/libgint/src/display/dclear.c new file mode 100644 index 0000000..ed45a6d --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/display/dclear.c @@ -0,0 +1,12 @@ +#include +#include + +/* + dclear() + Clears the whole vram. +*/ +void dclear(void) +{ + int i; + for(i = 0; i < 256; i++) vram[i] = 0; +} diff --git a/src/p7os/cake.exe/libgint/src/display/dclear_area.c b/src/p7os/cake.exe/libgint/src/display/dclear_area.c new file mode 100644 index 0000000..4cb4a70 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/display/dclear_area.c @@ -0,0 +1,21 @@ +#include +#include + +/* + dclear_area() + Clears an area of the vram using rectangle masks. Both (x1, y1) and + (x2, y2) are cleared. +*/ +void dclear_area(int x1, int y1, int x2, int y2) +{ + uint32_t masks[4]; + if(adjustRectangle(&x1, &y1, &x2, &y2)) return; + getMasks(x1, x2, masks); + + int begin = y1 << 2; + int end = (y2 + 1) << 2; + int i; + + for(i = 0; i < 4; i++) masks[i] = ~masks[i]; + for(i = begin; i < end; i++) vram[i] &= masks[i & 3]; +} diff --git a/src/p7os/cake.exe/libgint/src/display/display_vram.c b/src/p7os/cake.exe/libgint/src/display/display_vram.c new file mode 100644 index 0000000..2dc3763 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/display/display_vram.c @@ -0,0 +1,43 @@ +#include + +// Program video ram. It resides in .bss section, therefore it is cleared at +// program initialization and stripped from the executable file. +static int local_vram[256]; +int *vram = local_vram; + +/* + display_getLocalVRAM() + Returns the local video ram address. This function always return the + same address. + The buffer returned by this function should not be used directly when + running the gray engine. +*/ +inline void *display_getLocalVRAM(void) +{ + return (void *)local_vram; +} + +/* + display_getCurrentVRAM() + Returns the current video ram. This function usually returns the + parameter of the last call to display_useVRAM(), unless the gray engine + is running (in which case the result is undefined). Returns the local + vram address by default. +*/ +inline void *display_getCurrentVRAM(void) +{ + return (void *)vram; +} + +/* + display_useVRAM() + Changes the current video ram address. The argument MUST be a 4- + aligned 1024-byte buffer ; otherwise any drawing operation will crash + the program. + This function will most likely have no effect when running the gray + engine. +*/ +inline void display_useVRAM(void *ptr) +{ + vram = (int *)ptr; +} diff --git a/src/p7os/cake.exe/libgint/src/display/dline.c b/src/p7os/cake.exe/libgint/src/display/dline.c new file mode 100644 index 0000000..e6e1422 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/display/dline.c @@ -0,0 +1,116 @@ +#include +#include + +#define sgn(x) ((x) < 0 ? -1 : 1) +#define abs(x) ((x) < 0 ? -(x) : (x)) +#define rnd(x) ((int)((x) + 0.5)) + +/* + dline() + Draws a line on the screen. Automatically optimizes horizontal and + vertical lines. +*/ + +static void dhline(int x1, int x2, int y, enum Color color) +{ + uint32_t masks[4]; + int offset = y << 2; + int i; + + // Swapping x1 and x2 if needed. + if(x1 > x2) x1 ^= x2, x2 ^= x1, x1 ^= x2; + getMasks(x1, x2, masks); + + switch(color) + { + case Color_White: + for(i = 0; i < 4; i++) vram[offset + i] &= ~masks[i]; + break; + + case Color_Black: + for(i = 0; i < 4; i++) vram[offset + i] |= masks[i]; + break; + + case Color_Invert: + for(i = 0; i < 4; i++) vram[offset + i] ^= masks[i]; + break; + + default: + break; + } +} + +static void dvline(int y1, int y2, int x, enum Color color) +{ + int offset = (y1 << 2) + (x >> 5); + int end = (y2 << 2) + (x >> 5); + int mask = 0x80000000 >> (x & 31); + + switch(color) + { + case Color_White: + while(offset <= end) vram[offset] &= ~mask, offset += 4; + break; + + case Color_Black: + while(offset <= end) vram[offset] |= mask, offset += 4; + break; + + case Color_Invert: + while(offset <= end) vram[offset] ^= mask, offset += 4; + break; + + default: + break; + } +} + +void dline(int x1, int y1, int x2, int y2, enum Color color) +{ + if(adjustRectangle(&x1, &y1, &x2, &y2)) return; + + // Possible optimizations. + if(y1 == y2) + { + dhline(x1, x2, y1, color); + return; + } + if(x1 == x2) + { + dvline(y1, y2, x1, color); + return; + } + + int i, x = x1, y = y1, cumul; + int dx = x2 - x1, dy = y2 - y1; + int sx = sgn(dx), sy = sgn(dy); + + dx = abs(dx), dy = abs(dy); + + dpixel(x1, y1, color); + + if(dx >= dy) + { + cumul = dx >> 1; + for(i = 1; i < dx; i++) + { + x += sx; + cumul += dy; + if(cumul > dx) cumul -= dx, y += sy; + dpixel(x, y, color); + } + } + else + { + cumul = dy >> 1; + for(i = 1; i < dy; i++) + { + y += sy; + cumul += dx; + if(cumul > dy) cumul -= dy, x += sx; + dpixel(x, y, color); + } + } + + dpixel(x2, y2, color); +} diff --git a/src/p7os/cake.exe/libgint/src/display/dpixel.c b/src/p7os/cake.exe/libgint/src/display/dpixel.c new file mode 100644 index 0000000..60c3a06 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/display/dpixel.c @@ -0,0 +1,32 @@ +#include +#include + +/* + dpixel() + Puts a pixel in the vram. +*/ +void dpixel(int x, int y, enum Color color) +{ + if((unsigned int)x > 127 || (unsigned int)y > 63) return; + + int offset = (y << 2) + (x >> 5); + int mask = 0x80000000 >> (x & 31); + + switch(color) + { + case Color_White: + vram[offset] &= ~mask; + break; + + case Color_Black: + vram[offset] |= mask; + break; + + case Color_Invert: + vram[offset] ^= mask; + break; + + default: + break; + } +} diff --git a/src/p7os/cake.exe/libgint/src/display/dreverse_area.c b/src/p7os/cake.exe/libgint/src/display/dreverse_area.c new file mode 100644 index 0000000..0288cbe --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/display/dreverse_area.c @@ -0,0 +1,21 @@ +#include +#include + +/* + dreverse_area() + Reverses an area of the vram. This function is a simple application of + the rectangle masks concept. (x1, y1) and (x2, y2) are reversed as + well. +*/ +void dreverse_area(int x1, int y1, int x2, int y2) +{ + uint32_t masks[4]; + if(adjustRectangle(&x1, &y1, &x2, &y2)) return; + getMasks(x1, x2, masks); + + int begin = y1 << 2; + int end = (y2 + 1) << 2; + int i; + + for(i = begin; i < end; i++) vram[i] ^= masks[i & 3]; +} diff --git a/src/p7os/cake.exe/libgint/src/display/dupdate.c b/src/p7os/cake.exe/libgint/src/display/dupdate.c new file mode 100644 index 0000000..6ca42f8 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/display/dupdate.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +/* + dupdate() + Displays the vram on the physical screen. +*/ +void dupdate(void) +{ + if(gray_runs()) return; + screen_display((const void *)vram); +} diff --git a/src/p7os/cake.exe/libgint/src/display/font_system.bmp b/src/p7os/cake.exe/libgint/src/display/font_system.bmp new file mode 100644 index 0000000..cee82be Binary files /dev/null and b/src/p7os/cake.exe/libgint/src/display/font_system.bmp differ diff --git a/src/p7os/cake.exe/libgint/src/display/getMasks.c b/src/p7os/cake.exe/libgint/src/display/getMasks.c new file mode 100644 index 0000000..6f3091c --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/display/getMasks.c @@ -0,0 +1,33 @@ +#include + +/* + getMasks() + Computes the rectangle masks needed to affect pixels located between x1 + and x2 (both included). The four masks are stored in the third argument + (seen as an array). +*/ +void getMasks(int x1, int x2, uint32_t *masks) +{ + // Indexes of the first and last longs that are non-blank. + int l1 = x1 >> 5; + int l2 = x2 >> 5; + int i = 0; + + // Setting the base masks. Those are the final values, except for the + // longs with indexes l1 and l2, that still need to be adjusted. + while(i < l1) masks[i++] = 0x00000000; + while(i <= l2) masks[i++] = 0xffffffff; + while(i < 4) masks[i++] = 0x00000000; + + // Removing the long number information in x1 and x2 (that is, the + // multiples of 32) to keep only the interesting information -- the + // number of null bits to add in l1 and l2. + x1 &= 31; + // Inverting x2 is here the same as computing 32 - x, since 32 is a + // power of 2 (positive bits at the left are removed by the mask). + x2 = ~x2 & 31; + + // Setting the first and last masks. + masks[l1] &= (0xffffffff >> x1); + masks[l2] &= (0xffffffff << x2); +} diff --git a/src/p7os/cake.exe/libgint/src/events/event_get.c b/src/p7os/cake.exe/libgint/src/events/event_get.c new file mode 100644 index 0000000..eceb1ff --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/events/event_get.c @@ -0,0 +1,38 @@ +#include +#include +#include + +/* + pollevent() + Returns the next event. If no one is available, returns an event whose + type is ET_None. This function always returns immediately. +*/ +struct Event pollevent(void) +{ + struct Event event = { + .type = ET_None + }; + if(queue_size <= 0) return event; + + event = event_queue[queue_start]; + + queue_size--; + if(queue_start == EVENTS_QUEUE_SIZE - 1) queue_start = 0; + else queue_start++; + + return event; +} + +/* + getevent() + Returns the next event. If no one is available, waits for something to + happen. This function uses low-level sleep and should be preferred to + active waiting using loops. +*/ +struct Event getevent(void) +{ + struct Event event; + + while((event = pollevent()).type == ET_None) sleep(); + return event; +} diff --git a/src/p7os/cake.exe/libgint/src/events/event_push.c b/src/p7os/cake.exe/libgint/src/events/event_push.c new file mode 100644 index 0000000..3c47d09 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/events/event_push.c @@ -0,0 +1,26 @@ +#include +#include + +volatile struct Event event_queue[EVENTS_QUEUE_SIZE]; +volatile int queue_start = 0; +volatile int queue_size = 0; + +/* + event_push() + Queues a user-defined event, allowing it to be retrieved by getevent() + or pollevent() later. Pushing ET_None events is not allowed. + Returns non-zero on error. +*/ +int event_push(struct Event event) +{ + if(queue_size >= EVENTS_QUEUE_SIZE) return 1; + if(event.type == ET_None) return 2; + + int index = queue_start + queue_size; + if(index >= EVENTS_QUEUE_SIZE) index -= EVENTS_QUEUE_SIZE; + + event_queue[index] = event; + queue_size++; + + return 0; +} diff --git a/src/p7os/cake.exe/libgint/src/gray/gclear.c b/src/p7os/cake.exe/libgint/src/gray/gclear.c new file mode 100644 index 0000000..e3beb21 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/gray/gclear.c @@ -0,0 +1,14 @@ +#include + +/* + gclear() + Clears the video ram. +*/ +void gclear(void) +{ + int *v1 = gray_lightVRAM(); + int *v2 = gray_darkVRAM(); + int i; + + for(i = 0; i < 256; i++) v1[i] = v2[i] = 0; +} diff --git a/src/p7os/cake.exe/libgint/src/gray/gclear_area.c b/src/p7os/cake.exe/libgint/src/gray/gclear_area.c new file mode 100644 index 0000000..42c3f29 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/gray/gclear_area.c @@ -0,0 +1,15 @@ +#include +#include + +/* + gclear_area() + Clears an area of the video ram. End points (x1, y1) and (x2, y2) are + included. +*/ +void gclear_area(int x1, int y1, int x2, int y2) +{ + display_useVRAM(gray_lightVRAM()); + dclear_area(x1, y1, x2, y2); + display_useVRAM(gray_darkVRAM()); + dclear_area(x1, y1, x2, y2); +} diff --git a/src/p7os/cake.exe/libgint/src/gray/gline.c b/src/p7os/cake.exe/libgint/src/gray/gline.c new file mode 100644 index 0000000..9b31480 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/gray/gline.c @@ -0,0 +1,24 @@ +#include +#include + +/* + gline() + Draws a line in the vram. Automatically optimizes special cases. +*/ +void gline(int x1, int y1, int x2, int y2, enum Color color) +{ + enum Color c1, c2; + + if(color == Color_None) return; + else if(color == Color_Invert) c1 = c2 = Color_Invert; + else + { + c1 = 3 * (color & 1); + c2 = 3 * (color >> 1); + } + + display_useVRAM(gray_lightVRAM()); + dline(x1, y1, x2, y2, c1); + display_useVRAM(gray_darkVRAM()); + dline(x1, y1, x2, y2, c2); +} diff --git a/src/p7os/cake.exe/libgint/src/gray/gpixel.c b/src/p7os/cake.exe/libgint/src/gray/gpixel.c new file mode 100644 index 0000000..be44071 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/gray/gpixel.c @@ -0,0 +1,47 @@ +#include + +/* + gpixel() + Puts a pixel in the vram. +*/ +void gpixel(int x, int y, enum Color color) +{ + if((unsigned int)x > 127 || (unsigned int)y > 63) return; + + int offset = (y << 2) + (x >> 5); + int mask = 0x80000000 >> (x & 31); + + int *v1 = gray_lightVRAM(); + int *v2 = gray_lightVRAM(); + + switch(color) + { + case Color_White: + v1[offset] &= ~mask; + v2[offset] &= ~mask; + break; + + case Color_Light: + v1[offset] |= mask; + v2[offset] &= ~mask; + break; + + case Color_Dark: + v1[offset] &= ~mask; + v2[offset] |= mask; + break; + + case Color_Black: + v1[offset] |= mask; + v2[offset] |= mask; + break; + + case Color_Invert: + v1[offset] ^= mask; + v2[offset] ^= mask; + break; + + default: + break; + } +} diff --git a/src/p7os/cake.exe/libgint/src/gray/gray_engine.c b/src/p7os/cake.exe/libgint/src/gray/gray_engine.c new file mode 100644 index 0000000..639c750 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/gray/gray_engine.c @@ -0,0 +1,157 @@ +//--- +// +// gint core/drawing module: gray +// +// Runs the gray engine and handles drawing for the dual-buffer system. +// +//--- + +#include +#include +#include +#include + +static int internal_vrams[3][256]; +static const void *vrams[4]; + +static int current = 0; +static int delays[2]; + +static int runs = 0; + +#define GRAY_PRESCALER TIMER_Po_64 + + + +//--- +// Engine control. +//--- + +/* + gray_start() + Starts the gray engine. The control of the screen is transferred to the + gray engine. +*/ +void gray_start(void) +{ + if(runs) return; + + timer_start(TIMER_GRAY, delays[0], GRAY_PRESCALER, gray_interrupt, 0); + current &= 1; + runs = 1; +} + +/* + gray_stop() + Stops the gray engine. The monochrome display system takes control of + the video ram. +*/ +void gray_stop(void) +{ + if(!runs) return; + + timer_stop(TIMER_GRAY); + runs = 0; + + display_useVRAM(display_getLocalVRAM()); +} + +/* + gray_setDelays() + Changes the gray engine delays. +*/ +void gray_setDelays(int light, int dark) +{ + delays[0] = light; + delays[1] = dark; +} + + + +//--- +// Engine information. +//--- + +/* + gray_runs() + Returns 1 if the gray engine is running, 0 otherwise. +*/ +inline int gray_runs(void) +{ + return runs; +} + +/* + gray_lightVRAM() + Returns the module's gray vram address. +*/ +void *gray_lightVRAM(void) +{ + return (void *)vrams[~current & 2]; +} + +/* + gray_lightVRAM() + Returns the module's dark vram address. +*/ +void *gray_darkVRAM(void) +{ + return (void *)vrams[(~current & 2) | 1]; +} + +/* + gray_getDelays() + Returns the gray engine delays. Pointers are not set if NULL. +*/ +void gray_getDelays(int *light, int *dark) +{ + if(light) *light = delays[0]; + if(dark) *dark = delays[1]; +} + + + +//--- +// Drawing. +//--- + +/* + gupdate() + Swaps the vram buffer sets. +*/ +inline void gupdate(void) +{ + current ^= 2; +} + + + +//--- +// Interrupt control and initialization. +//--- + +/* + gray_interrupt() + Answers a timer interrupt. Swaps the buffers. +*/ +void gray_interrupt(void) +{ + timer_reload(TIMER_GRAY, delays[(~current) & 1]); + screen_display(vrams[current]); + current ^= 1; +} + +/* + gray_init() + Initializes the gray engine. +*/ +void gray_init(void) +{ + vrams[0] = (const void *)display_getLocalVRAM(); + vrams[1] = (const void *)internal_vrams[0]; + vrams[2] = (const void *)internal_vrams[1]; + vrams[3] = (const void *)internal_vrams[2]; + + delays[0] = 912; + delays[1] = 1343; +} diff --git a/src/p7os/cake.exe/libgint/src/gray/greverse_area.c b/src/p7os/cake.exe/libgint/src/gray/greverse_area.c new file mode 100644 index 0000000..7a3fccd --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/gray/greverse_area.c @@ -0,0 +1,15 @@ +#include +#include + +/* + greverse_area() + Reverses an area of the vram. End points (x1, y1) and (x2, y2) are + included. +*/ +void greverse_area(int x1, int y1, int x2, int y2) +{ + display_useVRAM(gray_lightVRAM()); + dreverse_area(x1, y1, x2, y2); + display_useVRAM(gray_darkVRAM()); + dreverse_area(x1, y1, x2, y2); +} diff --git a/src/p7os/cake.exe/libgint/src/keyboard/getPressedKey.c b/src/p7os/cake.exe/libgint/src/keyboard/getPressedKey.c new file mode 100644 index 0000000..ca8ba32 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/getPressedKey.c @@ -0,0 +1,24 @@ +#include + +/* + getPressedKey() + Finds a pressed key in the keyboard state and returns it. +*/ +int getPressedKey(volatile unsigned char *keyboard_state) +{ + int row = 1, column = 0; + int state; + if(keyboard_state[0] & 1) return KEY_AC_ON; + + while(row <= 9 && !keyboard_state[row]) row++; + if(row > 9) return KEY_NONE; + + state = keyboard_state[row]; + while(!(state & 1)) + { + state >>= 1; + column++; + } + + return (column << 4) | row; +} diff --git a/src/p7os/cake.exe/libgint/src/keyboard/getPressedKeys.c b/src/p7os/cake.exe/libgint/src/keyboard/getPressedKeys.c new file mode 100644 index 0000000..b6dd739 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/getPressedKeys.c @@ -0,0 +1,54 @@ +#include + +/* + getPressedKeys() + Find 'count' pressed keys in the keyboard state and fills the 'keys' + array. Returns the number of actually-pressed keys found. +*/ +int getPressedKeys(volatile unsigned char *keyboard_state, int *keys, + int count) +{ + int row = 1, column; + int found = 0, actually_pressed; + int state; + if(count <= 0) return 0; + + if(keyboard_state[0] & 1) + { + keys[found++] = KEY_AC_ON; + count--; + } + + while(count && row <= 9) + { + while(row <= 9 && !keyboard_state[row]) row++; + if(row > 9) break; + + state = keyboard_state[row]; + column = 0; + + while(count && column < 8) + { + if(state & 1) + { + keys[found++] = (column << 4) | row; + count--; + } + + state >>= 1; + column++; + } + + row++; + } + + actually_pressed = found; + + while(count) + { + keys[found++] = KEY_NONE; + count--; + } + + return actually_pressed; +} diff --git a/src/p7os/cake.exe/libgint/src/keyboard/getkey.c b/src/p7os/cake.exe/libgint/src/keyboard/getkey.c new file mode 100644 index 0000000..a1d2525 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/getkey.c @@ -0,0 +1,131 @@ +#include +#include +#include + +/* + getkey() + Blocking function with auto-repeat and SHIFT modifying functionalities. + Roughly reproduces the behavior of the system's GetKey(). +*/ +int getkey(void) +{ + return getkey_opt( + Getkey_ShiftModifier | + Getkey_AlphaModifier | + + Getkey_RepeatArrowKeys, + + 0 + ); +} + +/* + getkey_opt() + Enhances getkey() with more general functionalities. + If max_cycles is non-zero and positive, getkey_opt() will return + KEY_NOEVENT if no event occurs during max_cycle analysis. +*/ +void getkey_opt_wait(int *cycles) +{ + while(!interrupt_flag) sleep(); + interrupt_flag = 0; + + if(*cycles > 0) (*cycles)--; +} +int getkey_opt(enum GetkeyOpt options, int cycles) +{ + struct Event event; + int modifier = 0; + static int event_ref = 0; + + if(cycles <= 0) cycles = -1; + while(cycles != 0) + { + event = pollevent(); + switch(event.type) + { + case ET_None: + if(last_key == KEY_NONE) + { + getkey_opt_wait(&cycles); + continue; + } + + // Handling repetitions. + enum KeyType type = keytype(last_key); + if(!(options & (type << 4))) break; + + if(event_ref <= 0) + { + getkey_opt_wait(&cycles); + event_ref++; + continue; + } + + last_events++; + event_ref--; + + if(last_events >= (last_repeats ? repeat_next : + repeat_first)) + { + last_repeats++; + last_events = 0; + return last_key; + } + break; + + case ET_KeyPress: + ; + int key = event.key; + if(options & Getkey_ShiftModifier && key == KEY_SHIFT) + { + modifier ^= MOD_SHIFT; + continue; + } + if(options & Getkey_AlphaModifier && key == KEY_ALPHA) + { + modifier ^= MOD_ALPHA; + continue; + } + + last_key = key; + last_repeats = 0; + last_events = 0; + event_ref = 0; + return key | modifier; + + case ET_KeyRel: + if(event.key != last_key) break; + last_key = KEY_NONE; + last_repeats = 0; + last_events = 0; + event_ref = 0; + break; + + default: + break; + } + } + + last_key = KEY_NONE; + last_repeats = 0; + last_events = 0; + event_ref = 0; + return KEY_NONE; +} + +/* +int getkey_opt(enum GetkeyOpt options, int max_cycles) +{ + while(max_cycles != 0) + { + // Handling "new key" events. + + // Handling key repetitions. + + } + + // When no key was pressed during the given delay... + return KEY_NOEVENT; +} +*/ diff --git a/src/p7os/cake.exe/libgint/src/keyboard/keyboard_config.c b/src/p7os/cake.exe/libgint/src/keyboard/keyboard_config.c new file mode 100644 index 0000000..e19347f --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/keyboard_config.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +/* + keyboard_setRepeatRate() + Sets the default repeat rate for key events. The unit for the argument + is the keyboard period. + For example at 32 Hz, values of (20, 4) will imitate the system + default. +*/ +void keyboard_setRepeatRate(int first, int next) +{ + if(first < 0) first = 0; + if(next < 0) next = 0; + + repeat_first = first; + repeat_next = next; +} diff --git a/src/p7os/cake.exe/libgint/src/keyboard/keyboard_interrupt.c b/src/p7os/cake.exe/libgint/src/keyboard/keyboard_interrupt.c new file mode 100644 index 0000000..e98dc51 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/keyboard_interrupt.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include + +//--- +// Keyboard variables. +//--- + +// These ones get modified by interrupts. +volatile unsigned char keyboard_state[10] = { 0 }; +volatile int interrupt_flag = 0; + +// Key statistics. +int repeat_first = 10, repeat_next = 2; +int last_key = KEY_NONE, last_repeats = 0, last_events = 0; + +// RTC callback id. +unsigned cb_id; + + + +//--- +// Interrupt management. +//--- + +static void push_press(int keycode) +{ + struct Event event = { + .type = ET_KeyPress, + .key = keycode, + }; + event_push(event); +} + +static void push_release(int keycode) +{ + struct Event event = { + .type = ET_KeyRel, + .key = keycode, + }; + event_push(event); +} + +/* + keyboard_interrupt() + Callback for keyboard update. Allows keyboard analysis functions to + wake only when keyboard interrupts happen. +*/ +void keyboard_interrupt(void) +{ + unsigned char state[10] = { 0 }; + + isSH3() ? keyboard_updateState_7705(state) + : keyboard_updateState_7305(state) + ; + + // Try to minimize number of operations in common cases... this handles + // AC/ON. + if(keyboard_state[0] ^ state[0]) + { + unsigned char pressed = ~keyboard_state[0] & state[0]; + unsigned char released = keyboard_state[0] & ~state[0]; + + if(pressed & 1) push_press(KEY_AC_ON); + if(released & 1) push_release(KEY_AC_ON); + } + keyboard_state[0] = state[0]; + + for(int row = 1; row <= 9; row++) + { + unsigned char pressed = ~keyboard_state[row] & state[row]; + unsigned char released = keyboard_state[row] & ~state[row]; + keyboard_state[row] = state[row]; + + // Fasten this a bit. + if(!pressed && !released) continue; + + for(int column = 0; column < 8; column++) + { + if(pressed & 1) push_press ((column << 4) | row); + if(released & 1) push_release((column << 4) | row); + + pressed >>= 1; + released >>= 1; + } + } + + interrupt_flag = 1; +} + +/* + keyboard_init() + Starts the keyboard timer. +*/ +void keyboard_init(void) +{ + cb_id = rtc_cb_add(RTCFreq_16Hz, keyboard_interrupt, 0); +} + +/* + keyboard_setFrequency() + Sets the keyboard frequency. +*/ +void keyboard_setFrequency(enum KeyboardFrequency frequency) +{ + if(frequency < 1 || frequency > 7) return; + rtc_cb_edit(cb_id, frequency, keyboard_interrupt); +} + +/* + keyboard_quit() + Stops the keyboard timer. +*/ +void keyboard_quit(void) +{ + rtc_cb_end(cb_id); +} diff --git a/src/p7os/cake.exe/libgint/src/keyboard/keyboard_misc.c b/src/p7os/cake.exe/libgint/src/keyboard/keyboard_misc.c new file mode 100644 index 0000000..abdf59c --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/keyboard_misc.c @@ -0,0 +1,25 @@ +#include +#include + +/* + keylast() + Returns the matrix code of the last pressed key. If repeat_count is + non-NULL, it is set to the number of repetitions. +*/ +int keylast(int *repeat_count) +{ + if(repeat_count) *repeat_count = last_repeats; + return last_key; +} + + + +/* + keystate() + Returns the address of the keyboard state array. The returned address + is the handler's buffer, therefore it contains volatile data. +*/ +volatile unsigned char *keystate(void) +{ + return keyboard_state; +} diff --git a/src/p7os/cake.exe/libgint/src/keyboard/keyboard_sh7305.c b/src/p7os/cake.exe/libgint/src/keyboard/keyboard_sh7305.c new file mode 100644 index 0000000..ac740b6 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/keyboard_sh7305.c @@ -0,0 +1,142 @@ +//--- +// +// gint core module: keyboard analyzer +// +// Probably the most difficult hardware interaction. There is very few +// documentation on how the system actually analyzes the keyboard. While +// disassembling syscalls reveals the following procedure (which was +// already documented by SimonLothar), there is nothing about the +// detection problems of the multi-getkey system. +// +//--- + +#include +#include <7305.h> + +//--- +// Keyboard management. +//--- + +/* + kdelay() + Should sleep during a few milliseconds. Well... + This delay has a great influence on key detection. Here are a few + observations of what happens with common numbers of "nop" (without + overclock). Take care of the effect of overclock! + + Column effects + May have something to do with register HIZCRB not being used here. When + many keys on the same column are pressed, other keys of the same column + may be triggered. + + - Less Bad key detection. + - 8 Very few column effects. Most often, three keys may be pressed + simultaneously. However, [UP] has latencies and is globally not + detected. + - 12 Seems best. Every individual key is detected well. No column + effect observed before four keys. + - 16 Every single key is detected correctly. Pressing two keys on a + same column does not usually create a column effect. Three keys + almost always. + - More Does not improve single key detection, and increase column + effects. At 256 every single key press create a whole column + effect. +*/ +static void kdelay(void) +{ + #define r4(str) str str str str + + __asm__ + ( + "nop\n\t" + ); + + #undef r4 +} + +/* + krow() + Reads a keyboard row. Works like krow() for SH7705. See gint_7705.c for + more details. +*/ +static int krow(int row) +{ + volatile unsigned short *injector1 = (unsigned short *)0xa4050116; + volatile unsigned char *data1 = (unsigned char *)0xa4050136; + + volatile unsigned short *injector2 = (unsigned short *)0xa4050118; + volatile unsigned char *data2 = (unsigned char *)0xa4050138; + + volatile unsigned short *detector = (unsigned short *)0xa405014c; + volatile unsigned char *keys = (unsigned char *)0xa405016c; + + volatile unsigned char *key_register = (unsigned char *)0xa40501c6; +// volatile unsigned short *hizcrb = (unsigned short *)0xa405015a; + + unsigned short smask; + unsigned char cmask; + int result = 0; + + if(row < 0 || row > 9) return 0; + + // Additional configuration for SH7305. + *detector = 0xaaaa; + *key_register = 0xff; + *injector1 = (*injector1 & 0xf000) | 0x0555; + *injector2 = (*injector2 & 0xf000) | 0x0555; + *data1 |= 0x3f; + *data2 |= 0x3f; + kdelay(); + + if(row < 6) + { + smask = 0x0003 << (row * 2); + cmask = ~(1 << row); + + *injector1 = ((*injector1 & 0xf000) | 0x0aaa) ^ smask; + *injector2 = (*injector2 & 0xf000) | 0x0aaa; + kdelay(); + + *data1 = (*data1 & 0xc0) | cmask; + *data2 |= 0x3f; + kdelay(); + } + else + { + smask = 0x0003 << ((row - 6) * 2); + cmask = ~(1 << (row - 6)); + + *injector1 = (*injector1 & 0xf000) | 0x0aaa; + *injector2 = ((*injector2 & 0xf000) | 0x0aaa) ^ smask; + kdelay(); + + *data1 |= 0x3f; + *data2 = (*data2 & 0xc0) | cmask; + kdelay(); + } + + // Reading the keyboard row. + result = ~*keys; + kdelay(); + + // Re-initializing the port configuration and data. + *injector1 = (*injector1 & 0xf000) | 0x0aaa; + *injector2 = (*injector2 & 0xf000) | 0x0aaa; + kdelay(); + *injector1 = (*injector1 & 0xf000) | 0x0555; + *injector2 = (*injector2 & 0xf000) | 0x0555; + kdelay(); + *data1 &= 0xc0; + *data2 &= 0xc0; + + return result; +} + +/* + keyboard_updateState() + Updates the keyboard state. +*/ +void keyboard_updateState_7305(volatile unsigned char *keyboard_state) +{ + for(int i = 0; i < 10; i++) keyboard_state[i] = krow(i); +} diff --git a/src/p7os/cake.exe/libgint/src/keyboard/keyboard_sh7705.c b/src/p7os/cake.exe/libgint/src/keyboard/keyboard_sh7705.c new file mode 100644 index 0000000..1ab1800 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/keyboard_sh7705.c @@ -0,0 +1,135 @@ +//--- +// +// gint core module: keyboard analyzer +// +// Probably the most difficult hardware interaction. There is very few +// documentation on how the system actually analyzes the keyboard. While +// disassembling syscalls reveals the following procedure (which was +// already documented by SimonLothar), there is nothing about the +// detection problems of the multi-getkey system. +// +//--- + +#include +#include <7705.h> + +//--- +// Keyboard management. +//--- + +/* + kdelay() + Used to be a low-level sleep using the watchdog, as in the system. This + way seems OK at least, and it doesn't create column effects as for + SH7305. +*/ +static void kdelay(void) +{ + #define r4(str) str str str str + + __asm__ + ( + r4("nop\n\t") + ); + + #undef r4 + + /* Watchdog delay version. + const int delay = 0xf4; + + // Disabling the watchdog timer interrupt and resetting the + // configuration. Setting the delay. + INTC.IPRB.BIT._WDT = 0; + WDT.WTCSR.WRITE = 0xa500; + WDT.WTCNT.WRITE = 0x5a00 | (delay & 0xff); + + // Counting on Po/256. + WDT.WTCSR.WRITE = 0xa505; + // Starting the timer (sets again to Po/256). + WDT.WTCSR.WRITE = 0xa585; + + // Waiting until it overflows (delaying), then clearing the overflow + // flag. + while((WDT.WTCSR.READ.BYTE & 0x08) == 0); + WDT.WTCSR.WRITE = 0xa500 | (WDT.WTCSR.READ.BYTE & 0xf7); + + // Resetting the configuration and the counter. + WDT.WTCSR.WRITE = 0xa500; + WDT.WTCSR.WRITE = 0x5a00; + + // Enabling back the watchdog timer interrupt. + INTC.IPRB.BIT._WDT = GINT_INTP_WDT; + */ +} + +/* + krow() + Reads a keyboard row. +*/ +static int krow(int row) +{ + // '11' on the active row, '00' everywhere else. + unsigned short smask = 0x0003 << ((row % 8) * 2); + // '0' on the active row, '1' everywhere else. + unsigned char cmask = ~(1 << (row % 8)); + // Line results. + int result = 0; + + if(row < 0 || row > 9) return 0; + + // Initial configuration. + PFC.PBCR.WORD = 0xaaaa; + PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x0055; + kdelay(); + + if(row < 8) + { + // Configuring port B/M as input except for the row to check, + // which has to be an output. This sets '01' (output) on the + // active row, '10' (input) everywhere else. + PFC.PBCR.WORD = 0xaaaa ^ smask; + PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x00aa; + kdelay(); + + // Every bit set to 1 except the active row bit. + PB.DR.BYTE = cmask; + PM.DR.BYTE = (PM.DR.BYTE & 0xf0) | 0x0f; + kdelay(); + } + else + { + // The same, but deals with port M. + PFC.PBCR.WORD = 0xaaaa; + PFC.PMCR.WORD = ((PFC.PMCR.WORD & 0xff00) | 0x00aa) ^ smask; + kdelay(); + + PB.DR.BYTE = 0xff; + PM.DR.BYTE = (PM.DR.BYTE & 0xf0) | cmask; + kdelay(); + } + + // Reading the keyboard row. + result = ~PA.DR.BYTE; + kdelay(); + + // Re-initializing the port configuration and data. + PFC.PBCR.WORD = 0xaaaa; + PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x00aa; + kdelay(); + PFC.PBCR.WORD = 0x5555; + PFC.PMCR.WORD = (PFC.PMCR.WORD & 0xff00) | 0x0055; + kdelay(); + PB.DR.BYTE = 0x00; + PM.DR.BYTE &= 0xf0; + + return result; +} + +/* + keyboard_updateState() + Updates the keyboard state. +*/ +void keyboard_updateState_7705(volatile unsigned char *keyboard_state) +{ + for(int i = 0; i < 10; i++) keyboard_state[i] = krow(i); +} diff --git a/src/p7os/cake.exe/libgint/src/keyboard/keychar.c b/src/p7os/cake.exe/libgint/src/keyboard/keychar.c new file mode 100644 index 0000000..bd9e9cc --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/keychar.c @@ -0,0 +1,36 @@ +#include + +/* + keychar() + Returns the ASCII character associated with a key, or 0 for control + keys. +*/ +int keychar(int key) +{ + char flat[] = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, '2', '^', 0x0, 0x0, 0x0, + 'X', 'L', 'l', 's', 'c', 't', + 0x0, 0x0, '(', ')', ',', '>', + '7', '8', '9', 0x0, 0x0, 0x0, + '4', '5', '6', '*', '/', 0x0, + '1', '2', '3', '+', '-', 0x0, + '0', '.', 'e', '_', 0x0, 0x0 + }; + char alpha[] = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 'r', 'o', 0x0, 0x0, 0x0, + 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 0x0, 0x0, 0x0, + 'P', 'Q', 'R', 'S', 'T', 0x0, + 'U', 'V', 'W', 'X', 'Y', 0x0, + 'Z', ' ', '"', 0x0, 0x0, 0x0 + }; + + int id = keyid(key); + + return (key & MOD_ALPHA) ? alpha[id] : flat[id]; +} diff --git a/src/p7os/cake.exe/libgint/src/keyboard/keyid.c b/src/p7os/cake.exe/libgint/src/keyboard/keyid.c new file mode 100644 index 0000000..c4ed014 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/keyid.c @@ -0,0 +1,17 @@ +#include + +/* + keyid() + Returns a non-matrix key code that can be used for array subscript. + Ignores modifiers. +*/ +int keyid(int key) +{ + if(key < 0) return -1; + key &= MOD_CLEAR; + + int row = 9 - (key & 0x0f); + int column = 6 - ((key & 0xf0) >> 4); + + return 6 * row + column; +} diff --git a/src/p7os/cake.exe/libgint/src/keyboard/keytype.c b/src/p7os/cake.exe/libgint/src/keyboard/keytype.c new file mode 100644 index 0000000..9e3c0c9 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/keytype.c @@ -0,0 +1,17 @@ +#include + +/* + keytype() + Returns a key's type. Ignores modifiers. +*/ +enum KeyType keytype(int key) +{ + key &= MOD_CLEAR; + + if(key == KEY_UP || key == KEY_RIGHT || key == KEY_DOWN || + key == KEY_LEFT) return KeyType_Arrow; + + if((key & 0x0f) == 0x09) return KeyType_Function; + + return keychar(key) ? KeyType_Character : KeyType_Control; +} diff --git a/src/p7os/cake.exe/libgint/src/keyboard/multigetkey.c b/src/p7os/cake.exe/libgint/src/keyboard/multigetkey.c new file mode 100644 index 0000000..dbe8a44 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/keyboard/multigetkey.c @@ -0,0 +1,46 @@ +#include +#include + +/* + multigetkey() + Listens the keyboard for simultaneous key hits. Uses the same options + as getkey_opt(). + multigetkey() fills the 'keys' array with 'count' key codes, adding + KEY_NOKEY if less than 'count' keys are pressed. + Be aware that rectangle and column effects can make multigetkey() read + unpressed keys as pressed (see documentation for more information). + Setting count = 3 is generally safe. + The function returns after 'max_cycles' if no key is pressed. +*/ +void multigetkey(int *keys, int count, int max_cycles) +{ + int number; + + if(!max_cycles) max_cycles = -1; + + while(max_cycles != 0) + { + while(!interrupt_flag) sleep(); + interrupt_flag = 0; + if(max_cycles > 0) max_cycles--; + + number = getPressedKeys(keyboard_state, keys, count); + + // We need to update the last key data, in case multigetkey() + // returns a single key, and getkey() is called a short time + // after. Otherwise getkey() could re-send an event for this + // key. + if(number == 1) + { + last_key = keys[0]; + last_repeats = 0; + last_events = 0; + } + + if(number) return; + } + + // When no key was pressed during the given delay... (no need to fill + // the array, it has already been done by getPressedKeys()). + return; +} diff --git a/src/p7os/cake.exe/libgint/src/mmu/pseudoTLBInit.c b/src/p7os/cake.exe/libgint/src/mmu/pseudoTLBInit.c new file mode 100644 index 0000000..b27d60d --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/mmu/pseudoTLBInit.c @@ -0,0 +1,29 @@ +#include + +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" + +/* + mmu_pseudoTLBInit() + We need the system to fill the TLB for us, so that it knows what + happens to its contents. We don't want to edit the TLB ourselves, so + we'll just read random data from every 4k-page in the rom area to have + the system virtualize it entirely. + The index system for TLB entries ensures this process will work for + 128-k or less add-ins. On SH7705 there is a limit, which is 384-k (it + does probably not exist on SH7305) but there is no guarantee that the + system will not go wild after 128-k. +*/ +void mmu_pseudoTLBInit(void) +{ + extern unsigned int romdata; + unsigned int address = 0x00300000; + unsigned int x; + + while(address <= (unsigned int)&romdata) + { + x = *((volatile unsigned int *)address); + address += 0x1000; + } +} + +#pragma GCC diagnostic pop diff --git a/src/p7os/cake.exe/libgint/src/mpu/gint_sh7305.c b/src/p7os/cake.exe/libgint/src/mpu/gint_sh7305.c new file mode 100644 index 0000000..7327a38 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/mpu/gint_sh7305.c @@ -0,0 +1,219 @@ +//--- +// +// gint core module: sh7305 interrupt handler +// +// Of course all the work related to interrupts is heavily platform- +// dependent. This module handles interrupts and configures the MPU to +// save and restore the system's configuration when execution ends. +// +//--- + +#include +#include +#include +#include +#include <7305.h> +#include + +#include + +//--- +// Interrupt codes. +//--- + +#define IC_RTC_PRI 0xaa0 +#define IC_KEYSC 0xbe0 +#define IC_TMU0_TUNI0 0x400 +#define IC_TMU0_TUNI1 0x420 +#define IC_TMU0_TUNI2 0x440 + + + +//--- +// Exception handling. +//--- + +void gint_int_7305(void) +{ + volatile unsigned int *intevt = (unsigned int *)0xff000028; + unsigned int code = *intevt; + + switch(code) + { + case IC_RTC_PRI: + rtc_interrupt(); + break; + + case IC_TMU0_TUNI0: + timer_interrupt(TIMER_TMU0); + break; + + case IC_TMU0_TUNI1: + timer_interrupt(TIMER_TMU1); + break; + + case IC_TMU0_TUNI2: + timer_interrupt(TIMER_TMU2); + break; + + default: + gint_callDefaultHandler(code); + } +} + +/* + gint_reg() + Returns the address of a common register. All common registers exist + on both platforms but they may hold different values for the same + information (f.i. EXPEVT may not return the same value for a given + exception on both 7705 and 7305). +*/ +volatile void *gint_reg_7305(enum Register reg) +{ + volatile unsigned int *expevt = (unsigned int *)0xff000024; + volatile unsigned int *tea = (unsigned int *)0xff00000c; + volatile unsigned int *mmucr = (unsigned int *)0xff000010; + + switch(reg) + { + case Register_EXPEVT: return expevt; + case Register_TEA: return tea; + case Register_MMUCR: return mmucr; + default: return NULL; + } +} + +/* + gint_strerror() + Returns a string that describe the error set in EXPEVT. This string is + not platform-dependent. +*/ +const char *gint_strerror_7305(void) +{ + volatile unsigned int *expevt = gint_reg_7305(Register_EXPEVT); + + switch(*expevt) + { + case 0x1e0: return gint_str[3]; + case 0x0e0: return gint_str[8]; + case 0x040: return gint_str[14]; + case 0x0a0: return gint_str[17]; + case 0x180: return gint_str[6]; + case 0x1a0: return gint_str[7]; + case 0x100: return gint_str[9]; + case 0x060: return gint_str[15]; + case 0x0c0: return gint_str[18]; + case 0x080: return gint_str[20]; + case 0x160: return gint_str[21]; + } + return gint_str[0]; +} + + + +//--- +// Setup. +//--- + +static unsigned short ipr[12]; +static unsigned char rcr2; +// Saves of the keyboard registers. Could be better. +static unsigned short inj1, inj2, det; +static unsigned char data1, data2, keys, reg; + +static void gint_priority_lock_7305(void) +{ + // Saving the current interrupt priorities. + ipr[0] = INTX.IPRA.WORD; + ipr[1] = INTX.IPRB.WORD; + ipr[2] = INTX.IPRC.WORD; + ipr[3] = INTX.IPRD.WORD; + ipr[4] = INTX.IPRE.WORD; + ipr[5] = INTX.IPRF.WORD; + ipr[6] = INTX.IPRG.WORD; + ipr[7] = INTX.IPRH.WORD; + ipr[8] = INTX.IPRI.WORD; + ipr[9] = INTX.IPRJ.WORD; + ipr[10] = INTX.IPRK.WORD; + ipr[11] = INTX.IPRL.WORD; + + // Disabling everything by default to avoid freezing on non-handled + // interrupts. + INTX.IPRA.WORD = 0x0000; + INTX.IPRB.WORD = 0x0000; + INTX.IPRC.WORD = 0x0000; + INTX.IPRD.WORD = 0x0000; + INTX.IPRE.WORD = 0x0000; + INTX.IPRF.WORD = 0x0000; + INTX.IPRG.WORD = 0x0000; + INTX.IPRH.WORD = 0x0000; + INTX.IPRI.WORD = 0x0000; + INTX.IPRJ.WORD = 0x0000; + INTX.IPRK.WORD = 0x0000; + INTX.IPRL.WORD = 0x0000; + + // Saving keyboard registers. + inj1 = *((volatile unsigned short *)0xa4050116); + data1 = *((volatile unsigned char *)0xa4050136); + inj2 = *((volatile unsigned short *)0xa4050118); + data2 = *((volatile unsigned char *)0xa4050138); + det = *((volatile unsigned short *)0xa405014c); + keys = *((volatile unsigned char *)0xa405016c); + reg = *((volatile unsigned char *)0xa40501c6); + + // Allowing RTC. Keyboard analysis is done regularly using a RTC + // because SH7305's special KEYSC interface does not allow us to clear + // the keyboard interrupt flags. + INTX.IPRK._RTC = GINT_INTP_RTC; + INTX.IPRA.TMU0_0 = GINT_INTP_KEY; + INTX.IPRA.TMU0_1 = GINT_INTP_GRAY; + INTX.IPRA.TMU0_2 = GINT_INTP_TIMER; +} + +static void gint_priority_unlock_7305(void) +{ + // Restoring the interrupt priorities. + INTX.IPRA.WORD = ipr[0]; + INTX.IPRB.WORD = ipr[1]; + INTX.IPRC.WORD = ipr[2]; + INTX.IPRD.WORD = ipr[3]; + INTX.IPRE.WORD = ipr[4]; + INTX.IPRF.WORD = ipr[5]; + INTX.IPRG.WORD = ipr[6]; + INTX.IPRH.WORD = ipr[7]; + INTX.IPRI.WORD = ipr[8]; + INTX.IPRJ.WORD = ipr[9]; + INTX.IPRK.WORD = ipr[10]; + INTX.IPRL.WORD = ipr[11]; + + // Restoring keyboard registers. + *((volatile unsigned short *)0xa4050116) = inj1; + *((volatile unsigned char *)0xa4050136) = data1; + *((volatile unsigned short *)0xa4050118) = inj2; + *((volatile unsigned char *)0xa4050138) = data2; + *((volatile unsigned short *)0xa405014c) = det; + *((volatile unsigned char *)0xa405016c) = keys; + *((volatile unsigned char *)0xa40501c6) = reg; +} + +void gint_setup_7305(void) +{ + volatile struct mod_rtc *RTC = RTC_SH7305; + + gint_priority_lock_7305(); + + // Saving the RTC configuration. + rcr2 = RTC->RCR2.BYTE; + // Disabling RTC interrupts by default. + RTC->RCR2.BYTE = 0x09; +} + +void gint_stop_7305(void) +{ + volatile struct mod_rtc *RTC = RTC_SH7305; + + gint_priority_unlock_7305(); + + // Restoring the RTC configuration. + RTC->RCR2.BYTE = rcr2; +} diff --git a/src/p7os/cake.exe/libgint/src/mpu/gint_sh7705.c b/src/p7os/cake.exe/libgint/src/mpu/gint_sh7705.c new file mode 100644 index 0000000..a1c19aa --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/mpu/gint_sh7705.c @@ -0,0 +1,190 @@ +//--- +// +// gint core module: sh7705 interrupt handler +// +// Of course all the work related to interrupts is heavily platform- +// dependent. This module handles interrupts and configures the MPU to +// save and restore the system's configuration when execution ends. +// +//--- + +#include +#include +#include +#include +#include <7705.h> +#include + +#include + +//--- +// Interrupt codes. +//--- + +#define IC_RTC_PRI 0x4a0 +#define IC_PINT07 0x700 +#define IC_TMU0_TUNI0 0x400 +#define IC_TMU1_TUNI1 0x420 +#define IC_TMU2_TUNI2 0x440 + + + +//--- +// Exception handling. +//--- + +void gint_int_7705(void) +{ + volatile unsigned int *intevt2 = (unsigned int *)0xa4000000; + unsigned int code = *intevt2; + + switch(code) + { + case IC_RTC_PRI: + rtc_interrupt(); + break; + + case IC_TMU0_TUNI0: + timer_interrupt(TIMER_TMU0); + break; + + case IC_TMU1_TUNI1: + timer_interrupt(TIMER_TMU1); + break; + + case IC_TMU2_TUNI2: + timer_interrupt(TIMER_TMU2); + break; + + default: + gint_callDefaultHandler(code); + } +} + +/* + gint_reg() + Returns the address of a common register. All common registers exist + on both platforms but they may hold different values for the same + information (f.i. EXPEVT may not return the same value for a given + exception on both 7705 and 7305). +*/ +volatile void *gint_reg_7705(enum Register reg) +{ + volatile unsigned int *expevt = (unsigned int *)0xffffffd4; + volatile unsigned int *mmucr = (unsigned int *)0xfffffff4; + volatile unsigned int *tea = (unsigned int *)0xfffffffc; + + switch(reg) + { + case Register_EXPEVT: return expevt; + case Register_MMUCR: return mmucr; + case Register_TEA: return tea; + default: return NULL; + } +} + +/* + gint_strerror() + Returns a string that describe the error set in EXPEVT. This string is + not platform-dependent. + Some exception codes represent different errors when invoked inside the + general exception handler and the TLB error handler. Parameter 'is_tlb' + should be set to zero for general exception meanings, and anything non- + zero for TLB error meanings. +*/ +const char *gint_strerror_7705(int is_tlb) +{ + volatile unsigned int *expevt = gint_reg_7705(Register_EXPEVT); + + switch(*expevt) + { + case 0x1e0: return gint_str[3]; + case 0x0e0: return gint_str[4]; + case 0x040: return gint_str[is_tlb ? 10 : 11]; + case 0x0a0: return gint_str[12]; + case 0x180: return gint_str[6]; + case 0x1a0: return gint_str[7]; + case 0x100: return gint_str[5]; + case 0x060: return gint_str[is_tlb ? 13 : 19]; + case 0x0c0: return gint_str[16]; + case 0x080: return gint_str[20]; + case 0x160: return gint_str[21]; + case 0x5c0: return gint_str[22]; + } + return gint_str[0]; +} + + + +//--- +// Setup. +//--- + +static unsigned short iprs[8]; +static unsigned char rcr2; + +static void gint_priority_lock_7705(void) +{ + // Saving the interrupt masks from registers IPRA to IPRH. + iprs[0] = INTC.IPRA.WORD; + iprs[1] = INTC.IPRB.WORD; + iprs[2] = INTX.IPRC.WORD; + iprs[3] = INTX.IPRD.WORD; + iprs[4] = INTX.IPRE.WORD; + iprs[5] = INTX.IPRF.WORD; + iprs[6] = INTX.IPRG.WORD; + iprs[7] = INTX.IPRH.WORD; + + // Disabling everything by default to avoid receiving an interrupt that + // the handler doesn't handle, which would cause the user program to + // freeze. + INTC.IPRA.WORD = 0x0000; + INTC.IPRB.WORD = 0x0000; + INTX.IPRC.WORD = 0x0000; + INTX.IPRD.WORD = 0x0000; + INTX.IPRE.WORD = 0x0000; + INTX.IPRF.WORD = 0x0000; + INTX.IPRG.WORD = 0x0000; + INTX.IPRH.WORD = 0x0000; + + // Allowing RTC, which handles keyboard. + INTC.IPRA.BIT._RTC = GINT_INTP_RTC; + INTC.IPRA.BIT._TMU0 = GINT_INTP_KEY; + INTC.IPRA.BIT._TMU1 = GINT_INTP_GRAY; + INTC.IPRA.BIT._TMU2 = GINT_INTP_TIMER; +} + +static void gint_priority_unlock_7705(void) +{ + // Restoring the saved states. + INTC.IPRA.WORD = iprs[0]; + INTC.IPRB.WORD = iprs[1]; + INTX.IPRC.WORD = iprs[2]; + INTX.IPRD.WORD = iprs[3]; + INTX.IPRE.WORD = iprs[4]; + INTX.IPRF.WORD = iprs[5]; + INTX.IPRG.WORD = iprs[6]; + INTX.IPRH.WORD = iprs[7]; +} + +void gint_setup_7705(void) +{ + volatile struct mod_rtc *RTC = RTC_SH7705; + + gint_priority_lock_7705(); + + // Saving the RTC configuration. + rcr2 = RTC->RCR2.BYTE; + // Disabling RTC interrupts by default. + RTC->RCR2.BYTE = 0x09; +} + +void gint_stop_7705(void) +{ + volatile struct mod_rtc *RTC = RTC_SH7705; + + gint_priority_unlock_7705(); + + // Restoring the RTC configuration. + RTC->RCR2.BYTE = rcr2; +} diff --git a/src/p7os/cake.exe/libgint/src/mpu/mpu.c b/src/p7os/cake.exe/libgint/src/mpu/mpu.c new file mode 100644 index 0000000..f4c7dc6 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/mpu/mpu.c @@ -0,0 +1,80 @@ +//--- +// +// gint core module: mpu +// +// Determines which kind of MPU is running the program. +// +//--- + +#include + +enum MPU MPU_CURRENT; + +/* + getMPU() + + Returns the MPU identifier of the calculator. + Thanks to SimonLothar for this function and related information. + + Processor version register (PVR) and product control register (PRR) + hold information about the MPU version, they but are only accessible on + SH-4-based MPUs. + To detect SH-3-based MPUs, this function uses port L control register + (PLCR), whose bits 8 to 15 cannot be set with SH7337 where bits 8 to 11 + can be set with SH7355. + + Additionally, the CPU core ID register (CPIDR) at 0xff000048 returns 1 + on SH7305. +*/ +enum MPU getMPU(void) +{ + // Processor version register. + volatile unsigned int *pvr = (unsigned int *)0xff000030; + // Product version register. + volatile unsigned int *prr = (unsigned int *)0xff000044; + // Port L control register. + volatile unsigned short *plcr = (unsigned short *)0xa4000114; + // Saved value for PLCR. + unsigned short saved_plcr; + unsigned int tested_plcr; + + + // Looking for SH-3-based MPUs by testing PLCR writing access. + saved_plcr = *plcr; + *plcr = 0xffff; + tested_plcr = *plcr; + *plcr = saved_plcr; + + // Checking whether we are working with an SH7337 or an SH7355. + if(tested_plcr == 0x00ff) return MPU_SH7337; + if(tested_plcr == 0x0fff) return MPU_SH7355; + + // Looking for SH-4-based MPUs by testing the version registers. This + // needs to have the three upper bytes of the processor version + // register match 0x10300b : + if((*pvr & 0xffffff00) != 0x10300b00) return MPU_Unknown; + + // Now that we have an SH-4-based MPU, checking whether it is SH7305 or + // SH7724. + switch(*prr & 0xfffffff0) + { + case 0x00002c00: + return MPU_SH7305; + case 0x00002200: + return MPU_SH7724; + } + + // By default, the MPU is unknown. + return MPU_Unknown; +} + + + +/* + mpu_init() + Determines the MPU type and stores the result into MPU_CURRENT. +*/ +void mpu_init(void) +{ + MPU_CURRENT = getMPU(); +} diff --git a/src/p7os/cake.exe/libgint/src/rtc/rtc_callback.c b/src/p7os/cake.exe/libgint/src/rtc/rtc_callback.c new file mode 100644 index 0000000..3a69a95 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/rtc/rtc_callback.c @@ -0,0 +1,151 @@ +#include +#include +#include + +// Array holding callback informations. +struct rtc_cb cb_array[RTC_CB_ARRAY_SIZE] = { 0 }; +// Callback identifier (unique). +static int unique_id = 1; +// Current RTC interrupt frequency. +static enum RTCFrequency rtc_freq = RTCFreq_None; +// 256-Hz tick count. This counter is stopped when no callback is registered. +static unsigned elapsed256 = 0; + +/* + rtc_cb_update() + After successful registration or deletion of a callback, updates the + RTC interrupt frequency stored in register RCR2. After update, the + interrupt frequency is high enough to handle all callbacks, but nothing + more (so that no time is wasted handling interrupts that occur too + often). +*/ +static void rtc_cb_update(void) +{ + enum RTCFrequency max = RTCFreq_None; + int n; + + for(n = 0; n < RTC_CB_ARRAY_SIZE; n++) if(cb_array[n].id) + { + if(!max || (cb_array[n].freq && cb_array[n].freq < max)) + max = cb_array[n].freq; + } + + if(rtc_freq == max) return; + rtc_freq = max; + + volatile struct mod_rtc *RTC = isSH3() ? RTC_SH7705 : RTC_SH7305; + RTC->RCR2.BYTE = (rtc_freq << 4) | 0x09; +} + +/* + rtc_cb_add() + Registers a new callback for the RTC. Returns the callback id on + success (positive integer), or one of the following error codes: + -1 Array is full + -2 Invalid parameter + The number of repeats may be set to 0, in which case the callback is + called indefinitely unless the user calls rtc_cb_end(). +*/ +int rtc_cb_add(enum RTCFrequency freq, void (*function)(void), int repeats) +{ + int n = 0; + if(freq == RTCFreq_None || !function || repeats < 0) return -2; + + while(n < RTC_CB_ARRAY_SIZE && cb_array[n].id) n++; + if(n >= RTC_CB_ARRAY_SIZE) return -1; + + cb_array[n].freq = freq; + cb_array[n].callback = function; + cb_array[n].repeats = repeats; + cb_array[n].id = unique_id++; + + rtc_cb_update(); + + return cb_array[n].id; +} + +/* + rtc_cb_end() + Removes the callback with the given id (as returned by rtc_cb_add()) + from the callback array. +*/ +void rtc_cb_end(int id) +{ + int n = 0; + + while(n < RTC_CB_ARRAY_SIZE && cb_array[n].id != id) n++; + if(n >= RTC_CB_ARRAY_SIZE) return; + + cb_array[n].id = 0; + cb_array[n].freq = RTCFreq_None; + cb_array[n].callback = NULL; + cb_array[n].repeats = 0; + + rtc_cb_update(); +} + +/* + rtc_cb_edit() + Changes information related to a callback. This function returns 0 on + success, or one of the following error codes: + -1 Callback does not exist + -2 Invalid parameters + This function never removes a callback. Call rtc_cb_end() for this. +*/ +int rtc_cb_edit(int id, enum RTCFrequency new_freq, + void (*new_function)(void)) +{ + if(new_freq < 0 || new_freq > 7) return -2; + int n = 0; + + while(n < RTC_CB_ARRAY_SIZE && cb_array[n].id != id) n++; + if(n >= RTC_CB_ARRAY_SIZE) return -1; + + cb_array[n].freq = new_freq; + cb_array[n].callback = new_function; + rtc_cb_update(); + + return 0; +} + +/* + rtc_cb_interrupt() + Handles an RTC interrupt. Calls the RTC callbacks if necessary, and + updates the repeat counts. +*/ +void rtc_cb_interrupt(void) +{ + int n; + + int scales[] = { + 1, // 256 Hz + 4, // 64 Hz + 16, // 16 Hz + 64, // 4 Hz + 128, // 2 Hz + 256, // 1 Hz + 512, // 0.5 Hz + }; + // Adding to elapsed256 the number of 256-Hz ticks that correspond to + // the current interrupt frequency, and rounding the result to a + // multiple of this tick number. + elapsed256 = (elapsed256 + scales[rtc_freq]) & ~(scales[rtc_freq] - 1); + + for(n = 0; n < RTC_CB_ARRAY_SIZE; n++) + { + struct rtc_cb *cb = &cb_array[n]; + if(!cb->id || !cb->freq) continue; + + // Only execute callback when the number of elapsed 256-Hz + // ticks reach a multiple that correspond to the callback + // frequency. + if(elapsed256 & (scales[cb->freq] - 1)) continue; + + if(cb->callback) (*cb->callback)(); + if(cb->repeats) + { + if(cb->repeats == 1) rtc_cb_end(cb->id); + else cb->repeats--; + } + } +} diff --git a/src/p7os/cake.exe/libgint/src/rtc/rtc_getTime.c b/src/p7os/cake.exe/libgint/src/rtc/rtc_getTime.c new file mode 100644 index 0000000..5e9f653 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/rtc/rtc_getTime.c @@ -0,0 +1,38 @@ +#include +#include +#include + +/* + integer() + Converts a BCD value to an integer. +*/ +static int integer8(int bcd) +{ + return (bcd & 0x0f) + 10 * (bcd >> 4); +} +static int integer16(int bcd) +{ + return (bcd & 0xf) + 10 * ((bcd >> 4) & 0xf) + 100 * ((bcd >> 8) & 0xf) + + 1000 * (bcd >> 12); +} + +/* + rtc_getTime() + Reads the current time from the RTC. There is no guarantee that the + week day is correct (use the time API for that). +*/ +struct RTCTime rtc_getTime(void) +{ + volatile struct mod_rtc *rtc = isSH3() ? RTC_SH7705 : RTC_SH7305; + struct RTCTime time; + + time.seconds = integer8(rtc->RSECCNT.BYTE); + time.minutes = integer8(rtc->RMINCNT.BYTE); + time.hours = integer8(rtc->RHRCNT.BYTE); + time.month_day = integer8(rtc->RDAYCNT.BYTE); + time.month = integer8(rtc->RMONCNT.BYTE); + time.year = integer16(rtc->RYRCNT.WORD); + time.week_day = rtc->RWKCNT; + + return time; +} diff --git a/src/p7os/cake.exe/libgint/src/rtc/rtc_interrupt.c b/src/p7os/cake.exe/libgint/src/rtc/rtc_interrupt.c new file mode 100644 index 0000000..775a220 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/rtc/rtc_interrupt.c @@ -0,0 +1,15 @@ +#include +#include +#include + +/* + rtc_interrupt() + Handles an RTC interrupt by calling the callback. +*/ +void rtc_interrupt(void) +{ + rtc_cb_interrupt(); + + volatile struct mod_rtc *RTC = isSH3() ? RTC_SH7705 : RTC_SH7305; + RTC->RCR2.PEF = 0; +} diff --git a/src/p7os/cake.exe/libgint/src/rtc/rtc_setTime.c b/src/p7os/cake.exe/libgint/src/rtc/rtc_setTime.c new file mode 100644 index 0000000..d343c51 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/rtc/rtc_setTime.c @@ -0,0 +1,36 @@ +#include +#include +#include + +/* + bcd() + Converts an integer to a BCD value. +*/ +static int bcd8(int integer) +{ + integer %= 100; + return ((integer / 10) << 4) | (integer % 10); +} +static int bcd16(int integer) +{ + integer %= 10000; + return (bcd8(integer / 100) << 8) | bcd8(integer % 100); +} + +/* + rtc_setTime() + Sets the time in the RTC registers. The week day is set to 0 if greater + than 6. Other fields are not checked. +*/ +void rtc_setTime(struct RTCTime time) +{ + volatile struct mod_rtc *rtc = isSH3() ? RTC_SH7705 : RTC_SH7305; + + rtc->RSECCNT.BYTE = bcd8(time.seconds); + rtc->RMINCNT.BYTE = bcd8(time.minutes); + rtc->RHRCNT.BYTE = bcd8(time.hours); + rtc->RDAYCNT.BYTE = bcd8(time.month_day); + rtc->RMONCNT.BYTE = bcd8(time.month); + rtc->RYRCNT.WORD = bcd16(time.year); + rtc->RWKCNT = time.week_day < 7 ? time.week_day : 0; +} diff --git a/src/p7os/cake.exe/libgint/src/screen/screen_display.c b/src/p7os/cake.exe/libgint/src/screen/screen_display.c new file mode 100644 index 0000000..c04d7d8 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/screen/screen_display.c @@ -0,0 +1,35 @@ +#include + +/* + screen_display() + + Displays the given vram on the screen. Only bytes can be transferred + through the screen registers, which is unfortunate because most of the + vram-related operations use longword-base operations. +*/ +void screen_display(const void *ptr) +{ + const char *vram = (const char *)ptr; + volatile char *selector = (char *)0xb4000000; + volatile char *data = (char *)0xb4010000; + int line, bytes; + + for(line = 0; line < 64; line++) + { + // Setting the x-address register. + *selector = 4; + *data = line + 0xc0; + + // Setting Y-Up mode. + *selector = 1; + *data = 1; + + // Setting y-address. + *selector = 4; + *data = 0; + + // Selecting data write register 7 and sending a line's bytes. + *selector = 7; + for(bytes = 0; bytes < 16; bytes++) *data = *vram++; + } +} diff --git a/src/p7os/cake.exe/libgint/src/setjmp/setjmp.s b/src/p7os/cake.exe/libgint/src/setjmp/setjmp.s new file mode 100644 index 0000000..3b6f910 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/setjmp/setjmp.s @@ -0,0 +1,79 @@ +/* + standard library module: setjmp + + Long jumps. The register contents are saved in a buffer when setjmp() + is called and restored at any time when longjmp() performs the jump. + + This is based on a trick that uses pr ; the user program is resumed + after the setjmp() call when longjmp() is invoked but this is not + setjmp() that returns. longjmp() restores the pr value that was saved + by setjmp() and performs an rts instruction. + + setjmp() returns 0 when called to set up the jump point and a non-zero + value when invoked through a long jump. If 0 is given as return value + to longjmp(), then 1 is returned. +*/ + + .global _setjmp + .global _longjmp + +_setjmp: + /* Getting some free space. */ + add #64, r4 + + /* Saving general-purpose registers. */ + mov.l r15, @-r4 + mov.l r14, @-r4 + mov.l r13, @-r4 + mov.l r12, @-r4 + mov.l r11, @-r4 + mov.l r10, @-r4 + mov.l r9, @-r4 + mov.l r8, @-r4 + + /* Saving control and system registers. */ + stc.l sr, @-r4 + stc.l ssr, @-r4 + stc.l spc, @-r4 + stc.l gbr, @-r4 + stc.l vbr, @-r4 + sts.l mach, @-r4 + sts.l macl, @-r4 + sts.l pr, @-r4 + + /* This function always return 0. The cases where setjmp() seems to + return non-zero values, when a long jump has just been performed, is + actually handled by longjmp(). */ + rts + mov #0, r0 + + + +_longjmp: + /* Restoring the system and control registers. Restoring pr is actually + what performs the jump -- and makes the user program think that + setjmp() has returned. */ + lds.l @r4+, pr + lds.l @r4+, macl + lds.l @r4+, mach + ldc.l @r4+, vbr + ldc.l @r4+, gbr + ldc.l @r4+, spc + ldc.l @r4+, ssr + ldc.l @r4+, sr + + /* Restoring the general-purpose registers. */ + mov.l @r4+, r8 + mov.l @r4+, r9 + mov.l @r4+, r10 + mov.l @r4+, r11 + mov.l @r4+, r12 + mov.l @r4+, r13 + mov.l @r4+, r14 + mov.l @r4+, r15 + + /* Preventing return value from being 0 (must be at least 1). */ + tst r5, r5 + movt r0 + rts + add r5, r0 diff --git a/src/p7os/cake.exe/libgint/src/stdio/snprintf.c b/src/p7os/cake.exe/libgint/src/stdio/snprintf.c new file mode 100644 index 0000000..6c5eb20 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdio/snprintf.c @@ -0,0 +1,20 @@ +#include +#include +#include + +/* + snprintf() + Prints to a string with a size limit. +*/ +int snprintf(char *str, size_t size, const char *format, ...) +{ + va_list args; + va_start(args, format); + + int x = __printf(size, format, args); + memcpy(str, __stdio_buffer, x + 1); + + + va_end(args); + return x; +} diff --git a/src/p7os/cake.exe/libgint/src/stdio/sprintf.c b/src/p7os/cake.exe/libgint/src/stdio/sprintf.c new file mode 100644 index 0000000..f0a018e --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdio/sprintf.c @@ -0,0 +1,19 @@ +#include +#include +#include + +/* + sprintf() + Prints to a string. +*/ +int sprintf(char *str, const char *format, ...) +{ + va_list args; + va_start(args, format); + + int x = __printf(0, format, args); + memcpy(str, __stdio_buffer, x + 1); + + va_end(args); + return x; +} diff --git a/src/p7os/cake.exe/libgint/src/stdio/stdio_format.c b/src/p7os/cake.exe/libgint/src/stdio/stdio_format.c new file mode 100644 index 0000000..5a8ecfb --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdio/stdio_format.c @@ -0,0 +1,895 @@ +#include +#include + +#include +#include +#include + +/* + Internal buffer. + + Using a buffer *really* simplifies everything. But it also has + disadvantages, such as some memory loss and limited output size. + + So, in case we find a possibility to get rid of this buffer, we will + just have to change function character(), which is for now the only + function that directly accesses the buffer. +*/ +char __stdio_buffer[__stdio_buffer_size]; + + + +/* + Composed types for format definition. + + The Format structure handles everything in a format: data type, value, + alternative forms, alignment and character number, precision... there + are mainly a data type (altered by a size option), a value to print + and a number of characters. + + Other options are handled by The FormatFlags enumeration. See the + description of functions __printf() for further description on option + precedence and influence. +*/ + +enum FormatFlags +{ + // Alternatives forms add '0' and '0x' prefixes in octal and + // hexadecimal bases. (#) + Alternative = 1, + // Under specific conditions, zero-padding may be used instead of + // whitespace-padding. (0) + ZeroPadded = 2, + // Left alignment specifies that additional spaces should be added + // after the value instead of before. (-) + LeftAlign = 4, + // In numeric display, this forces a blank sign to be written before + // positive values. ( ) + BlankSign = 8, + // In numeric display, this forces an explicit sign in all cases. This + // option overrides BlankSign. (+) + ForceSign = 16 +}; + +struct Format +{ + // Format type, one of 'diouxXcs' ('eEfFgGaApnm' still to add). + char type; + // Format size, one of 'l', 'h', 'i' ('i' means 'hh'). + char size; + + // Number of characters printed. + int characters; + // Number of digits after the dot. + int precision; + + // Various flags. + enum FormatFlags flags; + + // Value to output. + union + { + // Signed int with formats %c, %d and %i. + signed int _int; + // Unsigned int with formats %o, %u, %x and %X. + unsigned int _unsigned; + // Double with formats %f, %F, %e, %E, %g and %G. +// double _double; + // String pointer with format %s. + const char *_pointer; + }; +}; + + + +//--- +// Static declarations. +//--- + +// Outputs a character in the buffer. Updates counters. +static void character(int c); +// Outputs n timers the given character. +static void character_n(int c, int n); +// Reads a format from the given string pointer address (must begin with '%'). +static struct Format get_format(const char **pointer); +// Computes the number of spaces and zeros to add to the bare output. +static void get_spacing(struct Format format, int *begin_spaces, int *sign, + int *zeros, int length, int *end_spaces); + +static void format_di (struct Format format); +static void format_u (struct Format format); +static void format_oxX (struct Format format); +// static void format_e (struct Format format); +static void format_c (struct Format format); +static void format_s (struct Format format); +static void format_p (struct Format format); + +#define abs(x) ((x) < 0 ? -(x) : (x)) + +// Number of characters currently written. +static size_t written = 0; +// Total number of function calls (characters theoretically written). +static size_t total = 0; +// Maximum number of characters to output. +static size_t max = 0; + + + +/* + character() + Outputs a character to the buffer. This function centralizes all the + buffer interface, so that if we come to remove it for property reasons, + we would just have to edit this function. + + Static variables written and total are both needed, because the + terminating NUL character may be written after the maximum has been + reached. + In other words, when the function ends, we need to have a variable + counting the current position in the buffer (written), and one other + containing the total number of theoretic characters (total) because + these two values may be different. + + Of course the three variables need to be initialized before using this + function. +*/ +static void character(int c) +{ + // If there is space left in the buffer. + if(written < max - 1) __stdio_buffer[written++] = c; + total++; +} + +/* + character_n() + Outputs n times the same character. Thought to be used to output spaces + or zeros without heavy loops. +*/ +static void character_n(int c, int n) +{ + int i = 0; + while(i++ < n) character(c); +} + +/* + get_format() + Reads the format from the given string pointer and returns a + corresponding Format structure. The string pointer points to is also + modified, so that is points to the first character after the format. + This function expects **pointer == '%'. +*/ +static struct Format get_format(const char **pointer) +{ + const char *convspec = "diouxXeEfFgGaAcspnm"; + struct Format format; + + const char *string = *pointer, *ptr; + int c, i; + + // Moving the string pointer after the '%' character. + string++; + + // Initializing structure. + format.type = 0; + format.size = 0; + format.flags = 0; + // Initializing digit counts. + format.characters = -1; + format.precision = -1; + + // Parsing the format string. Testing each character until a + // conversion specifier is found. + while((c = *string)) + { + // Looking for a conversion specifier. + ptr = strchr(convspec, c); + if(ptr) + { + format.type = *ptr; + break; + } + + // Looking for a left precision string (number of digits before + // the dot), introduced by a non-null digit. + if(c >= '1' && c <= '9') + { + format.characters = 0; + for(i = 0; i < 9 && isdigit(*string); string++) + { + format.characters *= 10; + format.characters += *string - '0'; + } + + // As pointer is now pointing to the next character, + // we want to try tests again from the beginning. + continue; + } + + // Looking for a right precision string (number of digits after + // the dot), introduced by a point. + if(c == '.') + { + string++; + if(!isdigit(*string)) continue; + + format.precision = 0; + for(i = 0; i < 9 && isdigit(*string); string++) + { + format.precision *= 10; + format.precision += *string - '0'; + } + + // As pointer is now pointing on the next character, + // we want to try tests again from the beginning. + continue; + } + + // Handling predefined characters. + switch(*string) + { + // Length modifiers. + case 'h': + format.size = 'h' + (format.size == 'h'); + break; + case 'l': + case 'L': + case 'z': + case 't': + format.size = *string; + break; + + // Flags. + case '#': + format.flags |= Alternative; + break; + case '0': + format.flags |= ZeroPadded; + break; + case '-': + format.flags |= LeftAlign; + break; + case ' ': + format.flags |= BlankSign; + break; + case '+': + format.flags |= ForceSign; + break; + } + + string++; + } + + // If the format hasn't ended, the type attribute is left to zero and + // the main loop will handle failure and break. Nothing has to be done + // here. + + *pointer = string + 1; + return format; +} + +/* + get_spacing() + Computes the arrangement of beginning spaces, sign, zeros, pure value + and ending spaces in formats. + This formatting follows a recurrent model which is centralized in this + function. Note that you can't have `begin_spaces` and `end_spaces` + both non-zero: at least one is null. +*/ +static void get_spacing(struct Format format, int *begin_spaces, int *sign, + int *zeros, int length, int *end_spaces) +{ + // Using a list of types involving a sign. + const char *signed_types = "dieEfFgGaA"; + int spaces; + // Digits represents pure output + zeros (don't mix up with the *real* + // displayed digits). + int digits; + int left = format.flags & LeftAlign; + + // Getting the total number of digits. + switch(format.type) + { + // In integer display, the number of digits output is specified in the + // precision. + case 'd': + case 'i': + case 'u': + digits = format.precision; + if(digits < length) digits = length; + break; + + // Binary display has prefixes such as '0' and '0x'. + case 'o': + case 'x': + case 'X': + digits = format.precision; + if(digits == -1) digits = length; + + if(format.flags & Alternative) + { + int hexa = (format.type == 'x' || format.type == 'X'); + digits += 1 + hexa; + length += 1 + hexa; + } + if(digits < length) digits = length; + break; + + // Other formats do not have additional zeros. + default: + digits = length; + break; + } + + if(sign) + { + if(strchr(signed_types, format.type)) + { + if(format.flags & BlankSign) *sign = ' '; + // Option '+' overrides option ' '. + if(format.flags & ForceSign) *sign = '+'; + // And of course negative sign overrides everything! + if(format.type == 'd' || format.type == 'i') + { + if(format._int < 0) *sign = '-'; + } +// else if(format._double < 0) *sign = '-'; + + } + else *sign = 0; + } + + // Computing the number of spaces. + spaces = format.characters - digits; + // Computing the number of zeros. + *zeros = digits - length; + + // Removing a space when a sign appears. + if(sign && *sign) spaces--; + + // Option '0' translates spaces to zeros, but only if no precision is + // specified; additionally, left alignment overrides zero-padding. + if(!left && format.precision == -1 && format.flags & ZeroPadded) + { + *zeros += spaces; + spaces = 0; + } + + // Setting the correct spaces number to the computed value, depending + // on the left alignment parameter. + *begin_spaces = left ? 0 : spaces; + *end_spaces = left ? spaces : 0; +} + +/* + __printf() + + Basic buffered formatted printing function. Fully-featured, so that + any call to a printf()-family function can be performed by __printf(). + + It always returns the number of characters of the theoretic formatted + output. The real output may be limited in size by the given size + argument when working with nprintf()-family functions, or the internal + buffer itself. + + The Flags structure isn't necessary, but it simplifies a lot format + argument handling (because flag effects depend on format type, which + is unknown when the flags are read). Also, length modifiers 'hh' is + stored as 'i' to simplify structure handling. 'll' is not supported. + Support for format '%lf' (C99) is planned. + + Generic information on options precedence and influence. + - Number of characters and precision represent different lengths + depending on the data type. + - '#' is independent. + - '+' overrides ' '. + - In integer display, '0' replaces spaces to zeros, only if no + precision (decimal digit number) is specified. + - '-' also overrides it, forcing whitespaces to be written at the end. + + Limits of function. + - Internal buffer size (there should be a loop to allow larger data). + - Precision values (format %a.b) are limited to 127. + + Unsupported features. + - ''' (single quote) (thousands grouping) + - 'I' (outputs locale's digits (glibc 2.2)) + - Length modifiers 'll' and 'q' (libc 5 and 4.4 BSD) + - This is not really a feature but incorrect characters in formats are + ignored and don't invalidate the format. +*/ +int __printf(size_t size, const char *string, va_list args) +{ + struct Format format; + + // Avoiding overflow by adjusting the size argument. + if(!size || size > __stdio_buffer_size) size = __stdio_buffer_size; + + // Initializing character() variables. + written = 0; + total = 0; + max = size; + + // Parsing the format string. At each iteration, a literal character, a + // '%%' identifier or a format is parsed. + while(*string) + { + // Literal text. + if(*string != '%') + { + character(*string++); + continue; + } + + // Literal '%'. + if(string[1] == '%') + { + string += 2; + character('%'); + continue; + } + + // Getting the format. + format = get_format(&string); + if(!format.type) break; + + /* Some debugging... + printf( + "Format found :%s%c%c, options %d, and %d.%d " + "digits\n", + format.size ? " " : "", + format.size ? format.size : ' ', + format.type, + format.flags, + format.digits, + format.mantissa + ); */ + + switch(format.type) + { + // Signed integers. + case 'd': + case 'i': + format._int = va_arg(args, signed int); + + // Reducing value depending on format size. + if(format.size == 'h') format._int &= 0x0000ffff; + if(format.size == 'i') format._int &= 0x000000ff; + + format_di(format); + break; + + // Unsigned integers. + case 'u': + format._unsigned = va_arg(args, unsigned int); + format_u(format); + break; + case 'o': + case 'x': + case 'X': + format._unsigned = va_arg(args, unsigned int); + format_oxX(format); + break; + +/* // Exponent notation. + case 'e': + case 'E': + format._double = va_arg(args, double); + format_e(format); + break; +*/ + // Characters. + case 'c': + format._int = va_arg(args, signed int) & 0xff; + format_c(format); + break; + + // Strings. + case 's': + format._pointer = va_arg(args, const char *); + format_s(format); + break; + + // Pointers. + case 'p': + format._unsigned = va_arg(args, unsigned int); + format_p(format); + break; + + // Character counter. + case 'n': + *va_arg(args, int *) = written; + break; + } + } + + // Adding a terminating NUL character. Function character() should have + // left an empty byte for that. + __stdio_buffer[written] = 0; + return total; +} + +/* + format_di() + + Subroutine itoa(). Writes the given signed integer to the internal + buffer, trough function character(). + It is used by conversion specifiers 'd' and 'i'. + Options '#' and '0' have no effect. +*/ +static void format_di(struct Format format) +{ + // In integer display, character number includes pure digits and + // additional zeros and spacing. + // The precision represents the number of digits (pure digits and + // zeros) to print. + // For example: ' 0004', pure digits: 1, digits: 4, characters: 5. + + int sign = 0; + signed int x = format._int; + // Using integers to store the number pure digits and additional spaces + // and zeros. + int bspaces, zeros, digits = 0, espaces; + // Using a multiplier to output digit in the correct order. + int multiplier = 1; + + // Returning if the argument is null with an explicit precision of + // zero, but only if there are no spaces. + if(!x && format.characters == -1 && !format.precision) return; + + + + //--- + // Computations. + //--- + + // Computing the number of digits and the multiplier. + x = abs(format._int); + if(!x) digits = 1; + else while(x) + { + digits++; + x /= 10; + if(x) multiplier *= 10; + } + + // Getting the corresponding spacing. + get_spacing(format, &bspaces, &sign, &zeros, digits, &espaces); + + + + //--- + // Output. + //--- + + character_n(' ', bspaces); + if(sign) character(sign); + character_n('0', zeros); + + x = abs(format._int); + // Writing the pure digits, except if the value is null with an + // explicit precision of zero. + if(x || format.precision) while(multiplier) + { + character((x / multiplier) % 10 + '0'); + multiplier /= 10; + } + + character_n(' ', espaces); +} + +/* + format_u() + Unsigned integers in base 10. Options ' ', '+' and '#' have no effect. +*/ +static void format_u(struct Format format) +{ + int bspaces, zeros, digits = 0, espaces; + int x = format._unsigned; + int multiplier = 1; + + // Computing number of digits. + if(!x) digits = 1; + else while(x) + { + digits++; + x /= 10; + if(x) multiplier *= 10; + } + + get_spacing(format, &bspaces, NULL, &zeros, digits, &espaces); + + //--- + // Output. + //--- + + character_n(' ', bspaces); + character_n('0', zeros); + + x = format._unsigned; + while(multiplier) + { + character('0' + (x / multiplier) % 10); + multiplier /= 10; + } + + character_n(' ', espaces); +} + +/* + format_oxX() + Unsigned integers in base 8 or 16. + Since the argument is unsigned, options ' ' and '+' have no effect. + Option '#' adds prefix '0' in octal or '0x' in hexadecimal. +*/ +static void format_oxX(struct Format format) +{ + // In unsigned display, the digit number specifies the minimal number + // of characters that should be output. If the prefix (alternative + // form) is present, it is part of this count. + // Integer part and decimal part digit numbers behave the same way as + // in signed integer display. + + // Using integers to store the number of digits, zeros and spaces. + int bspaces, zeros, digits = 0, espaces; + unsigned int x = format._unsigned; + int multiplier = 0, shift, mask; + int c, disp; + + + + //--- + // Computations. + //--- + + shift = (format.type == 'o') ? (3) : (4); + mask = (1 << shift) - 1; + disp = (format.type == 'x') ? (39) : (7); + + // Computing number of digits. + if(!x) digits = 1; + else while(x) + { + digits++; + x >>= shift; + if(x) multiplier += shift; + } + + // Getting the spacing distribution. + get_spacing(format, &bspaces, NULL, &zeros, digits, &espaces); + + + + //--- + // Output. + //--- + + character_n(' ', bspaces); + x = format._unsigned; + + // Writing the alternative form prefix. + if(format.flags & Alternative && x) + { + character('0'); + if(format.type != 'o') character(format.type); + } + + character_n('0', zeros); + + // Extracting the digits. + while(multiplier >= 0) + { + c = (x >> multiplier) & mask; + c += '0' + (c > 9) * disp; + + character(c); + multiplier -= shift; + } + + character_n(' ', espaces); +} + +/* + format_e() + Exponent notation. Option '#' has no effect. + +static void format_e(struct Format format) +{ + // In exponent display, the precision is the number of digits after the + // dot. + + // Using an integer to store the number exponent. + int exponent = 0; + // Using a double value for temporary computations, and another to + // store the format parameter. + double tmp = 1, x = format._double; + // Using spacing variables. Default length is for '0.e+00'; + int bspaces, zeros, sign, length = 6, espaces; + // Using an iterator and a multiplier. + int i, mul; + + + + //--- + // Computations. + //--- + + // Computing the exponent. For positive exponents, increasing until + // the temporary value gets greater than x. + if(x > 1) + { + // Looping until we haven't reached a greater exponent. + while(tmp < x) + { + // Incrementing the exponent. + exponent++; + // Multiplying the test value. + tmp *= 10; + } + // Removing an additional incrementation. + exponent--; + } + // For negative exponents, decreasing until it's lower. + else while(tmp > x) + { + // Decrementing the exponent. + exponent--; + // Dividing the test value. + tmp *= 0.1; + } + + // Adding a character if the exponent is greater that 100. + if(exponent >= 100) length++; + // Adding another one if it's greater than 1000. + if(exponent >= 1000) length++; + + // Adjusting the format precision, defaulting to 6. + if(format.precision == -1) format.precision = 6; + // Adding the decimal digits. + length += format.precision; + + // Getting the space repartition. + get_spacing(format, &bspaces, &sign, &zeros, length, &espaces); + + + + //--- + // Output. + //--- + + // Writing the beginning whitespaces. + character_n(' ', bspaces); + // Writing the sign if existing. + if(sign) character(sign); + // Writing the zeros. + character_n('0', zeros); + + // Initializing x. + x = abs(format._double) / tmp; + // Writing the first digit. + character(x + '0'); + character('.'); + + // Writing the decimal digits. + for(i = 0; i < format.precision; i++) + { + // Multiplying x by 10 and getting rid of the previous digit. + x = (x - (int)x) * 10; + // Writing the current digit. + character(x + '0'); + } + + // Writing the exponent letter and its sign. + character(format.type); + character(exponent < 0 ? '-' : '+'); + + // Getting a positive exponent. + exponent = abs(exponent); + + // Using a multiplier for the exponent. + if(exponent >= 1000) mul = 1000; + else if(exponent >= 100) mul = 100; + else mul = 10; + + // Writing the exponent characters. + while(mul) + { + // Writing the next character. + character((exponent / mul) % 10 + '0'); + // Dividing the multiplier. + mul *= 0.1; + } + + // Writing the ending whitespaces if left-aligned. + character_n(' ', espaces); +} +*/ + +/* + format_c() + Character output. Only handles left alignment and spacing. + Options '#', '0', ' ' and '+', as well as mantissa digit number, have + no effect. +*/ +static void format_c(struct Format format) +{ + // In character display, the digit number represents the number of + // characters written, including the argument and additional + // whitespaces. + + int spaces = format.characters - 1; + int left = format.flags & LeftAlign; + + if(!left) character_n(' ', spaces); + character(format._int & 0xff); + if(left) character_n(' ', spaces); +} + +/* + format_s() + String output. Spaces if needed. +*/ +void format_s(struct Format format) +{ + // In string display, the character number specify the minimum size of + // output (padded with whitespaces if needed) and the precision + // specify the maximum number of string characters output. + + int string = format.precision; + int spaces; + + const char *str = format._pointer; + int length, i; + int left = format.flags & LeftAlign; + + // Computing length of string and number of whitespaces. + length = strlen(str); + if(string > length || string == -1) string = length; + spaces = format.characters - string; + + if(!left) character_n(' ', spaces); + for(i = 0; i < string; i++) character(str[i]); + if(left) character_n(' ', spaces); +} + +/* + format_p() + Pointer output. Simple hexadecimal dump. Prints "(nil)" if pointer is + NULL. +*/ +void format_p(struct Format format) +{ + // Pointer display falls back to %#08x in the pointer is non-null, + // "(nil)" otherwise. + + unsigned int x = format._unsigned; + int bspaces, zeros, digits = 0, espaces; + int c, i; + + digits = x ? 10 : 5; + get_spacing(format, &bspaces, NULL, &zeros, digits, &espaces); + + character_n(' ', bspaces); + character_n('0', zeros); + + if(x) + { + character('0'); + character('x'); + for(i = 0; i < 8; i++) + { + c = x >> 28; + c += '0' + 39 * (c > 9); + character(c); + x <<= 4; + } + } + else + { + character('('); + character('n'); + character('i'); + character('l'); + character(')'); + } + + character_n(' ', espaces); +} diff --git a/src/p7os/cake.exe/libgint/src/stdio/vsnprintf.c b/src/p7os/cake.exe/libgint/src/stdio/vsnprintf.c new file mode 100644 index 0000000..0bfafd4 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdio/vsnprintf.c @@ -0,0 +1,15 @@ +#include +#include +#include + +/* + vsnprintf() + The most generic formatted printing function around there. +*/ +int vsnprintf(char *str, size_t size, const char *format, va_list args) +{ + int x = __printf(size, format, args); + memcpy(str, __stdio_buffer, x + 1); + + return x; +} diff --git a/src/p7os/cake.exe/libgint/src/stdio/vsprintf.c b/src/p7os/cake.exe/libgint/src/stdio/vsprintf.c new file mode 100644 index 0000000..0571fc0 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdio/vsprintf.c @@ -0,0 +1,15 @@ +#include +#include +#include + +/* + vsprintf() + Prints to a string from an argument list. +*/ +int vsprintf(char *str, const char *format, va_list args) +{ + int x = __printf(0, format, args); + memcpy(str, __stdio_buffer, x + 1); + + return x; +} diff --git a/src/p7os/cake.exe/libgint/src/stdlib/calloc.c b/src/p7os/cake.exe/libgint/src/stdlib/calloc.c new file mode 100644 index 0000000..e1b9ac9 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdlib/calloc.c @@ -0,0 +1,13 @@ +#include +#include + +/* + calloc() + Allocates 'n' elements of size 'size' and wipes the memory area. + Returns NULL on error. +*/ +void *calloc(size_t n, size_t size) +{ + void *ptr = malloc(n * size); + return ptr ? memset(ptr, 0, n * size) : NULL; +} diff --git a/src/p7os/cake.exe/libgint/src/stdlib/free.c b/src/p7os/cake.exe/libgint/src/stdlib/free.c new file mode 100644 index 0000000..b51d876 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdlib/free.c @@ -0,0 +1,20 @@ +#include + +#pragma GCC diagnostic ignored "-Wunused-parameter" + +#ifndef GINT_NO_SYSCALLS +void __free(void *ptr); +#endif + +/* + free() + Frees a memory block allocated by malloc(), calloc() or realloc(). +*/ +void free(void *ptr) +{ + #ifndef GINT_NO_SYSCALLS + __free(ptr); + #endif +} + +#pragma GCC diagnostic pop diff --git a/src/p7os/cake.exe/libgint/src/stdlib/malloc.c b/src/p7os/cake.exe/libgint/src/stdlib/malloc.c new file mode 100644 index 0000000..92366bc --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdlib/malloc.c @@ -0,0 +1,27 @@ +#include + +/* + malloc() + Allocates 'size' bytes and returns a pointer to a free memory area. + Returns NULL on error. +*/ + +#ifndef GINT_NO_SYSCALLS + +void *__malloc(size_t size); +void *malloc(size_t size) +{ + return __malloc(size); +} + +#else + +#pragma GCC diagnostic ignored "-Wunused-parameter" +void *malloc(size_t size) +{ + return NULL; +} +#pragma GCC diagnostic pop + +#endif + diff --git a/src/p7os/cake.exe/libgint/src/stdlib/realloc.c b/src/p7os/cake.exe/libgint/src/stdlib/realloc.c new file mode 100644 index 0000000..b98530e --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdlib/realloc.c @@ -0,0 +1,25 @@ +#include + +/* + realloc() + Reallocates a memory block and moves its data. +*/ + +#ifndef GINT_NO_SYSCALLS + +void *__realloc(void *ptr, size_t size); +void *realloc(void *ptr, size_t size) +{ + return __realloc(ptr, size); +} + +#else + +#pragma GCC diagnostic ignored "-Wunused-parameter" +void *realloc(void *ptr, size_t size) +{ + return NULL; +} +#pragma GCC diagnostic pop + +#endif diff --git a/src/p7os/cake.exe/libgint/src/stdlib/stdlib_abs.c b/src/p7os/cake.exe/libgint/src/stdlib/stdlib_abs.c new file mode 100644 index 0000000..3e4c4f8 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdlib/stdlib_abs.c @@ -0,0 +1,13 @@ +#include +#undef abs +#undef labs + +int abs(int x) +{ + return (x < 0) ? (-x) : x; +} + +long labs(long x) +{ + return (x < 0) ? (-x) : x; +} diff --git a/src/p7os/cake.exe/libgint/src/stdlib/stdlib_div.c b/src/p7os/cake.exe/libgint/src/stdlib/stdlib_div.c new file mode 100644 index 0000000..77f22a1 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdlib/stdlib_div.c @@ -0,0 +1,29 @@ +#include + +/* + div() + Computes the integer division of numerator by denominator. +*/ +div_t div(int numerator, int denominator) +{ + div_t result; + + result.quot = numerator / denominator; + result.rem = numerator - result.quot * denominator; + + return result; +} + +/* + ldiv() + Computes the integer division of two long integers. +*/ +ldiv_t ldiv(long numerator, long denominator) +{ + ldiv_t result; + + result.quot = numerator / denominator; + result.rem = numerator - result.quot * denominator; + + return result; +} diff --git a/src/p7os/cake.exe/libgint/src/stdlib/stdlib_rand.c b/src/p7os/cake.exe/libgint/src/stdlib/stdlib_rand.c new file mode 100644 index 0000000..d5c17a6 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/stdlib/stdlib_rand.c @@ -0,0 +1,14 @@ +#include + +static unsigned int seed = 1; + +void srand(unsigned int new_seed) +{ + seed = new_seed; +} + +int rand(void) +{ + seed = seed * 1103515245 + 12345; + return seed & 0x7fffffff; +} diff --git a/src/p7os/cake.exe/libgint/src/string/memcpy.c b/src/p7os/cake.exe/libgint/src/string/memcpy.c new file mode 100644 index 0000000..d78d1f6 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/string/memcpy.c @@ -0,0 +1,76 @@ +#include +#include + +/* + memcpy() + Copies a memory area. A smart copy is performed if possible. +*/ +void *memcpy(void *d, const void *s, size_t n) +{ + uint8_t *dest = (uint8_t *)d; + const uint8_t *src = (const uint8_t *)s; + + // A long-based copy needs the source and destination to be 4-aligned + // at the same time. + if(((intptr_t)dest & 3) == ((intptr_t)src & 3)) + { + // Getting to a long offset. + while((intptr_t)dest & 3) + { + *dest++ = *src++; + n--; + } + + // Copying groups of four bytes. + while(n >= 4) + { + *((uint32_t *)dest) = *((const uint32_t *)src); + + dest += 4, src += 4; + n -= 4; + } + + // Ending the copy. + while(n) + { + *dest++ = *src++; + n--; + } + } + + // Or we could try a word-based copy. + else if(((intptr_t)dest & 1) == ((intptr_t)src & 1)) + { + // Getting to a word offset. + if((intptr_t)dest & 1) + { + *dest++ = *src++; + n--; + } + + // Copying groups of two bytes. + while(n >= 2) + { + *((uint16_t *)dest) = *((const uint16_t *)src); + + dest += 2, src += 2; + n -= 2; + } + + // Ending the copy. + while(n) + { + *dest++ = *src++; + n--; + } + } + + // In some cases we can just perform a raw copy. + else while(n) + { + *dest++ = *src++; + n--; + } + + return d; +} diff --git a/src/p7os/cake.exe/libgint/src/string/memset.c b/src/p7os/cake.exe/libgint/src/string/memset.c new file mode 100644 index 0000000..7236516 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/string/memset.c @@ -0,0 +1,48 @@ +#include +#include + +/* + memset() + Sets the contents of a memory area. A smart copy is performed. +*/ +void *memset(void *d, int byte, size_t byte_number) +{ + uint8_t *dest = (uint8_t *)d; + unsigned short word = (byte << 8) | byte; + unsigned int longword = (word << 16) | word; + + // When the area is small, simply copying using byte operations. The + // minimum length used for long operations must be at least 3. + if(byte_number < 8) + { + while(byte_number) + { + *dest++ = byte; + byte_number--; + } + + return d; + } + + // Reaching a long offset. + while((intptr_t)dest & 3) + { + *dest++ = byte; + byte_number--; + } + // Copying using long operations. + while(byte_number >= 4) + { + *((uint32_t *)dest) = longword; + dest += 4; + byte_number -= 4; + } + // Ending the copy. + while(byte_number) + { + *dest++ = byte; + byte_number--; + } + + return d; +} diff --git a/src/p7os/cake.exe/libgint/src/string/strchr.c b/src/p7os/cake.exe/libgint/src/string/strchr.c new file mode 100644 index 0000000..7954fcf --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/string/strchr.c @@ -0,0 +1,11 @@ +#include + +/* + strchr + Searches a character in a string. +*/ +const char *strchr(const char *str, int value) +{ + while(*str && *str != value) str++; + return *str ? str : NULL; +} diff --git a/src/p7os/cake.exe/libgint/src/string/strcpy.c b/src/p7os/cake.exe/libgint/src/string/strcpy.c new file mode 100644 index 0000000..7659120 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/string/strcpy.c @@ -0,0 +1,11 @@ +#include + +/* + strcpy() + Copies a string to another. +*/ +char *strcpy(char *destination, const char *source) +{ + size_t length = strlen(source); + return memcpy(destination, source, length); +} diff --git a/src/p7os/cake.exe/libgint/src/string/strlen.c b/src/p7os/cake.exe/libgint/src/string/strlen.c new file mode 100644 index 0000000..7b5a9a1 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/string/strlen.c @@ -0,0 +1,12 @@ +#include + +/* + strlen() + Returns the length of a string. +*/ +size_t strlen(const char *str) +{ + int len = 0; + while(str[len]) len++; + return len; +} diff --git a/src/p7os/cake.exe/libgint/src/string/strncpy.c b/src/p7os/cake.exe/libgint/src/string/strncpy.c new file mode 100644 index 0000000..98422fa --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/string/strncpy.c @@ -0,0 +1,20 @@ +#include + +/* + strncpy() + Copies part of a string to another. +*/ +char *strncpy(char *destination, const char *source, size_t size) +{ + size_t length = strlen(source); + + if(length >= size) + { + return memcpy(destination, source, size); + } + else + { + memset(destination + length, 0, size - length); + return memcpy(destination, source, length); + } +} diff --git a/src/p7os/cake.exe/libgint/src/tales/tales_configuration.c b/src/p7os/cake.exe/libgint/src/tales/tales_configuration.c new file mode 100644 index 0000000..8b00345 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/tales/tales_configuration.c @@ -0,0 +1,15 @@ +#include +#include + +/* + text_configure() + Sets the font and mode to use for the following print operations. +*/ +void text_configure(struct Font *next_font, enum Color next_color) +{ + extern Font gint_font_system; + if(next_font) font = next_font; + else font = &gint_font_system; + + color = next_color; +} diff --git a/src/p7os/cake.exe/libgint/src/tales/tales_gray.c b/src/p7os/cake.exe/libgint/src/tales/tales_gray.c new file mode 100644 index 0000000..4b9b02a --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/tales/tales_gray.c @@ -0,0 +1,45 @@ +#include +#include +#include + +void operate_gray(OPERATE_ARGS) +{ + int *vl = gray_lightVRAM(); + int *vd = gray_darkVRAM(); + int vram_offset = (x >> 5) + (y << 2); + uint32_t op; + int i; + + for(i = 0; i < height; i++) + { + op = operators[i]; + + switch(color) + { + case Color_White: + vl[vram_offset] &= ~op; + vd[vram_offset] &= ~op; + break; + case Color_Light: + vl[vram_offset] |= op; + vd[vram_offset] &= ~op; + break; + case Color_Dark: + vl[vram_offset] &= ~op; + vd[vram_offset] |= op; + break; + case Color_Black: + vl[vram_offset] |= op; + vd[vram_offset] |= op; + break; + case Color_Invert: + vl[vram_offset] ^= op; + vd[vram_offset] ^= op; + break; + default: + break; + } + + vram_offset += 4; + } +} diff --git a/src/p7os/cake.exe/libgint/src/tales/tales_internals.c b/src/p7os/cake.exe/libgint/src/tales/tales_internals.c new file mode 100644 index 0000000..dbef3dd --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/tales/tales_internals.c @@ -0,0 +1,278 @@ +#include +#include +#include +#include +#include + +struct Font *font; +enum Color color; + +/* + tales_init() + Configures tales with the default font (which is part of gint). +*/ +void tales_init(void) +{ + text_configure(NULL, Color_Black); +} + +/* + getCharacterIndex() + Returns the index of a character in a font data area depending on the + font format and the size of the characters. Returns the index in the + data area, as long array, or -1 when the character does not belong to + the font format set. +*/ +int getCharacterIndex(int c) +{ + const char *data = (const char *)&font->glyphs; + int index, current; + int offset; + int width, bits; + + c &= 0x7f; + + + + // Getting the character index in the glyph array. + + if(font->format == FontFormat_Ascii) index = c; + else if(font->format == FontFormat_Print) index = c - 32; + + else switch(font->format) + { + case FontFormat_Numeric: + if(!isdigit(c)) return -1; + index = c - '0'; + break; + case FontFormat_LowerCase: + if(!islower(c)) return -1; + index = c - 'a'; + break; + case FontFormat_UpperCase: + if(!isupper(c)) return -1; + index = c - 'A'; + break; + case FontFormat_Letters: + if(!isalpha(c)) return -1; + index = c - 'A' - ('a' - 'z') * (c >= 'a'); + break; + case FontFormat_Common: + if(!isalnum(c)) return -1; + index = c - '0' - ('A' - '9') * (c >= 'A') - + ('a' - 'z') * (c >= 'a'); + break; + case FontFormat_Unknown: + default: + return -1; + } + + + + // Reaching the character offset. + + current = index & ~7; + offset = font->index[current >> 3]; + + while(current < index) + { + width = data[offset << 2]; + bits = font->data_height * width + 8; + + offset += (bits + 31) >> 5; + current++; + } + + return offset; +} + +/* + operate() + Operates on the vram using the given operators. The x-coordinate should + be a multiple of 32. There should be `height` operators. +*/ +void operate_mono(OPERATE_ARGS) +{ + int *vram = display_getCurrentVRAM(); + int vram_offset = (x >> 5) + (y << 2); + uint32_t op; + int i; + + for(i = 0; i < height; i++) + { + op = operators[i]; + + switch(color) + { + case Color_White: + vram[vram_offset] &= ~op; + break; + case Color_Black: + vram[vram_offset] |= op; + break; + case Color_Invert: + vram[vram_offset] ^= op; + break; + default: + break; + } + + vram_offset += 4; + } +} + +/* + update() + Updates the operators using the given glyph. The operation will not be + complete if there are not enough bits available in the operator data. + In this case the offset will become negative, which means that the + calling procedure has to call operate() and re-call update(). + `available` represents the number of free bits in the operators (lower + bits). + Returns the number of bits available after the operation. If it's + negative, call operate() and update() again. +*/ +int update(uint32_t *operators, int height, int available, + uint32_t *glyph) +{ + // Glyph width. + int width = glyph[0] >> 24; + int i; + + // The glyph mask extracts 'width' bits at the left. The partial mask + // is used when there are less than 'width' bits available in the + // current data longword. + uint32_t glyph_mask = 0xffffffff << (32 - width); + uint32_t partial_mask; + + int shift; + uint32_t line; + + // Current data longword, next data array index, and number of bits + // still available in 'data'. + uint32_t data = glyph[0] << 8; + int data_index = 1; + int bits_available = 24; + + for(i = 0; i < height; i++) + { + shift = 32 - available; + + // Getting the next 'width' bits. In some cases these bits will + // intersect two different longs. + line = data & glyph_mask; + line = (shift >= 0) ? (line >> shift) : (line << -shift); + operators[i] |= line; + + data <<= width; + bits_available -= width; + + // Continue until they do. + if(bits_available >= 0) continue; + + // Computing a special mask that extracts just the number of + // bits missing, and loading a new data longword. + partial_mask = 0xffffffff << (32 + bits_available); + data = glyph[data_index++]; + shift += width + bits_available; + + if(shift <= 31) + { + line = data & partial_mask; + line = (shift >= 0) ? (line >> shift) : + (line << -shift); + operators[i] |= line; + } + + data <<= -bits_available; + bits_available += 32; + } + + return available - width; +} + +/* + render() + Renders text without any formatting analysis, using the given operation + function. +*/ +void render(int x, int y, const char *str, void (*op)(OPERATE_ARGS)) +{ + // Operator data, and number of available bits in the operators (which + // is the same for all operators, since they are treated equally). + uint32_t *operators; + int available; + + // Raw glyph data, each glyph being represented by one or several + // longwords, and an index in this array. + uint32_t *data = (uint32_t *)font->glyphs; + int index; + + // Height of each glyph. This value is constant because the storage + // format requires it: it allows greater optimization. + int height; + + int i; + + + + if(!font) return; + + // Allocating data. There will be one operator for each line. + height = font->data_height; + if(x > 127 || y > 63 || y <= -height) return; + if(y + height > 64) height = 64 - y; + + operators = alloca(height * sizeof(uint32_t)); + for(i = 0; i < height; i++) operators[i] = 0; + if(!operators) return; + + // Computing the initial operator offset to have 32-aligned operators. + // This allows to write directly video ram longs instead of having to + // shift operators, and do all the vram operation twice. + available = 32 - (x & 31); + x &= ~31; + + // Displaying character after another. + while(*str) + { + index = getCharacterIndex(*str++); + if(index < 0) continue; + + // Updating the operators. + available = update(operators, height, available, data + index); + + // Continue until operators are full (this includes an + // additional bit to add a space between each character). + if(available > 1) + { + available--; + continue; + } + + // When operators are full, updating the video ram and + // preparing the operators for another row. + + (*op)(operators, height, x, y); + x += 32; + if(x > 96) break; + + memset(operators, 0, height << 2); + if(available >= 0) + { + available = 31 + available; + continue; + } + + // Finishing update, in case it has been only partially done, + // because there was not enough bits available to fit all the + // information. Also adding a space, assuming that characters + // aren't more than 30 bits wide. + available += 32 + (data[index] >> 24); + available = update(operators, height, available, data + index); + available--; + } + + // Final operation. + if(x <= 96 && available < 32) (*op)(operators, height, x, y); +} diff --git a/src/p7os/cake.exe/libgint/src/tales/tales_print.c b/src/p7os/cake.exe/libgint/src/tales/tales_print.c new file mode 100644 index 0000000..be3d107 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/tales/tales_print.c @@ -0,0 +1,33 @@ +#include +#include +#include + +/* + dprint() + Prints a formatted string. Works the same as printf(). +*/ +void dprint(int x, int y, const char *format, ...) +{ + va_list args; + + va_start(args, format); + __printf(0, format, args); + va_end(args); + + dtext(x, y, __stdio_buffer); +} + +/* + gprint() + Prints a formatted string. Works the same as printf(). +*/ +void gprint(int x, int y, const char *format, ...) +{ + va_list args; + + va_start(args, format); + __printf(0, format, args); + va_end(args); + + gtext(x, y, __stdio_buffer); +} diff --git a/src/p7os/cake.exe/libgint/src/tales/tales_text.c b/src/p7os/cake.exe/libgint/src/tales/tales_text.c new file mode 100644 index 0000000..3729f7d --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/tales/tales_text.c @@ -0,0 +1,20 @@ +#include +#include + +/* + dtext() + Prints the given string, without any analysis. +*/ +void dtext(int x, int y, const char *str) +{ + render(x, y, str, operate_mono); +} + +/* + gtext() + Prints the given raw string. +*/ +void gtext(int x, int y, const char *str) +{ + render(x, y, str, operate_gray); +} diff --git a/src/p7os/cake.exe/libgint/src/time/asctime.c b/src/p7os/cake.exe/libgint/src/time/asctime.c new file mode 100644 index 0000000..ed3d0a3 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/time/asctime.c @@ -0,0 +1,57 @@ +#include + +static char str[26]; + +/* + asctime() + Converts broken-down time to string representation on the form + "Wed Jun 30 21:49:08 1993\n". The returned string is statically + allocated and may be overwritten by any subsequent call to a time + function. +*/ +char *asctime(const struct tm *time) +{ + const char *days[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }, *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" + }; + int year = time->tm_year + 1900; + + str[0] = days[time->tm_wday][0]; + str[1] = days[time->tm_wday][1]; + str[2] = days[time->tm_wday][2]; + str[3] = ' '; + + str[4] = months[time->tm_mon][0]; + str[5] = months[time->tm_mon][1]; + str[6] = months[time->tm_mon][2]; + str[7] = ' '; + + str[8] = '0' + (time->tm_mday / 10); + str[9] = '0' + (time->tm_mday % 10); + str[10] = ' '; + + str[11] = '0' + (time->tm_hour / 10); + str[12] = '0' + (time->tm_hour % 10); + str[13] = ':'; + str[14] = '0' + (time->tm_min / 10); + str[15] = '0' + (time->tm_min % 10); + str[16] = ':'; + str[17] = '0' + (time->tm_sec / 10); + str[18] = '0' + (time->tm_sec % 10); + str[19] = ' '; + + str[20] = '0' + (year / 1000); + year %= 1000; + str[21] = '0' + (year / 100); + year %= 100; + str[22] = '0' + (year / 10); + str[23] = '0' + (year % 10); + + str[24] = '\n'; + str[25] = 0; + + return str; +} diff --git a/src/p7os/cake.exe/libgint/src/time/ctime.c b/src/p7os/cake.exe/libgint/src/time/ctime.c new file mode 100644 index 0000000..f3768e0 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/time/ctime.c @@ -0,0 +1,13 @@ +#include + +/* + ctime() + Converts calendar time to string representation on the form + "Wed Jun 30 21:49:08 1993\n". The returned string is statically + allocated and may be overwritten by any subsequent call to a time + function. +*/ +char *ctime(const time_t *timer) +{ + return asctime(gmtime(timer)); +} diff --git a/src/p7os/cake.exe/libgint/src/time/gmtime.c b/src/p7os/cake.exe/libgint/src/time/gmtime.c new file mode 100644 index 0000000..4d84587 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/time/gmtime.c @@ -0,0 +1,45 @@ +#include +#include +#include + +static struct tm tm; + +/* + gmtime() + Converts calendar time to broken-down time. The returned pointer is + statically allocated and may be overwritten by any subsequent call to + a time function. +*/ +struct tm *gmtime(const time_t *timeptr) +{ + time_t t = *timeptr; + div_t d; + int sec; + + tm.tm_year = 1970; + tm.tm_mon = 0; + + sec = daysInMonth(tm.tm_mon, tm.tm_year) * 24 * 3600; + while(t >= sec) + { + t -= sec; + if(++tm.tm_mon == 12) + { + tm.tm_year++; + tm.tm_mon = 0; + } + sec = daysInMonth(tm.tm_mon, tm.tm_year) * 24 * 3600; + } + tm.tm_year -= 1900; + + d = div(sec, 24 * 3600); + tm.tm_mday = d.quot; + d = div(d.rem, 3600); + tm.tm_hour = d.quot; + d = div(d.rem, 60); + tm.tm_min = d.quot; + tm.tm_sec = d.rem; + + mktime(&tm); + return &tm; +} diff --git a/src/p7os/cake.exe/libgint/src/time/mktime.c b/src/p7os/cake.exe/libgint/src/time/mktime.c new file mode 100644 index 0000000..928cf6f --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/time/mktime.c @@ -0,0 +1,68 @@ +#include +#include + +/* + mktime() + Converts broken-down time to calendar time. Computes structure fields + tm_wday and tm_yday using the other fields. Member structures outside + their range are normalized (e.g. 40 October becomes 9 November) and + tm_isdst is set. +*/ +time_t mktime(struct tm *time) +{ + int leaps, yr; + int days, i; + + // Normalizing time. + time->tm_min += (time->tm_sec / 60); + time->tm_hour += (time->tm_min / 60); + time->tm_mday += (time->tm_hour / 24); + time->tm_sec %= 60; + time->tm_min %= 60; + time->tm_hour %= 24; + + // Normalizing date. + days = daysInMonth(time->tm_mon, time->tm_year + 1900); + while(time->tm_mday >= days) + { + time->tm_mday -= days; + if(++time->tm_mon == 12) + { + time->tm_mon = 0; + time->tm_year++; + } + days = daysInMonth(time->tm_mon, time->tm_year + 1900); + } + + // Setting the year day. + days = 0; + for(i = 0; i < time->tm_mon; i++) + days += daysInMonth(i, time->tm_year + 1900); + time->tm_yday = days + time->tm_mday; + + // Setting the week day. The calendar is periodic over 400 years and + // 1601-01-01 was a Monday. + + // Years completely elapsed since last 400n + 1 year (1601-2001-etc). + yr = (time->tm_year + 1900 - 1) % 400; + // Leap years in these yr years. + leaps = (yr / 4) - (yr >= 100) - (yr >= 200) - (yr >= 300); + // Days completely elapsed since last 400n + 1 year, 01-01. + days = 365 * yr + leaps + time->tm_yday; + // Current day of week (1 means Monday 1601-01-01). + time->tm_wday = (1 + days) % 7; + + // This RTC does not seem to have any DST feature. + time->tm_isdst = 0; + + if(time->tm_year + 1900 < 1970) return (time_t)-1; + + // 134774 is the number of days between 1601-01-01 and 1970-01-01. Thus + // days become the number of days elapsed since 1970-01-01. + days -= 134774; + // days may become negative, so add the calendar period. + if(days < 0) days += 146097; + + return (time_t)((24 * 3600) * days + 3600 * time->tm_hour + + 60 * time->tm_min + time->tm_sec); +} diff --git a/src/p7os/cake.exe/libgint/src/time/time.c b/src/p7os/cake.exe/libgint/src/time/time.c new file mode 100644 index 0000000..16189d4 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/time/time.c @@ -0,0 +1,29 @@ +#include +#include + +/* + time() + Returns the current time as calendar time. If you need a broken-down + time, either use the RTC API or gmtime(). However, this function is + already based on mktime() (for hardware reasons) so it would be much + faster to use the RTC API if possible. + If timeptr is not NULL, it is set to the current time, that is, the + value that is returned. +*/ +time_t time(time_t *timeptr) +{ + struct RTCTime rtc = rtc_getTime(); + struct tm tm; + time_t calendar; + + tm.tm_sec = rtc.seconds; + tm.tm_min = rtc.minutes; + tm.tm_hour = rtc.hours; + tm.tm_mday = rtc.month_day; + tm.tm_mon = rtc.month; + tm.tm_year = rtc.year - 1900; + + calendar = mktime(&tm); + if(timeptr) *timeptr = calendar; + return calendar; +} diff --git a/src/p7os/cake.exe/libgint/src/time/time_misc.c b/src/p7os/cake.exe/libgint/src/time/time_misc.c new file mode 100644 index 0000000..88e01fc --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/time/time_misc.c @@ -0,0 +1,21 @@ +#include +#undef difftime + +/* + clock() + Should return elapsed CPU time since beginning of program execution. + This is currently not implemented and returns -1. +*/ +clock_t clock(void) +{ + return (clock_t)-1; +} + +/* + difftime() + Returns the number of seconds between the given points. +*/ +double difftime(time_t end, time_t beginning) +{ + return (double)(end - beginning); +} diff --git a/src/p7os/cake.exe/libgint/src/time/time_util.c b/src/p7os/cake.exe/libgint/src/time/time_util.c new file mode 100644 index 0000000..11c7048 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/time/time_util.c @@ -0,0 +1,28 @@ +#include + +/* + isLeap() + Determines whether the given year is a leap year. +*/ +int isLeap(int year) +{ + int leap = !(year & 3); // Take multiples of 4 + if(!(year % 100)) leap = 0; // Remove multiples of 100 + if(!(year % 400)) leap = 1; // Take multiples of 400 + + return leap; +} + +/* + daysInMonth() + Returns number of days for the given month (between 0 and 11) and year. +*/ +int daysInMonth(int month, int year) +{ + int days[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + + if(month != 1) return days[month]; + return days[month] + isLeap(year); +} diff --git a/src/p7os/cake.exe/libgint/src/timer/timer_get.c b/src/p7os/cake.exe/libgint/src/timer/timer_get.c new file mode 100644 index 0000000..9174164 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/timer/timer_get.c @@ -0,0 +1,25 @@ +#include +#include + +/* + timer_get() + Returns the timer and TSTR register addresses. +*/ +void timer_get(int timer, volatile struct mod_tmu **tmu, + volatile unsigned char **tstr) +{ + // Using SH7705 information for SH-3-based MPUs. + if(isSH3()) + { + if(tstr) *tstr = (volatile unsigned char *)0xfffffe92; + if(tmu) *tmu = (volatile struct mod_tmu *) + (0xfffffe94 + 12 * timer); + } + // Assuming SH7305 by default. + else + { + if(tstr) *tstr = (volatile unsigned char *)0xa4490004; + if(tmu) *tmu = (volatile struct mod_tmu *) + (0xa4490008 + 12 * timer); + } +} diff --git a/src/p7os/cake.exe/libgint/src/timer/timer_interrupt.c b/src/p7os/cake.exe/libgint/src/timer/timer_interrupt.c new file mode 100644 index 0000000..7dd91e4 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/timer/timer_interrupt.c @@ -0,0 +1,28 @@ +#include +#include + +#include + +struct Timer timers[3] = { { NULL, 0 }, { NULL, 0 }, { NULL, 0 } }; + +/* + timer_interrupt() + Handles the interrupt for the given timer. +*/ +void timer_interrupt(int timer) +{ + volatile struct mod_tmu *tmu; + timer_get(timer, &tmu, NULL); + + // Resetting the interrupt flag. + tmu->TCR.UNF = 0; + + // Calling the callback function. + if(timers[timer].callback) timers[timer].callback(); + + // Reducing the number of repetitions left, if not infinite. + if(!timers[timer].repeats) return; + // And stopping it if necessary. + if(timers[timer].repeats == 1) timer_stop(timer); + else timers[timer].repeats--; +} diff --git a/src/p7os/cake.exe/libgint/src/timer/timer_reload.c b/src/p7os/cake.exe/libgint/src/timer/timer_reload.c new file mode 100644 index 0000000..8cc047e --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/timer/timer_reload.c @@ -0,0 +1,22 @@ +#include +#include + +/* + timer_reload() + Reloads the given timer with the given constant. Starts the timer if + it was stopped. +*/ +void timer_reload(int timer, int new_delay) +{ + volatile struct mod_tmu *tmu; + volatile unsigned char *tstr; + int byte = (1 << timer); + timer_get(timer, &tmu, &tstr); + + // Setting the constant and the delay. + tmu->TCOR = new_delay; + tmu->TCNT = new_delay; + + // Starting the timer. + *tstr |= byte; +} diff --git a/src/p7os/cake.exe/libgint/src/timer/timer_start.c b/src/p7os/cake.exe/libgint/src/timer/timer_start.c new file mode 100644 index 0000000..6b7aa1e --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/timer/timer_start.c @@ -0,0 +1,35 @@ +#include +#include + +/* + timer_start() + Configures and starts a timer. +*/ +void timer_start(int timer, int delay, int prescaler, void (*callback)(void), + int repeats) +{ + volatile struct mod_tmu *tmu; + volatile unsigned char *tstr; + int byte = (1 << timer); + + timer_get(timer, &tmu, &tstr); + + // Loading the counter, the constant and the prescaler/ + tmu->TCOR = delay; + tmu->TCNT = delay; + tmu->TCR.TPSC = prescaler; + + // Resetting underflow flag and enabling interruptions. + tmu->TCR.UNF = 0; + tmu->TCR.UNIE = 1; + + // Counting on rising edge (ignored on SH7305). + tmu->TCR.CKEG = 0; + + // Loading the structure information. + timers[timer].callback = callback; + timers[timer].repeats = repeats; + + // Starting the timer. + *tstr |= byte; +} diff --git a/src/p7os/cake.exe/libgint/src/timer/timer_stop.c b/src/p7os/cake.exe/libgint/src/timer/timer_stop.c new file mode 100644 index 0000000..083c4a4 --- /dev/null +++ b/src/p7os/cake.exe/libgint/src/timer/timer_stop.c @@ -0,0 +1,18 @@ +#include +#include + +#include + +/* + timer_stop() + Stops the given timer. This function may be called even if the timer is + not running. +*/ +void timer_stop(int timer) +{ + volatile unsigned char *tstr; + int byte = (1 << timer); + + timer_get(timer, NULL, &tstr); + *tstr &= ~byte; +} diff --git a/src/p7os/cake.exe/osupd.ld b/src/p7os/cake.exe/osupd.ld new file mode 100644 index 0000000..6743064 --- /dev/null +++ b/src/p7os/cake.exe/osupd.ld @@ -0,0 +1,101 @@ +/* + This linker script links the object files when generating the ELF output. + `romdata`, `[be]bss`, `[be]data` symbols are used in the runtime + initialization routine (crt0.c) to initialize the application. + + Two RAM areas are specified. The "real ram" is accessed directly while the + other area is virtualized. It is not possible to execute code in + virtualized ram -- for an add-in, I don't know if this is also the case + for the UpdateExe, so I'll just take one part of the RAM. + + An end block is located at the end of the binary - it's in the `end` + section. +*/ + +OUTPUT_ARCH(sh3) +ENTRY(_start) + +MEMORY +{ + /* http://bible.planet-casio.com/simlo/chm/v20/CommunicationsProtocol.htm */ + rom : o = 0x88030000, l = 64k + ram : o = 0x08024000, l = 40k + realram : o = 0x0802e000, l = 8k +} + +SECTIONS +{ + /* ROM sections : binary code and read-only data */ + .text : { + *(.pretext.entry) + *(.pretext) + + _bctors = . ; + *(.ctors) + _ectors = . ; + _bdtors = . ; + *(.dtors) + _edtors = . ; + + *(.text) + *(.text.*) + } > rom + + .rodata : { + *(.rodata.fxconv) + *(.rodata) + *(.rodata.*) + + _romdata = ALIGN(4) ; + } > rom + + /* RAM sections : bss and rw data */ + .bss : { + _bbss = . ; + *(.bss) + _ebss = . ; + } > ram + + .data : AT(_romdata) ALIGN(4) { + _bdata = . ; + *(.data) + *(.data.*) + _edata = . ; + } > ram + + .cc : AT(_romdata + SIZEOF(.data)) ALIGN(4) { + *(.eh_frame) + *(.jcr) + + _gint_data = _romdata + SIZEOF(.data) + SIZEOF(.cc) ; + } > ram + + /* Real RAM: interrupt, exception and TLB miss handlers */ + .gint : AT(_gint_data) { + /* The vbr needs to be 0x100-aligned because of an ld issue. */ + . = ALIGN(0x100) ; + _gint_vbr = . ; + _bgint = . ; + + /* Exception handler. */ + . = _gint_vbr + 0x100 ; + *(.gint.exc.entry) + *(.gint.exc) + + /* TLB miss handler. */ + . = _gint_vbr + 0x400 ; + *(.gint.tlb.entry) + *(.gint.tlb) + + /* Interrupt handler. */ + . = _gint_vbr + 0x600 ; + *(.gint.int.entry) + *(.gint.int) + + _egint = . ; + } > realram + + .end : AT(_gint_data + SIZEOF(.gint)) { + *(.end) + } > rom +} diff --git a/src/p7os/cake.exe/src/endblock.c b/src/p7os/cake.exe/src/endblock.c new file mode 100644 index 0000000..8233702 --- /dev/null +++ b/src/p7os/cake.exe/src/endblock.c @@ -0,0 +1,26 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* endblock.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: cake.exe | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 18:05:41 |___/ */ +/* */ +/* ************************************************************************** */ +/** + * endblock: + * End block. + * + * "CASIO COMPUTER CO., LTD." and "CESG502" separated with a transmission + * escaper, where all characters occupy two bytes. + * This block is required to check if the uploaded binary is valid. + * + * Simon Lothar's documentation says the byte after the escape character + * is 0x03, this is not a mistake (if you was wondering). + */ + +extern char endblock[] __attribute__((section(".end"))); +char endblock[] = +"C\0A\0S\0I\0O\0 \0C\0O\0M\0P\0U\0T\0E\0R\0 \0C\0O\0.\0,\0 \0L\0T\0D\0.\0" +"\x10\3" +"C\0E\0S\0G\0""5\0""0\0""2"; diff --git a/src/p7os/cake.exe/src/main.c b/src/p7os/cake.exe/src/main.c new file mode 100644 index 0000000..cfe0647 --- /dev/null +++ b/src/p7os/cake.exe/src/main.c @@ -0,0 +1,40 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* main.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: cake.exe | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 18:05:41 |___/ */ +/* */ +/* ************************************************************************** */ + +#include +#include +#include +#include + +/* reboot like an update.exe - that means re-running the bootcode */ +static void (*reboot)(void) = (void*)0xa0000000; + +/** + * main: + * User-friendly entry point of the program. + */ + +int main(void) +{ + /* first display */ + dclear(); + dtext(1, 1, "CAKE.EXE"); + dupdate(); + + /* wait for user to press on EXIT */ + while (1) { + int key = getkey(); + if (key == KEY_EXIT) + break; + } + + /* we're done */ + (*reboot)(); +} diff --git a/src/p7os/main.c b/src/p7os/main.c new file mode 100644 index 0000000..31c743a --- /dev/null +++ b/src/p7os/main.c @@ -0,0 +1,188 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* p7os/main.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 23:55:54 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include + +/* ************************************************************************** */ +/* Error messages */ +/* ************************************************************************** */ +/* Couldn't initialize connexion to calculator. */ +static const char error_noconnexion[] = +"Could not connect to the calculator.\n" +"- Is it plugged in and in Receive mode/OS Update?\n" +"- Have you tried changing the cable ?\n"; + +/* Calculator was found but program wasn't allowed to communicate with it. */ +static const char error_noaccess[] = +"Could not get access to the calculator.\n" +"Install the appropriate udev rule, or run as root.\n"; + +/* The calculator acted in a weird way. */ +static const char error_unplanned[] = +"The calculator didn't act as planned: %s.\n" +"Stop receive mode on calculator and start it again before re-running " \ + QUOTE(BIN) ".\n"; + +/* Unsupported operation -> OS Update, not receive mode! */ +static const char error_unsupported[] = +"Required operation was unsupported by the calculator.\n" +"If you did not prepare, perhaps you should prepare?\n"; + +/* ************************************************************************** */ +/* Auxiliary functions */ +/* ************************************************************************** */ +/** + * osdisp: + * Nice little loading bar. + * + * Taken from `src/p7/main.c`. + * "Initialization" is when id > total (called in main). + * + * @arg id data packet ID. + * @arg total total number of packets. + */ + +static int osdisp_init = 0; +static void osdisp(p7ushort_t id, p7ushort_t total) +{ + /* here's the buffer */ + static char buf[50] = + "\r|---------------------------------------| 00.00%"; + static char *bar = &buf[2]; + + /* initialize */ + static int pos; + + /* if is initialize, fill */ + if (id > total) { + pos = 0; + /* indicate that is has been initialized */ + osdisp_init = 1; + /* put initial buffer */ + fputs(buf, stdout); + /* save cursor position */ + fputs("\x1B[s", stdout); + /* we're done */ + return ; + } + + /* id and total start from 1, let them start from zero */ + id--; total--; + + /* modify buffer */ + /* - # - */ + int current = 38 * id / total; + while (pos <= current) bar[pos++] = '#'; + /* - % - */ + unsigned int percent = 10000 * id / total; + sprintf(&buf[43], "%02u.%02u", percent / 100, percent % 100); + + /* put it */ + fputs(buf, stdout); + /* force cursor position */ + fputs("\x1B""8", stdout); +} + +/* ************************************************************************** */ +/* Main function */ +/* ************************************************************************** */ +/** + * main: + * User entry point of the program. + * + * @arg ac arguments count + * @arg av arguments values + * @return return code (0 if OK) + */ + +#define initflags (P7_ACTIVE | P7_CHECK | P7_TERM) +int main(int ac, char **av) +{ + /* parse args */ + args_t args; + if (parse_args(ac, av, &args)) + return (0); + + /* Initialize libp7 and communication */ + p7_handle_t *handle = NULL; int err; + if (args.com) err = p7_cominit(&handle, initflags, args.com); + else err = p7_init(&handle, initflags); + if (err) goto fail; + + /* prepare */ + if (!args.noprepare) { + /* make the preparation thing */ + printf("Uploading the Update.Exe.\n"); + if ((err = prepare_ops(handle, args.uexe, osdisp))) + goto fail; + if (osdisp_init) { + osdisp_init = 0; + puts("\b\b\b\b\b\bTransfer complete."); + } + handle = NULL; + + /* was only about preparing? */ + if (args.menu == mn_prepare_only) + return (0); + + /* sleep a little, in case */ + printf("Waiting for the Update.Exe to be setup...\n"); + sleep(1); + + /* re-open the handle */ + if (args.com) err = p7_cominit(&handle, initflags, args.com); + else err = p7_init(&handle, initflags); + if (err) { + p7_exit(handle); + goto fail; + } + } + + /* check according to menu */ + switch (args.menu) { + /* backup the thing menu */ + case mn_get: + /* get the os */ + printf("Gathering the OS...\n"); + err = p7_backup_romfile(handle, args.local, osdisp); + if (err) goto fail; + fclose(args.local); + break; + } + + /* exit libp7 */ + p7_exit(handle); + + /* then we're good */ + return (0); + +fail: + /* interrupt loading bar */ + if (osdisp_init) + puts("\b\b\b\b\b\bError !"); + + /* displaying error */ + if (err > 0) switch (err) { + case p7_error_nocalc: log(error_noconnexion); break; + case p7_error_noaccess: log(error_noaccess); break; + case p7_error_unsupported: log(error_unsupported); break; + default: log(error_unplanned, p7_strerror(err)); + } + + /* closing the handle */ + p7_exit(handle); + + /* closing the file, removing if necessary */ + if (args.localpath) { + fclose(args.local); + remove(args.localpath); + } + return (1); +} diff --git a/src/p7os/main.h b/src/p7os/main.h new file mode 100644 index 0000000..733ab86 --- /dev/null +++ b/src/p7os/main.h @@ -0,0 +1,48 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* p7os/main.h |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 23:55:55 |___/ */ +/* */ +/* ************************************************************************** */ +#ifndef MAIN_H +# define MAIN_H +# include +# include +# define Q(x) #x +# define QUOTE(x) Q(x) +# define log(S, ...) fprintf(stderr, S, ##__VA_ARGS__) + +/* ************************************************************************** */ +/* CLI options */ +/* ************************************************************************** */ +/* Menu */ +# define mn_prepare_only 1 +# define mn_get 2 + +/* Arguments */ +typedef struct { + /* basic things */ + int menu; + + /* communication and tweaks */ + int com, noprepare; + FILE *uexe; + + /* others */ + FILE *local; const char *localpath; +} args_t; + +/* Parsing function */ +int parse_args(int ac, char **av, args_t *args); + +/* ************************************************************************** */ +/* Actual things */ +/* ************************************************************************** */ +/* Main functions */ +int prepare_ops(p7_handle_t *handle, FILE *uexe, void (*disp)()); +int get_os(p7_handle_t *handle, FILE *dest); + +#endif /* MAIN_H */ diff --git a/src/p7os/prepare.c b/src/p7os/prepare.c new file mode 100644 index 0000000..4523e01 --- /dev/null +++ b/src/p7os/prepare.c @@ -0,0 +1,68 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* p7os/prepare.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 23:56:41 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" + +/* ************************************************************************** */ +/* Error messages */ +/* ************************************************************************** */ +/* Unable to open the embedded thingy */ +static const char error_fmemopen[] = +"Unable to open the embedded update.exe.\n"; + +/* ************************************************************************** */ +/* Embedded update.exe */ +/* ************************************************************************** */ +#define cake_exe_str (_binary_cake_exe_bin_start) +#define cake_exe_end (_binary_cake_exe_bin_end) +extern char _binary_cake_exe_bin_start[]; +extern char _binary_cake_exe_bin_end[]; + +/* ************************************************************************** */ +/* Main function */ +/* ************************************************************************** */ +/** + * prepare_ops: + * Prepare the operation, by uploading the update.exe. + * + * @arg handle the libp7 handle. + * @arg uexe the update.exe to use (NULL if use the embedded one). + * @return the error (-1 if not a libp7 error, 0 if ok) + */ + +int prepare_ops(p7_handle_t *handle, FILE *uexe, void (*disp)()) +{ + int err; size_t usize; + + /* prepare the update.exe */ + if (uexe) { + /* calculate the size */ + fseek(uexe, 0, SEEK_END); + usize = ftell(uexe); + fseek(uexe, 0, SEEK_SET); + } else { + /* take the default uexe */ + usize = (size_t)&cake_exe_end - (size_t)&cake_exe_str; + uexe = fmemopen(cake_exe_str, usize, "r"); + if (!uexe) { + fprintf(stderr, error_fmemopen); + return (-1); + } + } + + /* send the thing */ + if ((err = p7_sendexe_file(handle, uexe, 0x88030000, 0x88030000, disp))) { + fclose(uexe); + return (err); + } + + /* no error! */ + fclose(uexe); + return (0); +} diff --git a/src/p7os/vars.mk b/src/p7os/vars.mk new file mode 100755 index 0000000..3cc5551 --- /dev/null +++ b/src/p7os/vars.mk @@ -0,0 +1,4 @@ +#!/usr/bin/make -f +disable: +libs: + @echo libp7 diff --git a/src/p7screen/args.c b/src/p7screen/args.c new file mode 100644 index 0000000..2f6a55a --- /dev/null +++ b/src/p7screen/args.c @@ -0,0 +1,135 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* p7screen/args.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 23:55:55 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#include +#include + +/* ************************************************************************** */ +/* Help and version messages */ +/* ************************************************************************** */ +/* Version message */ +static const char version_message[] = +QUOTE(BIN) " - from " QUOTE(NAME) " v" QUOTE(VERSION) " (licensed under GPLv2)\n" +"Maintained by " QUOTE(MAINTAINER) ".\n" +"\n" +"This is free software; see the source for copying conditions.\n" +"There is NO warranty; not even for MERCHANTABILITY or\n" +"FITNESS FOR A PARTICULAR PURPOSE."; + +/* Help message */ +static const char help_main[] = +"Usage: " QUOTE(BIN) " [--help|-h] [--version|-v]\n" +" [--com ]\n" +"\n" +"Displays the streamed screen from a CASIO fx calculator.\n" +"\n" +"Options are:\n" +" -h, --help Display this help page\n" +" -v, --version Displays the version\n" +" --com The USB-serial port, if you want to communicate with a\n" +" calculator connected using a USB-to-serial cable. (1 to 20)\n" +" If this option isn't used, the program will look for a\n" +" directly connected USB calculator.\n" +" -z ZOOM Change the zoom (1 to 16)\n" +" By default, the zoom will be " QUOTE(DEFAULT_ZOOM) ".\n" +"\n" +"Report bugs to " QUOTE(MAINTAINER) "."; + +/* ************************************************************************** */ +/* Main function */ +/* ************************************************************************** */ +/** + * parse_args: + * Args parsing main function. + * + * Inspired of the edits of my first experiment with getopt. + * Interesting, huh? + * + * @arg ac the arguments count + * @arg av the arguments values + * @arg device pointer to the device + * @arg zoom pointer the zoom + * @arg args the parsed args pointer + * @return 0 if ok, other if not. + */ + +int parse_args(int ac, char **av, int *com, int *zoom) +{ + /* initialize args */ + *com = 0; + *zoom = DEFAULT_ZOOM; + + /* define options */ + const char short_options[] = "hvz:"; + const struct option long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {"com", required_argument, NULL, 'c'}, + {"zoom", required_argument, NULL, 'z'}, + {NULL, 0, NULL, 0} + }; + + /* get all options */ + int c; opterr = 0; + int help = 0, version = 0; + const char *s_com = NULL; + while ((c = getopt_long(ac, av, short_options, long_options, NULL)) != -1) { + switch (c) { + /* help */ + case 'h': help = 1; break; + /* version */ + case 'v': version = 1; break; + /* com port */ + case 'c': s_com = optarg; break; + /* zoom */ + case 'z': + *zoom = atoi(optarg); + if (*zoom <= 0 || *zoom > 16) { + log("-z, --zoom: should be between 1 and 16"); + return (1); + } + break; + + /* error (ignore) */ + case '?': + if (optopt == 'z') + log("-z, --zoom: expected an argument\n"); + else if (optopt == 'c') + log("--com: expected an argument\n"); + else + break; + return (1); + } + } + + /* check com port */ + if (s_com) { + if (!isdigit(s_com[0])) { + log("-c, --com: expected a number\n"); + return (0); + } + *com = atoi(s_com); + if (*com < 1 || *com > 20) { + log("-c, --com: COM port number should be between 1 and 20\n"); + return (0); + } + } + + /* check if there is any parameter */ + if (ac - optind) + help = 1; + + /* print help or version if required, and return */ + if (version) puts(version_message); + else if (help) puts(help_main); + else return (0); + return (1); +} diff --git a/src/p7screen/main.c b/src/p7screen/main.c new file mode 100644 index 0000000..e89a17c --- /dev/null +++ b/src/p7screen/main.c @@ -0,0 +1,167 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* p7screen/main.c |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 23:55:55 |___/ */ +/* */ +/* ************************************************************************** */ +#include "main.h" +#include +#include +#include + +/* ************************************************************************** */ +/* Error messages */ +/* ************************************************************************** */ +/* Couldn't initialize connexion to calculator. */ +static const char error_noconnexion[] = +"Could not connect to the calculator.\n" +"- Is it plugged in and in PROJ mode?\n" +"- Have you tried unplugging, plugging and selecting Projector on pop-up?\n" +"- Have you tried changing the cable?\n"; + +/* Calculator was found but program wasn't allowed to communicate with it. */ +static const char error_noaccess[] = +"Could not get access to the calculator.\n" +"Install the appropriate udev rule, or run as root.\n"; + +/* The calculator acted in a weird way. */ +static const char error_unplanned[] = +"The calculator didn't act as planned.\n" +"Stop receive mode on calculator and start it again before re-running " \ + QUOTE(BIN) ".\n" +"Error was: %s\n"; + +/* ************************************************************************** */ +/* Globals */ +/* ************************************************************************** */ +/* The z00m (omG) */ +static int zoom; + +/* ************************************************************************** */ +/* Auxiliary functions */ +/* ************************************************************************** */ +/** + * display_callback: + * The main callback for screen streaming. + * + * @arg w the width of the received image + * @arg h the height of the received image + * @arg pixels the image data + * @return if reception should continue + */ + +static int display_callback(int w, int h, uint32_t **pixels) +{ + /* create screen if there isn't one */ + static SDL_Surface *screen = NULL; + static int saved_w = 0, saved_h = 0; + if (!screen || saved_w != w || saved_h != h) { + /* create the window */ + if (!(screen = SDL_SetVideoMode(w * zoom, h * zoom, 32, + SDL_SWSURFACE | SDL_DOUBLEBUF))) { + log("Couldn't set video mode: %s\n", SDL_GetError()); + return (0); + } + SDL_WM_SetCaption("P7screen", NULL); + + /* save data and display message */ + saved_w = w; saved_h = h; + puts("Turn off your calculator (SHIFT+AC) when you have finished."); + } + + /* edit screen */ + /* - lock it - */ + SDL_LockSurface(screen); + /* - copy - */ + uint32_t *px = (uint32_t*)screen->pixels; + int linesize = w * zoom; + for (int y = 0; y < h; y++) { + uint32_t *refline = px; + for (int x = 0; x < w; x++) { + uint32_t pixel = pixels[y][x]; + for (int zx = 0; zx < zoom; zx++) + *px++ = pixel; + } + for (int zy = 1; zy < zoom; zy++) { + memcpy(px, refline, linesize * sizeof(uint32_t)); + px += linesize; + } + } + /* - unlock it - */ + SDL_UnlockSurface(screen); + + /* update screen */ + SDL_Flip(screen); + + /* check if user has pressed escape or cross */ + SDL_Event event; + SDL_PollEvent(&event); + if ((event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE) + || event.type == SDL_QUIT) + return (0); + + /* continue! */ + return (1); +} + +/* ************************************************************************** */ +/* Main function */ +/* ************************************************************************** */ +/** + * main: + * Entry point of the program. + * + * @arg ac arguments count + * @arg av arguments values + * @return if it worked (0 if OK) + */ + +int main(int ac, char **av) +{ + /* parse args */ + int com; + if (parse_args(ac, av, &com, &zoom)) + return (0); + + /* Initialize libp7 */ + p7_handle_t *handle = NULL; int err; + if (com) err = p7_cominit(&handle, 0, com); + else err = p7_init(&handle, 0); + if (err) { + /* display error */ + switch (err) { + case p7_error_nocalc: log(error_noconnexion); break; + case p7_error_noaccess: log(error_noaccess); break; + default: log(error_unplanned, p7_strerror(err)); break; + } + + /* return */ + return (1); + } + + /* Initialize SDL */ + if (SDL_Init(SDL_INIT_VIDEO)) { + log("Failed to initialize SDL: %s\n", SDL_GetError()); + return (3); + } + atexit(SDL_Quit); + + /* receive screen */ + if ((err = p7_getscreen(handle, &display_callback)) + && err != p7_error_nocalc) { + switch (err) { + case p7_error_timeout: log(error_noconnexion); break; + default: log(error_unplanned, p7_strerror(err)); break; + } + return (1); + } + + /* close */ + p7_exit(handle); + + /* everything went well */ + return (0); +} diff --git a/src/p7screen/main.h b/src/p7screen/main.h new file mode 100644 index 0000000..0fe964a --- /dev/null +++ b/src/p7screen/main.h @@ -0,0 +1,20 @@ +/* ************************************************************************** */ +/* _____ _ */ +/* p7screen/main.h |_ _|__ _ _| |__ ___ _ _ */ +/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */ +/* | | (_) | |_| | | | | __/ |_| | */ +/* By: thomas |_|\___/ \__,_|_| |_|\___|\__, |.fr */ +/* Last updated: 2017/01/16 23:55:55 |___/ */ +/* */ +/* ************************************************************************** */ +#ifndef MAIN_H +# define MAIN_H +# include +# define Q(x) #x +# define QUOTE(x) Q(x) +# define log(S, ...) fprintf(stderr, S, ##__VA_ARGS__) + +/* all functions */ +int parse_args(int ac, char **av, int *com, int *zoom); + +#endif /* MAIN_H */ diff --git a/src/p7screen/vars.mk b/src/p7screen/vars.mk new file mode 100755 index 0000000..c09f426 --- /dev/null +++ b/src/p7screen/vars.mk @@ -0,0 +1,3 @@ +#!/usr/bin/make -f +libs: + @echo libp7 sdl