f256/distro/f256lib.adoc
2024-06-17 20:44:13 -05:00

1373 lines
33 KiB
Text

= *_F256Dev_*: Compiler, Tools, and C Library for the Foenix F256 Family of Computers
:author: Scott Duensing
:email: scott@kangaroopunch.com
:homepage: https://kangaroopunch.com
:revnumber: 1.0
:revdate: 03-JUN-2024
:revremark: First Draft
:source-highlighter: coderay
:sectnums:
:toc: left
:toclevels: 5
:toc-title: Contents
== Introduction
*_F256Dev_* is a C development system for the https://c256foenix.com[Foenix F256]
family of "modern retro" computers.
It consists of the *_LLVM-MOS_* compiler toolchain, the *_F256lib_* programming library,
several helpful tools, build and run scripts, and more.
*_F256lib_* is a C library targeting the F256 family.
It provides easy access to the platform's various features (graphics, text, I/O, etc.) from
within a C program.
In addition, *_F256lib_* also unleashes the power of the F256 by automatically handling most of
the sometimes tricky memory management and paging required to truly harness the power of the system.
TIP: Although fairly complete, not every feature of the Foenix F256 computers are
supported yet. Not finding a feature you need? <<Support,Let us know>>!
== Audience
This document is not an introduction to programming. It assumes you are comfortable with
your host OS and working from the command line.
Example pathnames in this document are usually in Windows format.
Linux and MacOS folks, you can cope.
== Requirements
* Foenix F256jr, F256K, (or emulator) with a 65c02 or 65816 CPU.
* Host PC running Linux (x64), Windows (x64), or MacOS (Apple Silicon).
On Windows, you will also need:
* https://www.rarlab.com/[WinRAR] or https://www.7zip.com/[7-Zip] installed.
* https://www.python.org/[Python 3.x] installed and in your PATH.
For MacOS and Linux:
* Ensure you have Python 3.x installed.
NOTE: Although the 65816 is supported, it is currently treated as a 65c02.
== Installation
Download the appropriate installation script:
|===
| Platform |Script
| 64 bit Intel Windows
| https://kangaroopunch.com/files/download/software/f256-install.bat[f256-install.bat]
| 64 bit Intel Linux
| https://kangaroopunch.com/files/download/software/f256-install.sh[f256-install.sh]
| 64 bit ARM MacOS
| https://kangaroopunch.com/files/download/software/f256-install.sh[f256-install.sh]
|===
Create a new, empty directory, with no spaces in the name (or in the names of
the parent directories) and place this file into it. Recommended locations:
* On Windows: `C:\F256`
* On Linux and MacOS: `~/f256`
From that folder, execute
the script. It will download additional dependencies and install them. Aside
from some Python modules needed by FoenixManager, everything will stay inside
this new folder. Uninstalling is just a matter of deleting it.
== Configuration
You will need to modify `foenixmgr.ini` in the main installation folder. The
only thing that should need updated is the COM port used to communicate with
your F256. See: https://github.com/pweingar/FoenixMgr
== Upgrading
Just re-run your `f256-install` script!
WARNING: This will *delete* the `f256dev` folder! Do *NOT* put your own data
in this folder!
== Assumptions
This package was designed to be easy to use for new programmers. As such, some
liberties were taken that aren't entirely common practice. There are no
project files, makefiles, or other build configuration systems. The included
`f256build` and `f256run` scripts assume you have arranged your code in directories
like the example programs. If you are more advanced than this, feel free to go
crazy.
While we've tried to simplify things, do not be afraid to dig into the source code
for *_F256lib_* and the included tools!
[quote,Some Code Monkey Jedi]
Use the Source, Luke!
This manual also assumes you have familiariazed yourself with the
https://github.com/pweingar/F256Manual[hardware documentation]
for the Foenix F256. Without knowing the capabilities of the machine,
it's going to be hard to program in any lanugage with any toolkit!
== Amalgamated or Not?
*_F256lib_* is distributed in two formats. _Amalgamated_ (everything in a
single header file) or as individual source files for each section of the API.
We *highly* recommend using the amalgamated build unless you are interested
in working on the library itself. The included build tools do not support
using the non-amalgamated version out-of-the-box.
== Usage
Using *_F256lib_* is pretty painless for a low-level C library.
Simply include the header in each of your source files.
=== Setting Up Your Project
The main requirement is that each program have its
own parent directory named for that program and inside it, a "src" directory
where the actual code lives. Example:
[source]
C:\F256\CODE\MYPROGRAM\SRC
This would be a project named `MYPROGRAM` located in a `CODE` folder under the
folder you installed the toolkit in. (You do not have to locate your projects
under the toolkit folder.)
=== Creating Your Main Source File
In the file that contains your `main()` function, start with the following:
[,c]
----
#define F256LIB_IMPLEMENTATION
#include "f256lib.h"
int main(int argc, char *argv[]) {
printf("Hello from F256 Land!");
while(1)
;
return 0; // Reaching this will reset the F256.
}
----
=== Building Your Project
To build this, you would run `f256build` from the
`C:\F256` folder as follows:
[source]
f256build.bat code\myprogram
UNIX folks, flip your slashes!
[source]
----
./f256build.sh code/myprogram
----
NOTE: When using `f256build` to build your projects, the include path will be set automatically.
After a successful build, an overview of memory usage will be displayed. Double-check
this to ensure it appears "sane" for your program! If you run out of space in
either near memory or an overlay bank, you'll see errors here.
=== Running Your Project
If you properly configured your `foenixmgr.ini` and have connected your F256
to your host PC, simply use `f256run` to start your program:
[source]
f256run.bat code\myprogram
UNIX folks, still flip your slashes!
[source]
----
./f256run.sh code/myprogram
----
=== Debugging
If your program fails to compile or isn't doing what you expect, a lot of
useful information can be found in the `.builddir` directory that is created
under your program's project directory.
== Definitions
* `block`: an 8k segment of memory, aligned on 8k boundaries.
* `far memory`: RAM not directly accessable by the CPU (from 0x10000 on).
* `low memory`: the first 64k of memory (0x0000 to 0xffff).
* `overlay`: code that lives in far memory that is automatically paged in on demand.
* `slot`: an 8k segment of near memory, aligned on 8k boundaries, where blocks can be paged in.
* `word`: on the F256, a word is 16 bits.
TIP: Be sure to check the F256 hardware documentation to ensure the memory
range you wish to use is valid for what you are trying to accomplish.
For example, not all `far memory` addresses can be accessed by the video
subsystem. Know your hardware!
== API Overview
The *_F256lib_* API is broken down into several general sections:
[cols="1,3",grid=rows,frame=none]
|===
| <<Constants>>
| Provides friendly names for often used hardware addresses, kernel functions, and more.
| <<Types>>
| Helpful data types to keep you code ambiguity-free.
| <<Helpers>>
| Functions for safely dealing with memory and bits.
| <<Kernel>>
| Access to the TinyCore MicroKernel.
| <<DMA>>
| Direct memory access for fast fills and copies.
| <<Math Co-Processor>>
| Highly performant common math functions.
| <<Random Numbers>>
| Easy hardware-assisted random numbers.
| <<Text>>
| Text display layer handling.
| <<Graphics>>
| Common graphic functions shared by the bitmap, sprite, and tile layers.
| <<Bitmaps>>
| Bitmap graphic features.
| <<Sprites>>
| Functions for defining and manipulating sprites.
| <<Tiles>>
| Tile-based graphics features.
| <<File I/O>>
| MicroKernel file I/O wrapped as standard C file functions.
| <<Platform>>
| Bare minimum features needed to support the compiler standard library.
|===
NOTE: Several sections of the documentation mention "screen refresh rate"
dependent settings. At this time, *_F256lib_* only supports 60 Hz.
== API Details
The following section is a detailed description of the API provided by
*_F256lib_*. Only the portions of the API that are considered "stable" are
documented. You may discover other (potentially dangerous) goodies in the
source code.
=== Constants
A _lot_ of constants are provided by *_F256lib_*. Hardware registers, kernel
functions, return values, and more. If they were all listed here, this document
would be longer than anyone cares to read. For the ugly details, please see
the following:
* `f256dev\f256lib\f_api.h` contains kernel information.
* `f256dev\include` is full of header files containing handy contants.
=== Types
*_F256lib_* provides clear, helpful, data types. It's highly recommended
that you use `stdint.h`-style types for integer data to avoid size confusion. In
addition, we recommend using `char` only when you really mean character data,
`byte` for unsigned bytes, and `bool` for boolean values. `true` and `false`
are also provided.
=== Helpers
These helper functions are convenience features for dealing directly
with memory. Using them ensures the compiler will not optimize out
memory accesses that appear to "do nothing" but may be significant to the
hardware.
==== PEEK
[,c]
----
byte value = PEEK(uint16_t address);
----
Returns the 8 bit value of a given low memory address.
==== POKE
[,c]
----
POKE(uint16_t address, byte value);
----
Writes an 8 bit value to a given low memory address.
==== PEEKW
[,c]
----
uint16_t value = PEEKW(uint16_t address);
----
Returns the 16 bit value starting at a given low memory address.
==== POKEW
[,c]
----
POKEW(uint16_t address, uint16_t value);
----
Writes a 16 bit value starting at a given low memory address.
==== POKEA
[,c]
----
POKEA(uint16_t address, uint32_t value);
----
Writes a 24 bit value starting at a given low memory address. The remaining
8 bits of the `value` argument are ignored.
==== PEEKD
[,c]
----
uint32_t value = PEEKD(uint16_t address);
----
Returns the 32 bit value starting at a given low memory address.
==== POKED
[,c]
----
POKED(uint16_t address, uint32_t value);
----
Writes a 32 bit value starting at a given low memory address.
==== FAR_PEEK
[,c]
----
byte value = FAR_PEEK(uint32_t address);
----
Returns the 8 bit value of a given far memory address.
==== FAR_POKE
[,c]
----
FAR_POKE(uint32_t address, byte value);
----
Writes an 8 bit value to a given far memory address.
==== FAR_PEEKW
[,c]
----
uint16_t value = FAR_PEEKW(uint32_t address);
----
Returns the 16 bit value starting at a given far memory address.
==== FAR_POKEW
[,c]
----
FAR_POKEW(uint32_t address, uint16_t value);
----
Writes a 16 bit value starting at a given far memory address.
==== LOW_BYTE
[,c]
----
byte result = LOW_BYTE(int16_t value);
----
Returns the lower byte of a 16 bit word.
==== HIGH_BYTE
[,c]
----
byte result = HIGH_BYTE(int16_t value);
----
Returns the upper byte of a 16 bit word.
==== SWAP_NIBBLES
[,c]
----
byte result = SWAP_NIBBLES(byte value);
----
Returns the byte with the nibbles swapped.
==== SWAP_UINT16
[,c]
----
uint16_t result = SWAP_UINT16(uint16_t value);
----
Returns the word with the upper and lower bytes swapped.
==== CHECK_BIT
[,c]
----
byte result = CHECK_BIT(byte value, byte position);
----
Returns non-zero if the bit at the indicated position is set.
==== TOGGLE_BIT
[,c]
----
byte result = TOGGLE_BIT(byte value, byte position);
----
Returns the byte with the bit at the indicated position flipped.
==== CLEAR_BIT
[,c]
----
byte result = CLEAR_BIT(byte value, byte position);
----
Returns the byte with the bit at the indicated position cleared.
==== SET_BIT
[,c]
----
byte result = SET_BIT(byte value, byte position);
----
Returns the byte with the bit at the indicated position set.
=== Kernel
Kernel functions provide simplified access to the features provided by
https://github.com/ghackwrench/F256_MicroKernel[Gadget's TinyCore MicroKernel].
https://github.com/ghackwrench/F256_MicroKernel/tree/master/docs#readme[MicroKernel documentation]
is beyond the scope of this document.
Kernel interaction relies on two global variables:
[,c]
----
char kernelError;
kernelArgsT *kernelArgs;
----
* `kernelError` will be set to the error code, if any, returned by the kernel.
* `kernelArgs` provides structures to pass data to and receive data from the kernel.
.Keyboard Reading Example:
[,c]
----
do {
kernelNextEvent();
if (kernelEventData.type == kernelEvent(key.PRESSED)) {
printf("Key %c pressed.\n", kernelEventData.key.ascii);
}
} while(true);
----
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]
----
char kernelCall(function);
----
Calls one of the functions provided by the kernel. You will need to fill in the
proper fields in the `kernelArgs` structure prior to calling. `kernelArgs` will
be populated, as appropriate, if the call was successful.
==== kernelEvent
[,c]
----
size_t eventType = kernelEvent(size_t event);
----
Converts a named kernel `event` to the value expected by the `kernelEventData.type` structure.
See the above example for usage.
==== kernelGetPending
[,c]
----
byte kernelGetPending(void);
----
Returns the number of pending kernel events that need to be handled by your program.
==== kernelNextEvent
[,c]
----
void kernelNextEvent(void);
----
When using the kernel, you must call this function to "pump" the kernel's event queue.
Failing to call this often enough can starve the kernel of event objects.
=== DMA
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
[,c]
----
void dma2dFill(uint32_t start, uint16_t width, uint16_t height, uint16_t stride, byte value);
----
Fills a rectangular section of memory (near or far) with a value.
==== dmaFill
[,c]
----
void dmaFill(uint32_t start, uint32_t length, byte value);
----
Fills a linear section of memory (near or far) with a value.
=== Math Co-Processor
These functions provide vastly faster math operations than using the CPU alone.
Use them whenever possible!
==== mathSignedDivision
[,c]
----
int16_t mathSignedDivision(int16_t a, int16_t b);
----
Performs signed division on two 16 bit signed integer values.
Any remainder is discarded.
==== mathSignedDivisionRemainder
[,c]
----
int16_t mathSignedDivisionRemainder(int16_t a, int16_t b, int16_t *remainder);
----
Performs signed division on two 16 bit signed integer values. The remainder is
returned in the pointer passed as the `remainder` argument.
==== mathSignedMultiply
[,c]
----
int32_t mathSignedMultiply(int16_t a, int16_t b);
----
Performs signed multiplication of two signed 16 bit integer values.
NOTE: The return value is 32 bits.
==== mathUnsignedAddition
[,c]
----
uint32_t mathUnsignedAddition(uint32_t a, uint32_t b);
----
Performs unsigned multiplication of two unsigned 16 bit integer values.
NOTE: The return value is 32 bits.
==== mathUnsignedDivision
[,c]
----
uint16_t mathUnsignedDivision(uint16_t a, uint16_t b);
----
Performs unsigned division on two 16 bit unsigned integer values.
Any remainder is discarded.
==== mathUnsignedDivisionRemainder
[,c]
----
uint16_t mathUnsignedDivisionRemainder(uint16_t a, uint16_t b, uint16_t *remainder);
----
Performs unsigned division on two 16 bit unsigned integer values. The remainder is
returned in the pointer passed as the `remainder` argument.
==== mathUnsignedMultiply
[,c]
----
uint32_t mathUnsignedMultiply(uint16_t a, uint16_t b);
----
Performs unsigned multiplication of two unsigned 16 bit integer values.
NOTE: The return value is 32 bits.
=== Random Numbers
Generating good psuedo-random numbers is a significant challenge. Fortunately
the Foenix F256 has hardware-assisted random number generation.
==== randomRead
[,c]
----
uint16_t randomRead(void);
----
Returns the next psuedo-random unsigned 16 bit integer.
==== randomSeed
[,c]
----
void randomSeed(uint16_t seed);
----
Specifies the starting value for the psuedo-random number generator. Use this
to generate a reproducable sequence of "random" values.
On startup, the psuedo-random number generator is seeded from the real-time
clock, if available.
=== Text
On startup, the text layer is cleared, background colors are disabled, the
foreground color is set to white, the background to black, the cursor disabled,
and the font set to double-height producing an 80 column by 25 line display.
[,c]
----
void textClear(void);
----
Clears the text layer to the current text colors. Returns the cursor to the
upper-left corner.
[,c]
----
void textDefineBackgroundColor(byte slot, byte r, byte g, byte b);
----
Defines one of the 16 available colors in the text background color table.
`slot` specifies which color to define, 0 through 15. `r`, `g`, and `b` specify
how much of each color component to use, 0 through 255.
[,c]
----
void textDefineForegroundColor(byte slot, byte r, byte g, byte b);
----
Defines one of the 16 available colors in the text foreground color table.
`slot` specifies which color to define, 0 through 15. `r`, `g`, and `b` specify
how much of each color component to use, 0 through 255.
[,c]
----
void textEnableBackgroundColors(bool b);
----
Enabling background colors obscures any graphics layers behind the text layer.
[,c]
----
void textGetXY(byte *x, byte *y);
----
Returns the position of the cursor in the pointers `x` and `y`.
[,c]
----
void textGotoXY(byte x, byte y);
----
Moves the cursor to a new position at `x`, `y`. The valid values for the new
location depend on the current screen refresh rate and text doubling settings.
[,c]
----
void textPrint(char *message);
----
Displays the string `message` at the current cursor position. This function
uses much less code than using `printf()`.
[,c]
----
void textPrintInt(int32_t value);
----
Displays the signed integer `value` at the current cursor position. This function
uses much less code than using `printf()`.
[,c]
----
void textPrintUInt(uint32_t value);
----
Displays the unsigned integer `value` at the current cursor position. This function
uses much less code than using `printf()`.
[,c]
----
void textSetColor(byte f, byte b);
----
Specifies which color slots to use for the foreground and background colors of
future text output.
[,c]
----
void textSetCursor(byte c);
----
Specifies which ASCII character code to use as a cursor. Setting the cursor
to `0` will disable it.
[,c]
----
void textSetDouble(bool x, bool y);
----
Specifies wether or not to double the size of displayed characters on the `x`,
`y`, or both axis. Depending on the video refresh rate, this allows you to
produce text displays of the following sizes:
* At 60 Hz:
** 80x60
** 40x60
** 80x30
** 40x30
* At 70 Hz:
** 80x50
** 40x50
** 80x25
** 40x25
=== Graphics
Functions in this category affect the graphics system in general. They are used
to configure layers, colors, etc. To actually produce something on the display,
you'll need to use these functions in conjunction with functions from another
graphics subsystem.
The graphics system consists of three layers. By default, each layer is set
to its associated `bitmap`. (Layer 0 is Bitmap 0 and so on.)
==== graphicsDefineColor
[,c]
----
void graphicsDefineColor(byte clut, byte slot, byte r, byte g, byte b);
----
Defines one of the 256 available colors in one of the four graphics color tables.
`clut` is which color lookup table to modify, 0 through 4. `slot` specifies
which color index to define, 0 through 255. `r`, `g`, and `b` specify
how much of each color component to use, 0 through 255.
==== graphicsSetLayerBitmap
[,c]
----
void graphicsSetLayerBitmap(byte layer, byte which);
----
Specifies that `layer` (0 to 3) should display bitmap number `which` (0 to 3).
==== graphicsSetLayerTile
[,c]
----
void graphicsSetLayerTile(byte layer, byte which);
----
Specifies that `layer` (0 to 3) should display tilemap number `which` (0 to 3).
==== graphicsWaitVerticalBlank
[,c]
----
void graphicsWaitVerticalBlank(void);
----
Pauses program execution until the start of a vertical blank.
=== Bitmaps
The Foenix F256 can display up to three full-screen bitmaps at a time. Depending
on the screen refresh, the bitmaps are:
* At 60 Hz:
** 320x240 pixels
* At 70 Hz:
** 320x200 pixels
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 at the top of the far memory available to the Vicky graphics chip:
* Page 0 - 0x6c000 -> 0x7ebff
* Page 1 - 0x58000 -> 0x6abff
* Page 2 - 0x44000 -> 0x56bff
IMPORTANT: Be sure your program avoids using these memory ranges if you use
these pages!
NOTE: You may have noticed each bitmap page is aligned on an 8k boundary leaving
5k unused between each page. If you need this memory, go for it.
==== bitmapClear
[,c]
----
void bitmapClear(void);
----
Clears the currently active bitmap to the current color.
==== bitmapGetResolution
[,c]
----
void bitmapGetResolution(uint16_t *x, uint16_t *y);
----
Returns the size of the current bitmap in the pointers `x` and `y`.
==== bitmapLine
[,c]
----
void bitmapLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
----
Draws a line on the current bitmap in the current color from
`(x1, y1)` to `(x2, y2)`.
==== bitmapPutPixel
[,c]
----
void bitmapPutPixel(uint16_t x, uint16_t y);
----
Plots a single pixel on the current bitmap in the current color at
`(x, y)`.
==== bitmapSetActive
[,c]
----
void bitmapSetActive(byte p);
----
Specifies the currently active bitmap from 0 to 3.
==== bitmapSetAddress
[,c]
----
void bitmapSetAddress(byte p, uint32_t a);
----
Allows you to change where in far memory a bitmap is located. Bitmap page `p`
will be assigned to start at memory address `a`. Addresses must be aligned on
an 8k boundary (evenly divisible by 8192).
==== bitmapSetCLUT
[,c]
----
void bitmapSetCLUT(byte clut);
----
Specifies which color look up table to use for the current bitmap. Each bitmap
can have its own palette of 256 colors.
==== bitmapSetColor
[,c]
----
void bitmapSetColor(byte c);
----
Specifies the current color index in the current color table to use for future
drawing operations on the current bitmap.
==== bitmapSetVisible
[,c]
----
void bitmapSetVisible(byte p, bool v);
----
Specifies if bitmap page `p` is visible or not.
=== Sprites
The Foenix F256 provides 64 independent sprites with three sprite layers.
Sprites are small bitmaps of the following sizes:
* 8x8
* 16x16
* 24x24
* 32x32
To allow sprites to smootly enter and exit the screen, sprite coordinates are
larger than bitmap and tile coordinates. Sprite coordinates are:
* For 60 Hz:
** 352x272
* For 70 Hz:
** 352x232
The first 32 pixels are off the screen to the left and top. Sprites beyond the
horizontal and vertical resolutions shown are off the right and bottom of the
screen. See the hardware documentation for more details.
==== spriteDefine
[,c]
----
void spriteDefine(byte s, uint32_t address, byte size, byte CLUT, byte layer);
----
Assigns a block of memory to a given sprite. Sprite number `s` (0 to 63) will
pull its pixel data starting at `address` which can be in either near or far
memory. `size` is either 8, 16, 24, or 32. Each sprite can pull its color
information from one of the four (0 to 3) color lookup tables specified in
`CLUT`. `layer` specifies which of the three sprite layers you wish to use
(0 to 2).
==== spriteSetPosition
[,c]
----
void spriteSetPosition(byte s, uint16_t x, uint16_t y);
----
Positions sprite number `s` at location `(x, y)`.
TIP: Remember! Sprite coordinates are not the same as other graphics coordinates!
==== spriteSetVisible
[,c]
----
void spriteSetVisible(byte s, bool v);
----
Determines if sprite number `s` is visible on the display. All sprites begin
life hidden.
=== Tiles
Tile maps are composed of individual "tiles" of pixels that are either 8x8 or
16x16 in size. Tile maps can be smoothly scrolled horizontally and vertically.
Like bitmaps and sprites, each
==== tileDefineTileMap
[,c]
----
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]
----
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]
----
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]
----
void tileSetVisible(byte t, bool v);
----
Determines the visibility `v` of a particular tile map `t` (0 to 2).
=== File I/O
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.
Supported functions are listed below. For usage details, see the documentation
for the standard C library.
* `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!
=== Platform
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
Embedding binary data (sprites, tiles, bitmaps, whatever) into your program
at a specific memory address can be easily achieved with the `EMBED` macro.
=== 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".
== Optional Options
Before including *_F256lib_*, you may wish to define one or more of the following
to customize the library for your application:
|===
| `#DEFINE` |Description
| `SWAP_RESTORE`
| When using functions such as `FAR_PEEK` or bitmap features, return the swap slot back to it's original memory location before returning. By default, the swap slot is left in whatever state the last function that used it switched it to.
| `WITHOUT_GRAPHICS`
| Shortcut for `WITHOUT_BITMAP`, `WITHOUT_TILE`, and `WITHOUT_SPRITE`.
| `WITHOUT_BITMAP`
| Disables bitmap functions.
| `WITHOUT_TILE`
| Disables tilemap functions.
| `WITHOUT_SPRITE`
| Disables sprite functions.
| `WITHOUT_FILE`
| Disables file handling support.
| `WITHOUT_KERNEL`
| Disables microkernel support. Also disables `FILE`, `PLATFORM`, and `MAIN`.
| `WITHOUT_TEXT`
| Disables text functions. Also disables `PLATFORM`.
| `WITHOUT_MATH`
| Disables math co-processor support. Also disables `TEXT`, `PLATFORM` and `BITMAP`.
| `WITHOUT_MAIN`
| Removes support for the standardized `int main(int argc, char *argv[])` function and replaces it with `int main(void)`. You must also manually call `f256Init()` at the start of your program.
| `WITHOUT_PLATFORM`
| Removes basic C library I/O support for `getchar()` and `__putchar()`. This removes `printf()`.
| `WITHOUT_DMA`
| Removes DMA support. In the future, will also disable `BITMAP`.
|===
.Example:
[,c]
----
#define WITHOUT_FILE
#define WITHOUT_SPRITE
#define WITHOUT_TILE
#define F256LIB_IMPLEMENTATION
#include "f256lib.h"
int main(int argc, char *argv[]) {
return 0;
}
----
The compiler is really good at removing dead code so this isn't usually needed.
It's primarily helpful to purposefully diable features so you receive errors if
you attempt to use them.
== Support
Drop by the https://discord.gg/e32efF7FGy[Foenix Retro Systems Discord]!
I am almost always online as "sduensin".
Additional information on the F256 family of computers can be found on the
http://wiki.f256foenix.com/[F256 wiki].
As a last resort, you can email me, Scott Duensing, at scott@kangaroopunch.com
and I'll probably ask you to join the Discord. :-)