Updated README and TODO files

This commit is contained in:
lephe 2016-12-25 11:45:05 +01:00
parent 9a3433c52a
commit 4fceab4533
4 changed files with 71 additions and 355 deletions

View file

@ -71,10 +71,6 @@ define n
endef endef
ifeq ("$(wildcard $(config))","")
$(error "Configuration files are missing. Did you ./configure?")
endif
# Module-scope variables. # Module-scope variables.
$(foreach mod, $(modules), $(eval \ $(foreach mod, $(modules), $(eval \
mod-$(mod)-c = $(notdir $(wildcard src/$(mod)/*.c)) $n\ mod-$(mod)-c = $(notdir $(wildcard src/$(mod)/*.c)) $n\
@ -131,6 +127,9 @@ endef
all: $(config) $(target-std) $(target-lib) $(target-g1a) all: $(config) $(target-std) $(target-lib) $(target-g1a)
@ printf '\e[32;1mmsg \u00bb\e[0m All done!\n' @ printf '\e[32;1mmsg \u00bb\e[0m All done!\n'
$(config):
$(error "Configuration files are missing. Did you ./configure?")
build: build:
$(if $(VERBOSE),,@ printf '\e[35;1mdir \u00bb\e[0m mkdir $@\n') $(if $(VERBOSE),,@ printf '\e[35;1mdir \u00bb\e[0m mkdir $@\n')
$(if $(VERBOSE),,@) mkdir -p $@ $(if $(VERBOSE),,@) mkdir -p $@
@ -212,10 +211,7 @@ mrproper: clean
distclean: mrproper distclean: mrproper
install: install: $(target-std) $(target-lib)
p7 send -f $(target-g1a)
install_lib: $(target-std) $(target-lib)
mkdir -p $(folder) mkdir -p $(folder)
install -m 644 $^ $(folder) install -m 644 $^ $(folder)
install -m 644 -T demo/gintdemo.ld $(folder)/linker.ld install -m 644 -T demo/gintdemo.ld $(folder)/linker.ld
@ -223,4 +219,7 @@ install_lib: $(target-std) $(target-lib)
install -m 644 include/*.h $(folder)/gint install -m 644 include/*.h $(folder)/gint
@ printf '\e[32;1mmsg \u00bb\e[0m All installed!\n' @ printf '\e[32;1mmsg \u00bb\e[0m All installed!\n'
.PHONY: all clean mrproper distclean install install_lib help install_demo:
p7 send -f $(target-g1a)
.PHONY: all clean mrproper distclean install install_demo help

View file

@ -2,54 +2,77 @@ gint project
============ ============
gint (pronounce 'guin') is a low-level library for fx-9860G calculators. It 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 provides a mostly free-standing runtime support for the platform, and can be
toolchain (sh3eb-elf). used to develop add-ins under Linux along with the gcc toolchain (`sh3eb-elf`
target) and the [fxSDK](http://git.planet-casio.com/lephe/fxsdk).
By the way, gint is free software; you may use it for any purpose, share it, gint is free software: you may use it for any purpose, share it, modify it and
modify it and share you changes. No credit of any kind is needed, though share your changes. No credit of any kind is required, though appreciated.
appreciated.
Programming interface
---------------------
Because of its free-standing design, gint's API provides direct and efficient
access to the low-level MPU features, among which:
* Extensive keyboard control, including replication of the system behavior for
office applications and event-driven decisions for games
* Hardware timers running at over 10 MHz, allowing microsecond-level control
* Unlimited mappings of callbacks to Real-Time Clock events (requires build)
* Access to processor register for debugging information, determination of
processor speed (overclock is on the TODO list), backlight management...
The library also offers powerful higher-level features:
* A gray engine that works by rapidly swapping monochrome images
* Blazingly fast drawing functions when working with the fxSDK
* C Standard functions such as the `printf()` family.
Interrupt handler Interrupt handler
----------------- -----------------
The interrupt handler is the lowest-level part of the library. It directly The interrupt handler is the lowest-level part of the library. It directly
accesses the peripheral modules and performs keyboard analyzes, swaps screen accesses the peripheral modules and workarounds the system to perform keyboard
buffers, etc. analyzes directly on hardware or timer management.
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.
gint does not allow user programs to use their own handlers, but it allows them
to complete the original handler if they want to use interrupts that are not
supported by the library. It is also possible to map various interrupt-driven
events to user-provided callbacks using the API, which is not allowed by the
operating system. This is particularly useful for timers and the Real-Time
Clock (the 16 Hz interrupt can be used to run a physical engine, while the 1 Hz
interrupt can be used in a real-time management game).
Building and installing Building and installing
----------------------- -----------------------
There are some dependencies: To build and install gint, you will need the following components:
* The `sh3eb-elf` toolchain somewhere in the PATH * The `sh3eb-elf` toolchain linked somewhere in the PATH
* The fxSDK installed and available in the PATH * The [fxSDK](http://git.planet-casio.com/lephe/fxsdk) installed and available
in the PATH
The easiest way to build gint is simply to enter a terminal and execute `make`. The classical way to build gint is to enter a terminal and use the usual:
This will build the following components :
$ ./configure
$ make
# make install
This will build and install the following components in the storage folder of
the fxSDK:
* `libgint.a`, the gint library * `libgint.a`, the gint library
* `libc.a`, a (very) few standard procedures * `libc.a`, the partial standard library
* The libgint headers for development
The following additional files will be generated in the working directory:
* `gintdemo.g1a`, a test application * `gintdemo.g1a`, a test application
The common `clean`, `mrproper`, and `distclean` rules will clean the directory. The usual `clean`, `mrproper`, and `distclean` rules will clean the directory.
There are configuration options, which can be obtained using
`./configure --help`. Most of them customize size limits, if a project needs to
extend them. The true free-standing program may build the library using the
`--no-syscalls` switch, but some features will be disabled (dynamic
allocation...).
Source organization Source organization
@ -65,8 +88,6 @@ components:
* Other source files in `/src/module`: contain multiple functions that always * Other source files in `/src/module`: contain multiple functions that always
work together, or are lightweight enough not to be separated. Their names work together, or are lightweight enough not to be separated. Their names
often begin with `module_`. often begin with `module_`.
* Other files in `/src/module`: the `display` module contains a font, I think. * Other files in `/src/module`: the `display` module contains a font.
The demo application is in the `demo` directory. The demo application is in the `demo` directory.
The `doc` folder contains some documentation.

16
TODO
View file

@ -3,19 +3,21 @@ Bugs to fix:
- Lost keyboard control at startup (could not reproduce) - Lost keyboard control at startup (could not reproduce)
Simple improvements: Simple improvements:
- bopti: Monochrome bitmaps blending modes
- bopti: Partial transparency
- demo: Try 284x124 at (-60, -28) (all disadvantages) - demo: Try 284x124 at (-60, -28) (all disadvantages)
- display: Rectangle-based drawing functions - display: Rectangle-based drawing functions
- tales: Test all font encodings - tales: Test all font encodings
- time: Compute CLOCKS_PER_SEC - time: Compute CLOCKS_PER_SEC
- core: Add VBR handlers debugging information (if possible) - core: Add VBR handlers debugging information (if possible)
Larger improvements:
- errno: Introduce errno and use it more or less everywhere
- bopti: Monochrome bitmaps blending modes
- bopti: Handle partial transparency
- core: Implement all callbacks and a complete user API - core: Implement all callbacks and a complete user API
Other whole modules:
Modules to implement: - Serial communication through 3-pin
- Serial communication - USB communication
- Sound playback and synthesizing - Sound playback and synthesizing (if possible)
- Handle errors within errno - Overclock (relaunch clocks when overclocking)
Things to investigate: Things to investigate:
- Packed bit fields alignment - Packed bit fields alignment

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.