diff --git a/Makefile b/Makefile index f12c055..0960d86 100755 --- a/Makefile +++ b/Makefile @@ -71,10 +71,6 @@ define n 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\ @@ -131,6 +127,9 @@ endef all: $(config) $(target-std) $(target-lib) $(target-g1a) @ printf '\e[32;1mmsg \u00bb\e[0m All done!\n' +$(config): + $(error "Configuration files are missing. Did you ./configure?") + build: $(if $(VERBOSE),,@ printf '\e[35;1mdir \u00bb\e[0m mkdir $@\n') $(if $(VERBOSE),,@) mkdir -p $@ @@ -212,10 +211,7 @@ mrproper: clean distclean: mrproper -install: - p7 send -f $(target-g1a) - -install_lib: $(target-std) $(target-lib) +install: $(target-std) $(target-lib) mkdir -p $(folder) install -m 644 $^ $(folder) 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 @ 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 diff --git a/README.md b/README.md index f3b5fad..8511870 100644 --- a/README.md +++ b/README.md @@ -2,54 +2,77 @@ 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). +provides a mostly free-standing runtime support for the platform, and can be +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, -modify it and share you changes. No credit of any kind is needed, though -appreciated. +gint is free software: you may use it for any purpose, share it, modify it and +share your changes. No credit of any kind is required, though 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 ----------------- 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. +accesses the peripheral modules and workarounds the system to perform keyboard +analyzes directly on hardware or timer management. +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 ----------------------- -There are some dependencies: -* The `sh3eb-elf` toolchain somewhere in the PATH -* The fxSDK installed and available in the PATH +To build and install gint, you will need the following components: +* The `sh3eb-elf` toolchain linked somewhere 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`. -This will build the following components : +The classical way to build gint is to enter a terminal and use the usual: + + $ ./configure + $ make + # make install + +This will build and install the following components in the storage folder of +the fxSDK: * `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 -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 @@ -65,8 +88,6 @@ components: * 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. +* Other files in `/src/module`: the `display` module contains a font. The demo application is in the `demo` directory. - -The `doc` folder contains some documentation. diff --git a/TODO b/TODO index d1a6f87..348f9cc 100644 --- a/TODO +++ b/TODO @@ -3,19 +3,21 @@ Bugs to fix: - Lost keyboard control at startup (could not reproduce) 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 - 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 - -Modules to implement: -- Serial communication -- Sound playback and synthesizing -- Handle errors within errno +Other whole modules: +- Serial communication through 3-pin +- USB communication +- Sound playback and synthesizing (if possible) +- Overclock (relaunch clocks when overclocking) Things to investigate: - Packed bit fields alignment diff --git a/doc/bopti.md b/doc/bopti.md deleted file mode 100644 index b460253..0000000 --- a/doc/bopti.md +++ /dev/null @@ -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.