Removing p7os (non fonctionnel)

This commit is contained in:
Lailouezzz 2019-12-30 14:43:13 +01:00
parent 96b14f3ef9
commit ea1c5a1b0c
Signed by: Lailouezzz
GPG Key ID: 03FCE8A99EF8482C
169 changed files with 0 additions and 14206 deletions

View File

@ -1,220 +0,0 @@
/* ************************************************************************** */
/* _____ _ */
/* p7os/args.c |_ _|__ _ _| |__ ___ _ _ */
/* | Project: p7utils | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2017/01/16 23:55:54 |___/ */
/* */
/* ************************************************************************** */
#include "main.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <getopt.h>
#include <errno.h>
/* ************************************************************************** */
/* 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 <port>]\n"
" [--no-prepare] [--uexe <path>]\n"
" <subcommand> [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 <port> 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 <path> Use a custom update program.\n"
"\n"
"Type \"" QUOTE(BIN) " <subcommand> --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 <os.bin>]\n"
"Get the calculator OS image.\n"
"You must have \"p7os prepare\"-ed before.\n"
"\n"
"Options are :\n"
" -o <os.bin> 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);
}

View File

@ -1,6 +0,0 @@
/Makefile.cfg
/obj
/update.exe.elf
/update.exe.bin
/cake.exe.elf
/cake.exe.bin

View File

@ -1,3 +0,0 @@
[submodule "libgint"]
path = libgint
url = http://git.planet-casio.com/lephe/gint.git

View File

@ -1,336 +0,0 @@
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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w` and `show c` should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w` and `show c`; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a “copyright disclaimer” for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -1,136 +0,0 @@
#!/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.

View File

@ -1,63 +0,0 @@
#!/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.

View File

@ -1,81 +0,0 @@
#!/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

View File

@ -1,40 +0,0 @@
# 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.

View File

@ -1,8 +0,0 @@
# 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

View File

@ -1,97 +0,0 @@
#!/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 <<EOF
\`configure\` configures ${name} to adapt to systems that aren't mine.
Usage: $0 [OPTION]
Defaults for the options are specified in brackets.
General options:
--help display this help and exit
--version display version information and quit
--make-full-log display full commands while making
Report bugs to ${maintainer}.
EOF
exit 0
}
#******************************************************************************#
# Version message #
#******************************************************************************#
version() {
cat <<EOF
${name} configure script v${version}
Hand-written by Thomas "Cakeisalie5" Touhey.
This configure script is free software.
There is NO warranty; not even for MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
EOF
exit 0
}
#******************************************************************************#
# Check for help and version #
#******************************************************************************#
put_version=
put_help=
for arg ; do case "$arg" in
--help|-h) put_help=1 ;;
--version|-v) put_version=1 ;;
esac; done
[ $put_version ] && version
[ $put_help ] && usage
#******************************************************************************#
# Parse arguments #
#******************************************************************************#
for arg ; do case "$arg" in
--make-full-log) make_full_log=yes ;;
*) echo "$arg: didn't read" ;;
esac; done
#******************************************************************************#
# Create Makefile configuration #
#******************************************************************************#
# Clean
make mrproper MAKE_FULL_LOG=y 1>/dev/null
# Write
exec 3>&1 1>Makefile.cfg
cat <<EOF
#!/usr/bin/make -f
#******************************************************************************#
# Makefile configuration generated by ./configure #
#******************************************************************************#
# Configuration version and messages configuration
CONFIG_VERSION := $version
MAKE_FULL_LOG := $make_full_log
# End of file.
EOF
exec 1>&3 3>&-
chmod +x Makefile.cfg
# Finish
echo "Configuration loaded, you can make now."
# End of file.

View File

@ -1,10 +0,0 @@
/* ************************************************************************** */
/* _____ _ */
/* main.h |_ _|__ _ _| |__ ___ _ _ */
/* | Project: cake.exe | |/ _ \| | | | '_ \ / _ \ | | | */
/* | | (_) | |_| | | | | __/ |_| | */
/* By: thomas <thomas@touhey.fr> |_|\___/ \__,_|_| |_|\___|\__, |.fr */
/* Last updated: 2017/01/16 18:05:44 |___/ */
/* */
/* ************************************************************************** */

View File

@ -1,20 +0,0 @@
# 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

View File

@ -1,210 +0,0 @@
#! /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

View File

@ -1,72 +0,0 @@
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.

View File

@ -1,33 +0,0 @@
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)

View File

@ -1,78 +0,0 @@
#! /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=<integer> [default: 16]
Number of exit handlers that can be registered by atexit().
--rtc-callbacks=<integer> [default: 5]
Number of RTC callbacks that can be registered.
--events-queue-size=<integer> [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=<integer-value>";;
*)
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

View File

@ -1,531 +0,0 @@
#include "gintdemo.h"
#include <mpu.h>
#include <gint.h>
#include <keyboard.h>
#include <display.h>
#include <gray.h>
#include <internals/stdio.h>
//---
// 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<end_y ; i++)
{
if(begin_x < end_x)
{
line = bmp[i*(real_width>>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<end_x ; j++)
{
line = bmp[i*(real_width>>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<<real_width-width;
line <<= shift;
if(begin_x < end_x || bool1) screen[end_x] |= *p;
if(bool2) screen[end_x+1] |= *(p+1);
screen += 16;
}
}
#include <internals/timer.h>
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;
}

View File

@ -1,114 +0,0 @@
//---
//
// 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

View File

@ -1,110 +0,0 @@
/*
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
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

View File

@ -1,221 +0,0 @@
#include "gintdemo.h"
#include <display.h>
#include <gray.h>
#include <keyboard.h>
#include <internals/bopti.h>
#include <stddef.h>
/*
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;
}

View File

@ -1,102 +0,0 @@
#include "gintdemo.h"
#include <gray.h>
#include <keyboard.h>
#include <mpu.h>
/*
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();
}

View File

@ -1,82 +0,0 @@
#include "gintdemo.h"
#include <display.h>
#include <keyboard.h>
#include <stdlib.h>
/*
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;
}
}

View File

@ -1,262 +0,0 @@
#include "gintdemo.h"
#include <display.h>
#include <rtc.h>
#include <keyboard.h>
#include <stddef.h>
#include <ctype.h>
/*
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 <internals/rtc.h>
#include <mpu.h>
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);
}

View File

@ -1,158 +0,0 @@
#include "gintdemo.h"
#include <display.h>
#include <keyboard.h>
#include <gray.h>
#include <stddef.h>
/*
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);
}
}

View File

@ -1,272 +0,0 @@
#include "gintdemo.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <internals/timer.h>
#include <timer.h>
#include <display.h>
#include <keyboard.h>
#include <clock.h>
#include <mpu.h>
#include <rtc.h>
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;
}
}
}

View File

@ -1,306 +0,0 @@
# 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.

View File

@ -1,673 +0,0 @@
#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

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +0,0 @@
//---
//
// 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 <stddef.h>
/*
alloca()
Allocates a memory block on the stack.
*/
void *alloca(size_t size);
#define alloca(size) __builtin_alloca(size)
#endif // _ALLOCA_H

View File

@ -1,128 +0,0 @@
//---
//
// 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

View File

@ -1,35 +0,0 @@
//---
//
// 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

View File

@ -1,161 +0,0 @@
//---
//
// 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 <tales.h>
/*
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

View File

@ -1,84 +0,0 @@
//---
//
// 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

View File

@ -1,192 +0,0 @@
//---
//
// 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

View File

@ -1,160 +0,0 @@
//---
//
// 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 <display.h>
//---
// 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

View File

@ -1,160 +0,0 @@
//---
//
// 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 <stdint.h>
#include <display.h>
/*
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

View File

@ -1,56 +0,0 @@
//---
//
// gint drawing module: display
//
// Handles vram manipulation and drawing.
//
//---
#ifndef _INTERNALS_DISPLAY_H
#define _INTERNALS_DISPLAY_H 1
#include <stdint.h>
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

View File

@ -1,19 +0,0 @@
#ifndef _INTERNALS_EVENTS_H
#define _INTERNALS_EVENTS_H
#include <events.h>
#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

View File

@ -1,30 +0,0 @@
#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

View File

@ -1,39 +0,0 @@
#ifndef _INTERNALS_KEYBOARD_H
#define _INTERNALS_KEYBOARD_H
#include <keyboard.h>
// 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

View File

@ -1,21 +0,0 @@
//---
//
// 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

View File

@ -1,141 +0,0 @@
#ifndef _INTERNALS_RTC_H
#define _INTERNALS_RTC_H
#include <rtc.h>
#include <stddef.h>
#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

View File

@ -1,32 +0,0 @@
//---
//
// 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 <stddef.h>
#include <stdarg.h>
//---
// 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

View File

@ -1,55 +0,0 @@
#ifndef _INTERNALS_TALES_H
#define _INTERNALS_TALES_H 1
#include <tales.h>
#include <stdint.h>
#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

View File

@ -1,16 +0,0 @@
#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

View File

@ -1,48 +0,0 @@
#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

View File

@ -1,303 +0,0 @@
//---
//
// 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 <rtc.h>
//---
// 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

View File

@ -1,76 +0,0 @@
//---
//
// 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

View File

@ -1,121 +0,0 @@
//---
//
// 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

View File

@ -1,23 +0,0 @@
//---
//
// 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

View File

@ -1,35 +0,0 @@
//---
//
// 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

View File

@ -1,44 +0,0 @@
//---
//
// 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 <stddef.h>
#include <stdarg.h>
//---
// 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

View File

@ -1,149 +0,0 @@
//---
//
// 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 <stddef.h>
#include <limits.h>
// 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

View File

@ -1,63 +0,0 @@
//---
//
// standard library module: string
//
// String manipulation using NUL-terminated byte arrays, without extended
// characters.
//
//---
#ifndef _STRING_H
#define _STRING_H 1
#include <stddef.h>
//---
// 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

View File

@ -1,123 +0,0 @@
//---
//
// 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 <display.h>
#include <stdint.h>
//---
// 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

View File

@ -1,126 +0,0 @@
//---
//
// standard library module: time
//
// Provides time manipulation and representation functions.
//
//---
#ifndef _TIME_H
#define _TIME_H 1
#include <stddef.h>
//---
// 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

View File

@ -1,89 +0,0 @@
//---
//
// 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 <clock.h>
//---
// 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

View File

@ -1,329 +0,0 @@
#include <internals/bopti.h>
// 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;
}

View File

@ -1,57 +0,0 @@
#include <internals/bopti.h>
#include <internals/display.h>
/*
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++;
}
}

View File

@ -1,65 +0,0 @@
#include <internals/bopti.h>
#include <internals/display.h>
/*
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++;
}
}

View File

@ -1,57 +0,0 @@
#include <internals/bopti.h>
#include <internals/display.h>
#include <gray.h>
/*
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++;
}
}

View File

@ -1,85 +0,0 @@
#include <internals/bopti.h>
#include <internals/display.h>
#include <gray.h>
/*
#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++;
}
}

View File

@ -1,288 +0,0 @@
#include <clock.h>
#include <timer.h>
#include <internals/timer.h>
#include <rtc.h>
#include <stddef.h>
#include <mpu.h>
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);
}

View File

@ -1,168 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <gint.h>
#include <clock.h>
#include <internals/mmu.h>
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;
}

View File

@ -1,285 +0,0 @@
//---
//
// 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 <internals/gint.h>
#include <gint.h>
#include <mpu.h>
#include <stddef.h>
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 <display.h>
#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();
}

View File

@ -1,37 +0,0 @@
#include <internals/gint.h>
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",
};

View File

@ -1,66 +0,0 @@
/*
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)

View File

@ -1,41 +0,0 @@
/*
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

View File

@ -1,29 +0,0 @@
#include <internals/display.h>
/*
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
}

View File

@ -1,12 +0,0 @@
#include <internals/display.h>
#include <display.h>
/*
dclear()
Clears the whole vram.
*/
void dclear(void)
{
int i;
for(i = 0; i < 256; i++) vram[i] = 0;
}

View File

@ -1,21 +0,0 @@
#include <internals/display.h>
#include <display.h>
/*
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];
}

View File

@ -1,43 +0,0 @@
#include <display.h>
// 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;
}

View File

@ -1,116 +0,0 @@
#include <internals/display.h>
#include <display.h>
#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);
}

View File

@ -1,32 +0,0 @@
#include <internals/display.h>
#include <display.h>
/*
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;
}
}

View File

@ -1,21 +0,0 @@
#include <internals/display.h>
#include <display.h>
/*
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];
}

View File

@ -1,14 +0,0 @@
#include <internals/display.h>
#include <display.h>
#include <screen.h>
#include <gray.h>
/*
dupdate()
Displays the vram on the physical screen.
*/
void dupdate(void)
{
if(gray_runs()) return;
screen_display((const void *)vram);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View File

@ -1,33 +0,0 @@
#include <display.h>
/*
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);
}

View File

@ -1,38 +0,0 @@
#include <internals/events.h>
#include <events.h>
#include <clock.h>
/*
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;
}

View File

@ -1,26 +0,0 @@
#include <internals/events.h>
#include <events.h>
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;
}

View File

@ -1,14 +0,0 @@
#include <gray.h>
/*
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;
}

Some files were not shown because too many files have changed in this diff Show More