Optional AMEM
#include "libtini/amem.h"
The private AMEM memory service of the Appletini can make large banked transfers faster. It operates behind the usual resource API. The default build does not include the transport. The CPU path is always present and is the reference.
| Function | Purpose |
|---|---|
ti_amem_enable | Identify the controller and the service, then use them for permitted transfers |
ti_amem_disable | Use CPU transfers again |
ti_amem_available | Tell if acceleration is active |
ti_amem_last_error | Get the last error byte of the controller |
The AMEM build
python tools/build.py --cc65-home D:/Repos/cc65 --private --build-dir build/private
This command builds the library again with TI_PRIVATE_TRANSPORT=1 and the slot-7 FIFO transport, into build/private/. It also builds each game whose manifest does not set "private": false. The CPU-only outputs in build/ do not change. STARFALL has no AMEM build. In the default build, the four functions exist, but enable returns TI_E_UNAVAILABLE.
Accelerated transfers
ti_res_read,ti_res_writeandti_res_fillof 256 bytes or more.ti_res_copyof 256 bytes or more between two different resources. Copies in one resource stay on the CPU, also when they do not overlap.- The library splits large transfers at each bank boundary. The checks and buffer lifetimes are the same as on the CPU path. Each request writes only to private work memory.
AMEM never writes the screen. Publication, the backup and restore of the video session, and the screen loans of storage always use CPU writes. AMEM is not a framebuffer blitter. For small transfers, the request overhead can be more than the time of a CPU loop. See the benchmark notes.
Failure rules
A service can be missing, not supported or not available before the first request of a transfer. Then that transfer uses the CPU, and the call reports no error.
After a part of a transfer used AMEM, each failure returns TI_E_IO. The first pieces of the transfer can already have changed the destination. Thus the library never repeats the operation with CPU copies. Treat the destination as possibly partial, and recover at the transaction boundary of your program.
Some failures also stop the driver for the rest of the program. These failures are a failed request, a response that does not arrive and a response with an incorrect format. After such a failure, enable and transfers return TI_E_IO and send nothing.
The wait for a response is a maximum of 240 changes of the //e vertical blank flag, independent of the CPU speed. This is 2 seconds at 60 Hz and 2.4 seconds at 50 Hz. The time during which the controller holds the CPU does not count. Do not use disable and enable as an automatic retry after a failure of unknown effect.
Functions
ti_amem_enable
ti_error ti_amem_enable(void);
Call this function after ti_init. With interrupts masked, it gets the slot-7 expansion ROM space and saves INTCXROM. It examines the C700 ROM: its signature bytes and a CRC-16/CCITT-FALSE of $95D9 over the 256 bytes. This identifies the controller of F1.3.2. An unidentified controller receives no request.
A correct controller receives a STATUS request for the AMEM service. The service must report the AMEM signature, a supported major version and descriptor size, copy and fill support, the $0200-$BFFF windows and PRIVATE support. The transport then restores the interrupt state and INTCXROM of the caller and releases the expansion ROM space. It does not select again an expansion ROM that was selected before the call.
Each subsequent transfer does the STATUS check again before its first request, and it checks the highest bank that the service reports. The audio driver pauses during each request. Long requests mark a timing gap.
Returns
TI_OK when acceleration is active; TI_E_UNAVAILABLE for an unidentified controller, for a service that reports that it is not available or not supported, or in a CPU-only build; TI_E_IO for a stopped driver or a failed STATUS exchange.
ti_amem_disable
void ti_amem_disable(void);
This function removes the acceleration hooks. Transfers then use the CPU. The function does not start a stopped driver again, and it does not repair partly changed data. ti_shutdown also removes the hooks. After a new ti_init, call enable again.
ti_amem_available
uint8_t ti_amem_available(void);
This function returns 1 while acceleration is enabled, the driver is not stopped and the hooks are installed. In a CPU-only build, it returns 0.
ti_amem_last_error
uint8_t ti_amem_last_error(void);
This function returns the last error byte from the controller or the driver. The driver sets $61 for a STATUS reply with an incorrect format and $67 for a response timeout. A CPU-only build returns $21.
While a request runs, other foreground code and NMI handlers must not use the slot-7 expansion ROM space or the FIFO at $CFF0-$CFF2.