diff --git a/build-distro.sh b/build-distro.sh index 584279b..deb7417 100755 --- a/build-distro.sh +++ b/build-distro.sh @@ -92,6 +92,9 @@ pushd distro buildOverlayTool macos aarch64 $(pwd)/overlay.macos buildOverlayTool windows x86_64 $(pwd)/overlay.windows + cp -f ../../f256lib.adoc . + asciidoctor-pdf -o f256lib.pdf f256lib.adoc + popd if [[ -f ../f256dev.7z ]]; then diff --git a/f256lib.adoc b/distro/f256lib.adoc similarity index 80% rename from f256lib.adoc rename to distro/f256lib.adoc index 036027e..6c0e9cc 100644 --- a/f256lib.adoc +++ b/distro/f256lib.adoc @@ -538,6 +538,11 @@ do { TIP: Take a look at the `f256dev\examples\sprites` program and `f256dev\f256lib\f_file.c` from the *_F256lib_* source code for kernel usage examples. +IMPORTANT: Using these kernel functions along with file I/O statements or `getchar()` +can result in missing an event. File I/O and keyboard reading have their own +kernel polling loops and will discard any events they aren't waiting on for +themselves. + ==== kernelCall [,c] @@ -582,8 +587,8 @@ Failing to call this often enough can starve the kernel of event objects. === DMA -At the moment, DMA access is... hit and miss. Feel free to try it but don't expect -it to be stable. More DMA features will be available in the future. +IMPORTANT: At the moment, DMA access is... hit and miss. Feel free to try it + but don't expect it to be stable. More DMA features will be available in the future. ==== dma2dFill @@ -893,7 +898,7 @@ on the screen refresh, the bitmaps are: On startup, all three bitmaps are assigned to each associated graphics layer, but are not visible. The three bitmaps are located at the following memory -addresses: +addresses at the top of the far memory available to the Vicky graphics chip: * Page 0 - 0x6c000 -> 0x7ebff * Page 1 - 0x58000 -> 0x6abff @@ -1067,6 +1072,11 @@ Like bitmaps and sprites, each void tileDefineTileMap(byte t, uint32_t address, byte tileSize, uint16_t mapSizeX, uint16_t mapSizeY); ---- +Defines a tile map from a block of RAM. `t` is which map to define (0 to 2). +`address` is where in near or far memory the map data is located. `tileSize` +specifies the size of your tiles (either 8 or 16). Finally, `mapSizeX` and +`mapSizeY` determine the size of the map. + ==== tileDefineTileSet [,c] @@ -1074,6 +1084,11 @@ void tileDefineTileMap(byte t, uint32_t address, byte tileSize, uint16_t mapSize void tileDefineTileSet(byte t, uint32_t address, bool square); ---- +Specifies where in memory to find a given tile set. `t` determines which of the +eight available (0 to 7) tile sets we're defining. `address` is where in near +or far memory the tile data is located. `square` indicates if the tile data +in memory is laid out in a square or a single tile width vertical strip. + ==== tileSetScroll [,c] @@ -1081,6 +1096,10 @@ void tileDefineTileSet(byte t, uint32_t address, bool square); void tileSetScroll(byte t, byte xPixels, uint16_t xTiles, byte yPixels, uint16_t yTiles); ---- +Changes the position of a given tile map `t`. `xPixels` and `yPixels` allow +for fine scrolling of the tile map while `xTiles` and `yTiles` determine the +upper left tile to be displayed. + ==== tileSetVisible [,c] @@ -1088,68 +1107,193 @@ void tileSetScroll(byte t, byte xPixels, uint16_t xTiles, byte yPixels, uint16_t void tileSetVisible(byte t, bool v); ---- +Determines the visibility `v` of a particular tile map `t` (0 to 2). + === File I/O -fileDirEntT +File I/O from the MicroKernel is mapped to standard C library file routines +with a few minor changes for how the F256 handles drives. -int8_t fileClose(uint8_t *fd); -int8_t fileCloseDir(char *dir); -int8_t fileMakeDir(char *dir); -uint8_t *fileOpen(char *fname, char *mode); -char *fileOpenDir(char *name); -int16_t fileRead(void *buf, uint16_t nbytes, uint16_t nmemb, uint8_t *fd); -fileDirEntT *fileReadDir(char *dir); -int8_t fileRemoveDir(char *dir); -int8_t fileRename(char *name, char *to); -int8_t fileSeek(uint8_t *fd, uint32_t offset, uint8_t whence); -int8_t fileUnlink(char *name); -int16_t fileWrite(void *buf, uint16_t nbytes, uint16_t nmemb, uint8_t *fd); +Supported functions are listed below. For usage details, see the documentation +for the standard C library. -#define _DE_ISREG(t) (t == 0) -#define _DE_ISDIR(t) (t == 1) -#define _DE_ISLBL(t) (t == 2) -#define _DE_ISLNK(t) (0) +* `int closedir(DIR *dirp);` +* `int fclose(FILE *stream);` +* `FILE *fopen(const char *pathname, const char *mode);` +* `size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);` +* `int fseek(FILE *stream, long offset, int whence);` +* `size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);` +* `int mkdir(const char *pathname, mode_t mode);` +* `DIR *opendir(const char *name);` +* `struct dirent *readdir(DIR *dirp);` +* `int rename(const char *oldpath, const char *newpath);` +* `void rewind(FILE *stream);` +* `int rmdir(const char *pathname);` +* `int unlink(const char *pathname);` + +The following macros are available for identifying which type of directory +entry is being returned in `dirent->d_type`: + +* `_DE_ISREG(d_type)` +* `_DE_ISDIR(d_type)` +* `_DE_ISLBL(d_type)` +* `_DE_ISLNK(d_type)` + +NOTE: Seeking is only supported forward from the start of the file. +`SEEK_SET` is defined for use as `whence`. +Currently not supported by IEC drives. + +NOTE: Not all IEC devices support subdirectories. + +NOTE: Pathnames on the F256 use the backslash (`\`) to delimit +subdirectories. Similar to Windows, the F256 uses the concept of a "drive". +Unlike Windows, drives are numbered, not lettered, and start at `0` which is +the built-in SD card reader. An example path with a drive and subdirectory +looks like this: `0:\DOCS\README.TXT` + +IMPORTANT: Do not mix kernel access with file I/O. Using file I/O inside +a kernel event loop will cause the loop to miss events! -#define closedir fileCloseDir -#define DIR char -#define dirent fileDirEntS -#define FILE uint8_t -#define fclose fileClose -#define fopen fileOpen -#define fread fileRead -#define fseek fileSeek -#define fwrite fileWrite -#define mkdir(d,m) fileMakeDir(d) -#define opendir fileOpenDir -#define readdir fileReadDir -#define rename fileRename -#define rewind(s) (void)fileSeek(s, 0, SEEK_SET) -#define rmdir fileRemoveDir -#define SEEK_SET 0 -#define STDIN 0 -#define STDOUT 1 -#define unlink fileUnlink === Platform -void __putchar(char c); -int getchar(void); +The absolute lowest level features needed to make the compiler and its library +work. +==== __putchar + +[,c] +---- +void __putchar(char c); +---- + +Displays the character `c` on the screen. + + +==== getchar + +[,c] +---- +int getchar(void); +---- + +Reads a single key from the keyboard. + +IMPORTANT: If you are using kernel functions, do not call `getchar` inside +your kernel event loop. Use the kernel event `key.PRESSED` instead to avoid +losing events. Likewise, avoid standard C library routines that expect input +from the keyboard. == Using Code Overlays +One of the most powerful features of this toolchain is the ability to write +programs that use more than the 64k of RAM addressable by the CPU. Using the +MMU (Memory Management Unit) of the F256, *_F256lib_* is able to automatically +swap code in from far memory on demand. The only additional work needed by +the programmer is to specify which bits of code are to be relocated to far +memory. This is achieved with a `#define SEGMENT_name` statement. + +Example: + +[,c] +---- +#define F256LIB_IMPLEMENTATION +#include "f256lib.h" + + +void firstSegment(int arg1, int arg2); +void secondSegment(int arg1, int arg2); +void moreFirstSegment(int arg1, int arg2); + + +// This is the first segment we've defined. +// The linker will place this code in the first available +// far memory slot (default 0x10000). +#define SEGMENT_FIRST + +void firstSegment(int arg1, int arg2) { + printf("firstSegment = %d\n", arg1 + arg2); + secondSegment(arg1, arg2); +} + +// This is the second segment we've defined. +// The linker will place this code in the next available +// far memory slot (default 0x12000). +#define SEGMENT_SECOND + +void secondSegment(int arg1, int arg2) { + printf("secondSegment = %d\n", arg1 + arg2); + moreFirstSegment(arg1, arg2); +} + +// Back to the first segment. +// The linker will place this code immediately +// after the previous first segment code. +#define SEGMENT_FIRST + +void moreFirstSegment(int arg1, int arg2) { + printf("moreFirstSegment = %d\n", arg1 + arg2); +} + +// Back to near memory, the 64k visible to the processor. +// By default, this segment begins at 0x300. +#define SEGMENT_MAIN + +int main(int argc, char *argv[]) { + (void)argc; + (void)argv; + + firstSegment(1, 2); + + // Spin. + for (;;); + + return 0; +} +---- + +TIP: When building your program, the amount of space being used in each +segment will be displayed (or an error that you have overflowed a segment). +Use this information to help decide how to segment your program. + +IMPORTANT: You cannot change where the overlay tool will place your far +memory code. It always starts at `0x10000` and increments the address `0x2000` (8k) +for each additional segment. When using overlays, be careful to not overwrite +this memory with other data! + +NOTE: At the moment, you can only move code into far memory, not variables. + == Embedding Binary Data -* EMBED(); arguments must be literals. You cannot use #defines or variables. +Embedding binary data (sprites, tiles, bitmaps, whatever) into your program +at a specific memory address can be easily achieved with the `EMBED` macro. -* EMBED(); names (first argument) must begin with unique prefixes. For example, - "TILES" and "TILES_PALETTE" will cause an error due to "TILES" being a - complete substring of "TILES_PALETTE". +=== EMBED + +[,c] +---- +EMBED(name, "filename", address) +---- + +Embeds the contents of `"filename"` at near or far memory `address`. The +embedded data will be available by name through the following symbols: + +* `const char name_start[];` +* `const char name_end[];` + +Where `name` is the prefix of each symbol. + + +NOTE: `EMBED` arguments *must* be literals. You cannot use #defines or variables. + +NOTE: `EMBED` names (first argument) *must* begin with unique prefixes. For example, +"TILES" and "TILES_PALETTE" will cause an error due to "TILES" being a +complete substring of "TILES_PALETTE".