API¶
Application Programming Interface
Introduction¶
The API is how a 6502 program uses the host. A call such as open()
or time() is passed through the registers of the RIA to the
host, which does the work and passes the result back, much like a remote
procedure call. The host runs outside the 6502 and uses none of its RAM,
so all of RAM remains available to the program, and that program can
even be a 6502 operating system of your own.
The API comes with the compilers. It is part of the C libraries of cc65 and llvm-mos, so a program needs nothing else to use it. This is the “Hello, world!” program of the SDK template:
#include <rp6502.h>
#include <stdio.h>
#include "xram.h"
int main(void)
{
puts("Hello, world!");
}
puts() is the standard C function. In both compilers it ends in
WRITE_XSTACK, an API call that passes the bytes to the RIA, and the host
writes them to the console. Most of the API is standard C in this way:
stdio.h and unistd.h for the console and files, and time.h
for the clock. rp6502.h adds what standard C has no call for: access
to XRAM, the settings of the RIA, the filesystem abstraction, the line
editor, and starting another ROM.
The API does not reach the gamepads, the video or the sound. A program
drives those through XRAM and extended registers (XREGs), described in
the RIA and VGA datasheets. The API provides xreg()
and the XRAM calls that set them up.
Underneath the C functions is the Application Binary Interface (ABI), the register-level form of each call. A C program never sees it. The ABI is at the end of this page, for assembly programs and for anyone bringing another compiler to the Picocomputer.
Application Programming Interface¶
Most calls match their POSIX counterparts. The filesystem calls follow
FAT, the standard filesystem of USB drives and memory cards, so
f_stat() stands in for stat() with FAT’s attributes and dates.
A few calls take their arguments in a different order in the ABI than
in C. The flags described below mark the two forms where they differ.
Each operation below is one or more C declarations followed by a short list of details. Some declarations carry a flag:
ABI marks a prototype that is only the ABI form. LIB marks a
prototype that exists only in the library. A prototype with neither flag
is both.
Op code is the value a program writes to RIA_OP to start the
operation. An entry with only LIB prototypes has no op code.
C proto names the header the declaration comes from.
a regs names the arguments and the return value that fit in RIA_A
alone, so a program can leave RIA_X unset. errno lists what can
go wrong, and Errno Translations gives the number of each.
Registers¶
DROP¶
-
void ria_drop(void);¶
Empty the XSTACK by resetting its pointer. This is the only operation that finishes immediately, so there is no need to wait for it. It is never needed after a failed operation, because a failure already empties the XSTACK. Use it to discard the rest of a returned structure, or arguments already pushed for a call you decide not to make.
- Op code:
RIA_OP_DROP_XSTACK 0x00
- C proto:
rp6502.h
SPIN¶
-
lib int ria_spin(void)¶
Waits for the running API call to finish and returns
RIA_AandRIA_Xas an int. A call toria_spin()is aJSR RIA_SPIN, as described under Application Binary Interface.- C proto:
rp6502.h
VSYNC¶
IRQ¶
-
lib unsigned char ria_irq_read(void)¶
-
lib void ria_irq_write(unsigned char mask)¶
ria_irq_read()returns the triggered signals and clears them.ria_irq_write()sets the enable mask and also clears any triggered signals. Bit 7 is VSYNC and bit 6 is SIGINT, as in the register table of the RIA datasheet.- C proto:
rp6502.h
- Parameters:
mask – Signals to enable.
Extended Memory¶
XREG¶
-
int xreg(char device, char channel, unsigned char address, ...);¶
-
lib int xregn(char device, char channel, unsigned char address, unsigned count, ...);¶
Prefer xreg() from C to avoid a counting mistake. The count isn’t sent over the ABI, so both prototypes are equally valid.
The variadic argument is a list of ints to store in the extended registers, starting at address on the given device and channel. See Extended Registers in the RIA datasheet and the VGA datasheet for what each register does. Setting an extended register can fail, which doubles as feature detection: EINVAL means the device sent a negative acknowledgement, EIO means a timeout waiting for ack/nak, and EACCES means a write to the VGA control channel, which the RIA manages.
This is how you add virtual hardware to extended RAM. Both the RIA and the VGA include virtual devices you can install, and you can build your own hardware for the PIX bus and configure it with this same call.
Assembly programs use the
xregmacro in rp6502.inc, which takes the same arguments:xreg 1, 0, 1, 3, 2, $FF00.- Op code:
RIA_OP_XREG 0x01
- C proto:
rp6502.h
- Parameters:
device – PIX device ID. 0:RIA, 1:VGA, 2-6:unassigned
channel – PIX channel. 0-15
address – PIX address. 0-255
... – 16 bit integers to set starting at address.
- A regs:
return
- Errno:
EACCES, EINVAL, EIO
XRAM_READ¶
-
lib void xram0_read(void *dest, unsigned src, unsigned count)¶
-
lib void xram1_read(void *dest, unsigned src, unsigned count)¶
Copy
countbytes from XRAM to 6502 RAM, likememcpy.xram0_read()copies through portal 0 andxram1_read()through portal 1, the two XRAM portals of the RIA. The other portal is not touched. A count of 0 copies nothing.The call changes the portal’s address register and sets its step register to 1.
This copies within the machine. To load XRAM from a file, use READ_XRAM.
- C proto:
rp6502.h
- Parameters:
dest – Destination in 6502 RAM.
src – Source address in XRAM.
count – Quantity of bytes to copy.
XRAM_WRITE¶
-
lib void xram0_write(unsigned dest, const void *src, unsigned count)¶
-
lib void xram1_write(unsigned dest, const void *src, unsigned count)¶
Copy
countbytes from 6502 RAM into XRAM. This is the other direction of XRAM_READ and follows the same rules.- C proto:
rp6502.h
- Parameters:
dest – Destination address in XRAM.
src – Source in 6502 RAM.
count – Quantity of bytes to copy.
XRAM_SET¶
-
lib void xram0_set(unsigned dest, unsigned char val, unsigned count)¶
-
lib void xram1_set(unsigned dest, unsigned char val, unsigned count)¶
Fill
countbytes of XRAM withval, likememset.xram0_set()uses portal 0 andxram1_set()uses portal 1, with the same effect on the portal’s registers as XRAM_READ.- C proto:
rp6502.h
- Parameters:
dest – Address in XRAM to fill.
val – Byte written to every position.
count – Quantity of bytes to fill.
XRAM_MOVE¶
-
lib void xram_move(unsigned dest, unsigned src, unsigned count)¶
Copy
countbytes from one XRAM address to another, likememmove, so the result is correct even when the two ranges overlap. Portal 0 reads and portal 1 writes, and both address registers are changed. Both step registers are left at 1, or at -1 if the destination overlaps the end of the source and the copy runs backward.- C proto:
rp6502.h
- Parameters:
dest – Destination address in XRAM.
src – Source address in XRAM.
count – Quantity of bytes to copy.
XRAM_PEEK¶
-
lib unsigned char xram0_peek8(unsigned addr)¶
-
lib unsigned char xram1_peek8(unsigned addr)¶
-
lib unsigned xram0_peek16(unsigned addr)¶
-
lib unsigned xram1_peek16(unsigned addr)¶
Read one value from XRAM.
xram0_peek8()andxram0_peek16()read through portal 0, andxram1_peek8()andxram1_peek16()through portal 1. The other portal is not touched.The 8-bit calls read one byte and leave the step register unchanged. The 16-bit calls read two bytes, low byte first, and set the step register to 1. Every call changes the address register of the portal it uses.
- C proto:
rp6502.h
- Parameters:
addr – Address in XRAM to read.
- Returns:
The value read.
XRAM_POKE¶
-
lib void xram0_poke8(unsigned addr, unsigned char val)¶
-
lib void xram1_poke8(unsigned addr, unsigned char val)¶
-
lib void xram0_poke16(unsigned addr, unsigned val)¶
-
lib void xram1_poke16(unsigned addr, unsigned val)¶
Write one value to XRAM. This is the other direction of XRAM_PEEK and follows the same rules.
- C proto:
rp6502.h
- Parameters:
addr – Address in XRAM to write.
val – Value to write.
Process¶
ARGV¶
-
ABI int _argv(char *argv, int size)¶
The virtual _argv is called during C initialization to supply argc and argv to main(). It returns an array of zero-terminated string indexes followed by the strings themselves. The returned data is guaranteed valid. For example, [“ABC”, “DEF”] is:
06 00 0A 00 00 00 41 42 43 00 44 45 46 00
Because this can use up to 512 bytes of RAM, you opt in by defining
__argv_mem()to provide storage for the argv data. Use static memory, or dynamically allocated memory you can free afterward. You can also reject an oversized argv by returning NULL. The argv data is on the XSTACK while__argv_mem()runs, so__argv_mem()must not make an API call, not even through printf().void *__argv_mem(size_t size) { return malloc(size); }
- Op code:
RIA_OP_ARGV 0x08
- C proto:
(none)
- Returns:
Size of argv data
- Errno:
will not fail
EXEC¶
-
ABI int _exec(const char *argv, int size)¶
-
lib int ria_execl(const char *path, ...)¶
-
lib int ria_execv(const char *path, char *const argv[])¶
The virtual _exec is called by ria_execl() and ria_execv(). Note one difference from the execl() and execv() you may know: because RAM is precious, the path is supplied once, not again in argv[0]. In the launched ROM, argv[0] is the absolute form of the path given, with its drive, or
:NAMEfor a ROM on the null drive, as described in Installed ROMs.The data sent by _exec() is checked for pointer safety and sanity, but the path is assumed to point at a loadable ROM file. On EINVAL, the argv buffer is cleared, so later calls to _argv() return an empty set. If the ROM turns out to be invalid, the user is dropped back to the console with an error message.
The ria_execl() and ria_execv() wrappers accept at most 16 strings (the path plus up to 15 arguments) totaling no more than 512 bytes including the offset table; exceeding either limit returns -1 with EINVAL.
- Op code:
RIA_OP_EXEC 0x09
- C proto:
rp6502.h
- Returns:
Does not return on success — the new ROM begins executing. -1 on error.
- Errno:
EINVAL
EXIT¶
-
void exit(int status)¶
Halt the 6502 and hand the console back to the machine. This is the only operation that never returns; the OS pulls RESB low before the next instruction can execute. The status value is kept for the next ROM and is readable via
RIA_ATTR_EXIT_CODE.Dropping the user out of your program is generally discouraged, but calling exit() beats locking up, as does falling off the end of main().
- Op code:
RIA_OP_EXIT 0xFF
- C proto:
stdlib.h
- Parameters:
status – 0 is success, and any other value is an error.
Files¶
OPEN¶
-
int open(const char *path, int oflag)¶
Create a connection between a file and a file descriptor.
The options must include O_RDONLY, O_WRONLY or O_RDWR, or the call fails with EINVAL. An open of a directory fails with EACCES. A file can be open on several descriptors at once. Close a descriptor that writes a file before opening that file again, as described in Files and Folders.
A path can also name a device. See TERM for
CON:andTTY:, the SDK forROM:followed by an asset name, and PORT forSAVE:followed by a save name. See the RIA datasheet forVCP0:,MIDI0:andNFC:, and the RP6502-PICO-W page forAT:.- Op code:
RIA_OP_OPEN 0x14
- C proto:
fcntl.h
- Parameters:
path – Pathname to a file.
oflag – Bitfield of options.
- Returns:
File descriptor. -1 on error.
- A regs:
return, oflag
- Errno:
EACCES, EBUSY, EEXIST, EINVAL, EIO, EMFILE, ENODEV, ENOENT, ENOMEM, ENOSPC
- Options:
- O_RDONLY 0x01Open for reading only.O_WRONLY 0x02Open for writing only.O_RDWR 0x03Open for reading and writing.O_CREAT 0x10Create the file if it does not exist.O_TRUNC 0x20Truncate the file length to 0 after opening.O_APPEND 0x40Read/write pointer is set to the end of the file at open.O_EXCL 0x80If O_CREAT and O_EXCL are set, fail if the file exists.
CLOSE¶
-
int close(int fildes)¶
Finish pending writes and release the file descriptor. The descriptor goes back to the pool that open() draws from. What survives a failure after close differs by machine, as listed in Durability.
- Op code:
RIA_OP_CLOSE 0x15
- C proto:
fcntl.h
- Parameters:
fildes – File descriptor from open().
- Returns:
0 on success. -1 on error.
- A regs:
return, fildes
- Errno:
EBADF, EIO, ENOSPC
READ¶
-
lib int read(int fildes, void *buf, unsigned count)¶
Read
countbytes from a file into a buffer. This is implemented in the compiler library as a series of calls to READ_XSTACK.- C proto:
unistd.h
- Parameters:
buf – Destination for the returned data.
count – Quantity of bytes to read. 0x7FFF max.
fildes – File descriptor from open().
- Returns:
On success, number of bytes read is returned. On error, -1 is returned.
- A regs:
fildes
- Errno:
EACCES, EAGAIN, EBADF, EBUSY, EINTR, EINVAL, EIO, ENOSYS
READ_XSTACK¶
-
int read_xstack(void *buf, unsigned count, int fildes)¶
Read
countbytes from a file to the XSTACK.- Op code:
RIA_OP_READ_XSTACK 0x16
- C proto:
rp6502.h
- Parameters:
buf – Destination for the returned data.
count – Quantity of bytes to read. 0x200 max.
fildes – File descriptor from open().
- Returns:
On success, number of bytes read is returned. On error, -1 is returned.
- A regs:
fildes
- Errno:
EACCES, EAGAIN, EBADF, EBUSY, EINTR, EINVAL, EIO, ENOSYS
READ_XRAM¶
-
int read_xram(unsigned buf, unsigned count, int fildes)¶
Read
countbytes from a file to XRAM.- Op code:
RIA_OP_READ_XRAM 0x17
- C proto:
rp6502.h
- Parameters:
buf – Destination for the returned data.
count – Quantity of bytes to read. 0x7FFF max.
fildes – File descriptor from open().
- Returns:
On success, number of bytes read is returned. On error, -1 is returned.
- A regs:
fildes
- Errno:
EACCES, EAGAIN, EBADF, EBUSY, EINTR, EINVAL, EIO, ENOSYS
WRITE¶
-
lib int write(int fildes, const void *buf, unsigned count)¶
Write
countbytes from a buffer to a file. This is implemented in the compiler library as a series of calls to WRITE_XSTACK.- C proto:
unistd.h
- Parameters:
buf – Location of the data.
count – Quantity of bytes to write. 0x7FFF max.
fildes – File descriptor from open().
- Returns:
On success, number of bytes written is returned. On error, -1 is returned.
- A regs:
fildes
- Errno:
EACCES, EAGAIN, EBADF, EBUSY, EINTR, EINVAL, EIO, ENOSPC, ENOSYS
WRITE_XSTACK¶
-
int write_xstack(const void *buf, unsigned count, int fildes)¶
Write
countbytes from the XSTACK to a file.- Op code:
RIA_OP_WRITE_XSTACK 0x18
- C proto:
rp6502.h
- Parameters:
buf – Location of the data.
count – Quantity of bytes to write. 0x200 max.
fildes – File descriptor from open().
- Returns:
On success, number of bytes written is returned. On error, -1 is returned.
- A regs:
fildes
- Errno:
EACCES, EAGAIN, EBADF, EBUSY, EINTR, EINVAL, EIO, ENOSPC, ENOSYS
WRITE_XRAM¶
-
int write_xram(unsigned buf, unsigned count, int fildes)¶
Write
countbytes from XRAM to a file.- Op code:
RIA_OP_WRITE_XRAM 0x19
- C proto:
rp6502.h
- Parameters:
buf – Location of the data.
count – Quantity of bytes to write. 0x7FFF max.
fildes – File descriptor from open().
- Returns:
On success, number of bytes written is returned. On error, -1 is returned.
- A regs:
fildes
- Errno:
EACCES, EAGAIN, EBADF, EBUSY, EINTR, EINVAL, EIO, ENOSPC, ENOSYS
LSEEK¶
-
ABI long f_lseek(long offset, unsigned char whence, int fildes)¶
-
lib off_t lseek(int fildes, off_t offset, int whence)¶
Move the read/write pointer.
This can also be used to obtain the current read/write position with
f_lseek(0, SEEK_CUR, fd).A seek past the end of a file opened for writing extends the file with zeros. On a full drive, that seek fails with ENOSPC and leaves the file and the position unchanged. A seek past the end of a file opened only for reading stops at the end.
- Op code:
See table below.
- C proto:
f_lseek: rp6502.h, lseek: unistd.h
- Parameters:
offset – Distance to move the pointer.
whence – Where the offset is measured from. See table below.
fildes – File descriptor from open().
- Returns:
Read/write position. -1 on error. A resulting position past 0x7FFFFFFF cannot be represented in the returned long; the seek then fails with errno ERANGE and the file position is left unchanged.
- A regs:
fildes
- Errno:
EBADF, EINVAL, EIO, ENOSPC, ENOSYS, ERANGE, ESPIPE
RIA_OP_LSEEK_LLVM
RIA_OP_LSEEK_CC65
RIA_OP_LSEEK
0x1D
0x1A
SEEK_SET
0
2
SEEK_CUR
1
0
SEEK_END
2
1
SYNCFS¶
-
int syncfs(int fildes)¶
Finish pending writes for the file descriptor. The call returns once the data is stored, within the limits of each machine listed in Durability.
- Op code:
RIA_OP_SYNCFS 0x1E
- C proto:
unistd.h
- Parameters:
fildes – File descriptor from open().
- Returns:
0 on success. -1 on error.
- A regs:
return, fildes
- Errno:
EACCES, EBADF, EINVAL, EIO, ENOSPC, ENOSYS
ISATTY¶
-
lib int isatty(int fildes)¶
Test whether a file descriptor is the console.
stdin,stdout,stderr,CON:andTTY:are the console, as described in the console manifold.- C proto:
unistd.h
- Parameters:
fildes – File descriptor.
- Returns:
1 for the console. 0 for any other file descriptor.
Paths¶
STAT¶
-
int f_stat(const char *path, f_stat_t *dirent)¶
Returns file or directory info for requested path. See the FatFs documentation for details about the data structure.
typedef struct { unsigned long fsize; unsigned fdate; unsigned ftime; unsigned crdate; unsigned crtime; unsigned char fattrib; char altname[12 + 1]; char fname[255 + 1]; } f_stat_t;
A drive root, such as
/orMSC0:/, returns one fixed entry: a directory named/, with size 0 and zero dates. An empty path or a bare drive name, such asMSC0:, fails with EINVAL.- Op code:
RIA_OP_STAT 0x1F
- C proto:
rp6502.h
- Parameters:
path – Pathname to a directory entry.
dirent – Returned f_stat_t data.
- Returns:
0 on success. -1 on error.
- A regs:
return
- Errno:
EACCES, EINVAL, EIO, ENODEV, ENOENT, ENOMEM, ENOSYS
UNLINK¶
-
int unlink(const char *name)¶
Removes a file or directory from the volume. A read-only file fails with EACCES. Close a file before removing it.
- Op code:
RIA_OP_UNLINK 0x1B
- C proto:
unistd.h
- Parameters:
name – File or directory name to unlink (remove).
- Returns:
0 on success. -1 on error.
- A regs:
return
- Errno:
EACCES, EBUSY, EINVAL, EIO, ENODEV, ENOENT, ENOMEM, ENOSYS
RENAME¶
-
int rename(const char *oldname, const char *newname)¶
Renames or moves a file or directory within its drive. A new name on another drive fails with ENODEV. A file already at the new name is replaced when the old name is also a file, and any other entry at the new name fails with EEXIST. Close a file before renaming it, and before a rename replaces it.
- Op code:
RIA_OP_RENAME 0x1C
- C proto:
stdio.h
- Parameters:
oldname – Existing file or directory name to rename.
newname – New object name.
- Returns:
0 on success. -1 on error.
- A regs:
return
- Errno:
EACCES, EBUSY, EEXIST, EINVAL, EIO, ENODEV, ENOENT, ENOMEM, ENOSPC, ENOSYS
CHMOD¶
-
int f_chmod(const char *path, unsigned char attr, unsigned char mask)¶
Change the attributes of a file or directory.
- Op code:
RIA_OP_CHMOD 0x26
- C proto:
rp6502.h
- Parameters:
path – Pathname to a file or directory.
attr – New bitfield of attributes. See table.
mask – Only attributes with bits set here will be changed.
- Returns:
0 on success. -1 on error.
- A regs:
return, mask
- Errno:
EACCES, EINVAL, EIO, ENODEV, ENOENT, ENOMEM, ENOSYS
Attribute
Bit
Read Only
0x01
Hidden
0x02
System
0x04
Directory
0x10
Archive
0x20
UTIME¶
-
int f_utime(const char *path, unsigned fdate, unsigned ftime, unsigned crdate, unsigned crtime)¶
Update the date and time stamps of a file or directory. A date of 0 (invalid) leaves the date and time unchanged.
- Op code:
RIA_OP_UTIME 0x27
- C proto:
rp6502.h
- Parameters:
path – Pathname to a file or directory.
fdate – Modification date.
ftime – Modification time.
crdate – Creation date.
crtime – Creation time.
- Returns:
0 on success. -1 on error.
- A regs:
return
- Errno:
EACCES, EINVAL, EIO, ENODEV, ENOENT, ENOMEM, ENOSYS
Date¶ bit15:9
Years since 1980 (0..127)
bit8:5
Month (1..12)
bit4:0
Day (1..31)
Time¶ bit15:11
Hour (0..23)
bit10:5
Minute (0..59)
bit4:0
Second / 2 (0..29)
MKDIR¶
-
int f_mkdir(const char *name)¶
Make a new directory entry.
- Op code:
RIA_OP_MKDIR 0x28
- C proto:
rp6502.h
- Parameters:
name – Pathname of the directory to create.
- Returns:
0 on success. -1 on error.
- A regs:
return
- Errno:
EACCES, EEXIST, EINVAL, EIO, ENODEV, ENOENT, ENOMEM, ENOSPC, ENOSYS
Directories¶
OPENDIR¶
-
int f_opendir(const char *name)¶
Create a connection between a directory and a directory descriptor.
- Op code:
RIA_OP_OPENDIR 0x20
- C proto:
rp6502.h
- Parameters:
name – Pathname to a directory.
- Returns:
Directory descriptor. -1 on error.
- A regs:
return
- Errno:
EACCES, EINVAL, EIO, EMFILE, ENODEV, ENOENT, ENOMEM, ENOSYS
READDIR¶
-
int f_readdir(f_stat_t *dirent, int dirdes)¶
Returns directory entry info for the current read position of a directory descriptor, then advances the read position. At the end of the directory, the call succeeds and
fnameis empty.A name with a character that the code page cannot hold, or that FAT refuses, shows character 127 in place of each such character. That entry cannot be opened, because character 127 is refused in a path. On an RP6502-PICO, a name with a character that the code page cannot hold shows as its short 8.3 name instead, and that name opens the file.
- Op code:
RIA_OP_READDIR 0x21
- C proto:
rp6502.h
- Parameters:
dirdes – Directory descriptor from f_opendir().
dirent – Returned f_stat_t data.
- Returns:
0 on success. -1 on error.
- A regs:
return, dirdes
- Errno:
EACCES, EBADF, EINVAL, EIO, ENOENT, ENOMEM, ENOSYS
CLOSEDIR¶
-
int f_closedir(int dirdes)¶
Release the directory descriptor. The descriptor goes back to the pool that f_opendir() draws from.
- Op code:
RIA_OP_CLOSEDIR 0x22
- C proto:
rp6502.h
- Parameters:
dirdes – Directory descriptor from f_opendir().
- Returns:
0 on success. -1 on error.
- A regs:
return, dirdes
- Errno:
EBADF, EINVAL, EIO, ENOSYS
TELLDIR¶
-
long f_telldir(int dirdes)¶
Returns the read position of the directory descriptor.
- Op code:
RIA_OP_TELLDIR 0x23
- C proto:
rp6502.h
- Parameters:
dirdes – Directory descriptor from f_opendir().
- Returns:
Read position. -1 on error.
- A regs:
dirdes
- Errno:
EBADF, EINVAL, ENOSYS
SEEKDIR¶
-
int f_seekdir(long offs, int dirdes)¶
Set the read position for the directory descriptor. The OS reads entries one at a time up to the new position, starting from the current position when seeking forward and from the start of the directory when seeking backward. Use this for convenience, not performance.
- Op code:
RIA_OP_SEEKDIR 0x24
- C proto:
rp6502.h
- Parameters:
offs – New read position, as returned by f_telldir().
dirdes – Directory descriptor from f_opendir().
- Returns:
0 on success. -1 on error.
- A regs:
return, dirdes
- Errno:
EACCES, EBADF, EINVAL, EIO, ENODEV, ENOENT, ENOMEM, ENOSYS
REWINDDIR¶
-
int f_rewinddir(int dirdes)¶
Rewind the read position of the directory descriptor.
- Op code:
RIA_OP_REWINDDIR 0x25
- C proto:
rp6502.h
- Parameters:
dirdes – Directory descriptor from f_opendir().
- Returns:
0 on success. -1 on error.
- A regs:
return, dirdes
- Errno:
EACCES, EBADF, EINVAL, EIO, ENODEV, ENOENT, ENOSYS
Drives and Volumes¶
CHDIR¶
-
int chdir(const char *name)¶
Change to a directory entry. A directory on another drive also makes that drive the current drive.
- Op code:
RIA_OP_CHDIR 0x29
- C proto:
unistd.h
- Parameters:
name – Pathname of the directory to make current.
- Returns:
0 on success. -1 on error.
- A regs:
return
- Errno:
EACCES, EINVAL, EIO, ENODEV, ENOENT, ENOMEM, ENOSYS
CHDRIVE¶
-
int f_chdrive(const char *name)¶
Change the current drive. The name is that of a mounted drive, colon included, such as
MSC1:, and the name of a drive that is not mounted fails with ENODEV. Each drive keeps the last directory used on it, and that directory becomes current again. The drive names of each machine are listed in Filesystems.- Op code:
RIA_OP_CHDRIVE 0x2A
- C proto:
rp6502.h
- Parameters:
name – Drive name to change to.
- Returns:
0 on success. -1 on error.
- A regs:
return
- Errno:
EACCES, EINVAL, EIO, ENODEV, ENOENT
GETCWD¶
-
int f_getcwd(char *name, int size)¶
Get the current working directory.
The result is absolute and always includes a device name, such as
MSC0:/games. Each folder name in it shows as it does in READDIR. When the directory is longer than 255 bytes, the call fails with ENOMEM, because no call accepts a path that long.- Op code:
RIA_OP_GETCWD 0x2B
- C proto:
rp6502.h
- Parameters:
name – The returned directory.
size – Size of the
namebuffer. It stays in the C library, which fails with ENOMEM when the directory does not fit.
- Returns:
Size of returned name. -1 on error.
- Errno:
EACCES, EINVAL, EIO, ENODEV, ENOENT, ENOMEM
GETLABEL¶
-
int f_getlabel(const char *path, char *label)¶
Get the volume label. Label must have room for (11+1) bytes. Only an RP6502-PICO has volume labels, and other machines fail with EACCES, or ENOSYS on the Pocket.
- Op code:
RIA_OP_GETLABEL 0x2D
- C proto:
rp6502.h
- Parameters:
path – Volume to read the label from.
label – Storage for returned label.
- Returns:
Size of returned label. -1 on error.
- A regs:
return
- Errno:
EACCES, EINVAL, EIO, ENODEV, ENOENT, ENOMEM, ENOSYS
SETLABEL¶
-
int f_setlabel(const char *name)¶
Change the volume label. Max 11 characters. Only an RP6502-PICO has volume labels, and other machines fail with EACCES, or ENOSYS on the Pocket.
- Op code:
RIA_OP_SETLABEL 0x2C
- C proto:
rp6502.h
- Parameters:
name – Label with optional volume name.
- Returns:
0 on success. -1 on error.
- A regs:
return
- Errno:
EACCES, EINVAL, EIO, ENODEV, ENOENT, ENOMEM, ENOSYS
GETFREE¶
-
int f_getfree(const char *name, unsigned long *free, unsigned long *total)¶
Get the free and total space of a volume in 512-byte blocks. The operation pushes both counts to the XSTACK in this layout:
struct { unsigned long free; unsigned long total; };
- Op code:
RIA_OP_GETFREE 0x2E
- C proto:
rp6502.h
- Parameters:
name – Volume name.
free – Storage for returned value.
total – Storage for returned value.
- Returns:
0 on success. -1 on error.
- A regs:
return
- Errno:
EACCES, EINVAL, EIO, ENODEV, ENOENT, ENOMEM, ENOSYS
Line Editor¶
RLN_LASTKEY¶
-
int ria_rln_lastkey(char *key, unsigned char *action)¶
Returns the raw bytes of the most recently completed input sequence typed by the user during a non-blocking cooked read from
CON:. This includes single characters and multi-byte escape sequences such as arrow, function, and editing keys. Theactionout-parameter reports whether the line editor handled the key as an editing action (non-zero) or passed it through (zero). Reading consumes the captured sequence; the next call returns 0 until another key is typed. Sequences longer than 32 bytes, or any call made while no line read is in progress, return 0.- Op code:
RIA_OP_RLN_LASTKEY 0x30
- C proto:
rp6502.h
- Parameters:
key – Storage for the returned byte sequence.
action – Out-parameter set non-zero if the key triggered an editing action.
- Returns:
Length of key sequence. 0 if no key is available.
- A regs:
return
- Errno:
EINVAL
RLN_PEEK¶
-
int ria_rln_peek(char *peek, unsigned char *pos)¶
Returns the current contents of the line editor buffer and the cursor position within it. The buffer bytes are pushed to the XSTACK. It fails with EINVAL when no line read is in progress.
- Op code:
RIA_OP_RLN_PEEK 0x31
- C proto:
rp6502.h
- Parameters:
peek – Storage for the returned buffer contents. The C wrapper null-terminates the result, so it must hold up to
RIA_ATTR_RLN_LENGTH+ 1 bytes (256 max).pos – Out-parameter set to the cursor position within the buffer.
- Returns:
Length of the buffer contents. -1 on error.
- A regs:
return
- Errno:
EINVAL
RLN_POKE¶
-
int ria_rln_poke(const char *poke)¶
Feeds a string to the line editor as if the user had typed it. The bytes pass through the same input pipeline as live keystrokes: printable characters are written at the cursor (in overwrite mode while the editor is in its line-edit phase), and recognized editing escape sequences are honored. Any C0 control byte (0x00–0x1F) finishes the input, with two exceptions — ESC (
\33) begins a CSI sequence, and CAN (\30) aborts an in-flight one. Control bytes other than CR (\r) echo in caret notation (^@..``^_``) when the input length is at least 2. LF submits the field like CR but adds no linefeed, which is useful for form input on the last terminal row.- Op code:
RIA_OP_RLN_POKE 0x32
- C proto:
rp6502.h
- Parameters:
poke – Null-terminated string to feed into the editor.
- Returns:
- A regs:
return
- Errno:
EINVAL
Time¶
TIME_GET¶
-
ABI int _time(time_t *timep)¶
-
lib time_t time(time_t *timep)¶
Obtains the current time as seconds since the Unix epoch, 1970-01-01T00:00:00Z. The operation pushes the seconds to the XSTACK as a 64-bit signed integer and returns 0, or -1 on error. The cc65 time_t has 32 bits, so the cc65 time() fails with ERANGE when the seconds do not fit.
- Op code:
RIA_OP_TIME_GET 0x3F
- C proto:
time.h
- Returns:
The current time, also stored at
timepif it is not NULL. -1 on error.- A regs:
return
- Errno:
EINVAL, EIO, ERANGE
TIME_SET¶
-
int time_set(long long time)¶
Sets the clock to seconds since the Unix epoch. Supported only on the RP6502-PICO.
- Op code:
RIA_OP_TIME_SET 0x3E
- C proto:
rp6502.h
- Parameters:
time – Seconds since 1970-01-01T00:00:00Z.
- Returns:
0 on success. -1 on error.
- A regs:
return
- Errno:
EACCES, EINVAL
GMTIME¶
-
lib struct tm *gmtime(const time_t *timep)¶
Converts seconds since the Unix epoch to UTC broken-down time. Push the seconds as a signed integer of up to 64 bits. The operation pushes this struct tm back to the XSTACK and returns 0, or -1 on error.
struct tm { int16_t tm_sec; /* 0-61 */ int16_t tm_min; /* 0-59 */ int16_t tm_hour; /* 0-23 */ int16_t tm_mday; /* 1-31 */ int16_t tm_mon; /* 0-11 */ int16_t tm_year; /* years since 1900 */ int16_t tm_wday; /* 0-6, Sunday = 0 */ int16_t tm_yday; /* 0-365 */ int16_t tm_isdst; /* >0 DST, 0 no DST, <0 unknown */ };
- Op code:
RIA_OP_GMTIME 0x3A
- C proto:
time.h
- Returns:
Pointer to a static struct tm. NULL on error.
- A regs:
return
- Errno:
EINVAL, ERANGE
LOCALTIME¶
-
lib struct tm *localtime(const time_t *timep)¶
Converts seconds since the Unix epoch to local broken-down time using the configured time zone. Run
help set tzon an RP6502-PICO monitor to learn how to configure your time zone. Push the seconds as a signed integer of up to 64 bits. The operation pushes a struct tm (see GMTIME) back to the XSTACK and returns 0, or -1 on error.- Op code:
RIA_OP_LOCALTIME 0x3B
- C proto:
time.h
- Returns:
Pointer to a static struct tm. NULL on error.
- A regs:
return
- Errno:
EINVAL, ERANGE
MKTIME¶
-
lib time_t mktime(struct tm *timep)¶
Converts local broken-down time to seconds since the Unix epoch. Push a struct tm (see GMTIME) to the XSTACK; fields outside their ranges are normalized. The operation pushes the seconds back as a 64-bit signed integer and returns 0, or -1 on error. The C library mktime() then calls LOCALTIME to write the normalized struct, with tm_wday and tm_yday set, back to the caller.
- Op code:
RIA_OP_MKTIME 0x3C
- C proto:
time.h
- Returns:
Seconds since the Unix epoch. -1 on error.
- A regs:
return
- Errno:
EINVAL, ERANGE
STRFTIME¶
-
lib size_t strftime(char *buf, size_t bufsize, const char *format, const struct tm *tm)¶
Formats a broken-down time as a string. Push a struct tm (see GMTIME), then a zero-terminated format string, to the XSTACK. All struct tm fields must be in range, e.g. as returned by GMTIME, LOCALTIME, or MKTIME. The operation pushes the formatted string back without a terminator and returns its length: 0 if the result is empty or does not fit, or -1 on error. The format and the result share the XSTACK, which limits the result. The C library strftime() compares the length to its buffer size and abandons an oversized result with DROP.
%a %A %b %B %c %p %r %x %Xfollow the configured locale and%z %Zthe configured time zone. Set both withSET LOCandSET TZon an RP6502-PICO. The format and result are code page text.%Eand%Omodifiers are ignored.- Op code:
RIA_OP_STRFTIME 0x3D
- C proto:
time.h
- Returns:
Length of the string in
buf, not counting the terminator. 0 on error, or if the result is empty or does not fit.- A regs:
return
- Errno:
EINVAL
Attributes¶
ATTR_GET¶
-
long ria_attr_get(unsigned char id)¶
Returns the current value of a RIA attribute. See RIA Attributes for attribute IDs and descriptions.
- Op code:
RIA_OP_ATTR_GET 0x0A
- C proto:
rp6502.h
- Parameters:
id – Attribute ID. One of the
RIA_ATTR_*constants.
- A regs:
id
- Returns:
The attribute value as a 31-bit integer. -1 on error.
- Errno:
EINVAL
ATTR_SET¶
-
int ria_attr_set(long val, unsigned char id)¶
Sets the value of a RIA attribute. See RIA Attributes for attribute IDs and descriptions.
- Op code:
RIA_OP_ATTR_SET 0x0B
- C proto:
rp6502.h
- Parameters:
id – Attribute ID. One of the
RIA_ATTR_*constants.val – New value.
- A regs:
id
- Returns:
0 on success
- Errno:
EINVAL
RIA Attributes¶
RIA attributes are 31-bit values identified by an 8-bit ID, accessed with
ria_attr_get() and ria_attr_set(). Both succeed for any
valid attribute ID. Getting or setting an unknown ID returns -1 with
errno set to EINVAL, as does trying to set a get-only attribute.
ID / Name |
Description |
|---|---|
0x00
RIA_ATTR_ERRNO_OPT |
Errno mapping option. Selects which set of errno constants the OS
uses. The cc65 and llvm-mos C runtimes set it at startup whenever
the program links |
0x01
RIA_ATTR_PHI2_KHZ |
CPU clock speed in kHz. Range 100–8000. Changes take effect immediately and revert to the system setting when the ROM stops. |
0x02
RIA_ATTR_CODE_PAGE |
Active OEM code page used by the filesystem, console, and default VGA font. Reverts to the system setting when the ROM stops. If the requested page is unavailable, the system setting is selected; follow a set with a get to confirm the result. One of: 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869. |
0x03
RIA_ATTR_RLN_LENGTH |
Maximum input line length for the stdin line editor. 0–255, default 254. With 0, only a blank line can be entered. |
0x04
RIA_ATTR_LRAND |
31-bit hardware random number seeded with entropy from the RIA.
Returns a value in the range 0x0 to 0x7FFFFFFF. Suitable for
seeding a PRNG or direct use. The 16-bit |
0x05
RIA_ATTR_BEL |
BEL ( |
0x06
RIA_ATTR_LAUNCHER |
Launcher flag. Set to 1 to register the current ROM as the launcher; set to 0 to deregister. See the Launcher section for full details and usage patterns. |
0x07
RIA_ATTR_EXIT_CODE |
The exit code of the last ROM to exit. |
0x08
RIA_ATTR_SIGINT |
Read-only Ctrl-C latch. Returns 1 if a Ctrl-C has been seen since the previous get on any terminal attached to the console manifold, including the telnet Interrupt Process command; returns 0 otherwise. Reading clears the latch. Same as RIA IRQ SIGINT. |
0x09
RIA_ATTR_RLN_CAPS |
Caps mode applied to keystrokes by the console line editor. 0 (default) passes characters through unchanged; 1 forces all letters to upper case; 2 inverts the case of letters. Reverts to the system setting when the ROM stops. |
0x0A
RIA_ATTR_RLN_WIDTH |
Terminal width in columns used by the stdin line editor. Setting a non-zero value pins the width and bypasses auto-detect; 0 returns the channel to auto-detect (default). Reverts to 0 when the ROM stops. See TERM for how the console manifold probes terminal size. |
0x0B
RIA_ATTR_RLN_HEIGHT |
Terminal height in rows used by the stdin line editor. Setting
and revert semantics match |
0x0C
RIA_ATTR_RLN_SUPPRESS_NL |
Prevents read line from sending a CRLF at the end of input. Useful for using the last terminal line for field input. |
0x10
RIA_ATTR_CLK_RUN_MS |
Read-only milliseconds the 6502 has been running, counted from
the release of reset. Wraps approximately every 24.8 days. This
is the C |
0x11
RIA_ATTR_CLK_RUN_CS |
Read-only 6502 run time in 1/100 second ticks. Wraps approximately every 248 days. |
0x12
RIA_ATTR_CLK_RUN_DS |
Read-only 6502 run time in 1/10 second ticks. Wraps approximately every 6.8 years. |
0x13
RIA_ATTR_CLK_RUN_S |
Read-only 6502 run time in whole seconds. Wraps approximately every 68 years. |
Host Error Codes¶
A program never gets a host’s own error codes. Each host maps them onto
the errno values in the left column, and the table shows which become
which, for a developer porting code from POSIX or Windows. ENOTDIR,
for one, has no errno of its own here and arrives as ENOENT. The
littlefs codes are shown without their LFS_ERR_ prefix and the Windows
codes without their ERROR_ prefix. Any other code becomes EIO.
FatFs |
littlefs |
POSIX |
Windows |
|
|---|---|---|---|---|
ENOENT |
FR_NO_FILE, FR_NO_PATH |
NOENT |
ENOENT, ENOTDIR |
FILE_NOT_FOUND, PATH_NOT_FOUND, NO_MORE_FILES, DIRECTORY |
EACCES |
FR_DENIED, FR_WRITE_PROTECTED |
EACCES, EPERM, EROFS, EISDIR, ENOTEMPTY |
ACCESS_DENIED, SHARING_VIOLATION, LOCK_VIOLATION, WRITE_PROTECT, DIR_NOT_EMPTY |
|
EINVAL |
FR_INVALID_NAME, FR_INVALID_PARAMETER |
NOTDIR, ISDIR, NOTEMPTY, INVAL, NAMETOOLONG |
EINVAL, ENAMETOOLONG |
FILENAME_EXCED_RANGE, INVALID_NAME, INVALID_PARAMETER, NEGATIVE_SEEK |
ENODEV |
FR_NOT_READY, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM |
ENODEV, ENXIO, EXDEV |
NOT_READY, BAD_UNIT, INVALID_DRIVE, NOT_SAME_DEVICE |
|
ENOSPC |
FBIG, NOSPC |
ENOSPC, EFBIG |
DISK_FULL, HANDLE_DISK_FULL |
|
EEXIST |
FR_EXIST |
EXIST |
EEXIST |
ALREADY_EXISTS, FILE_EXISTS |
EMFILE |
FR_TOO_MANY_OPEN_FILES |
EMFILE, ENFILE |
TOO_MANY_OPEN_FILES |
|
ENOMEM |
FR_NOT_ENOUGH_CORE |
NOMEM |
ENOMEM |
NOT_ENOUGH_MEMORY, OUTOFMEMORY |
EBUSY |
FR_LOCKED |
EBUSY |
BUSY, PIPE_BUSY |
|
EBADF |
FR_INVALID_OBJECT |
BADF |
EBADF |
INVALID_HANDLE |
EAGAIN |
FR_TIMEOUT |
EAGAIN |
||
EINTR |
OPERATION_ABORTED |
|||
ESPIPE |
ESPIPE |
|||
ERANGE |
ERANGE |
|||
EIO |
FR_DISK_ERR, FR_INT_ERR, FR_MKFS_ABORTED |
IO, CORRUPT, NOATTR |
EIO |
On POSIX, a read or write on a descriptor opened the wrong way fails with
EBADF from the host and EACCES here.
The Pocket sets errno itself rather than mapping a host’s codes, so it has no column. The calls it lacks are listed under Compatibility.
Errno Translations¶
API calls set RIA_ERRNO when an error occurs. Because cc65 and llvm-mos
each define their own errno constants, the errno option selects which set
of numeric values to use. In C, errno maps directly to RIA_ERRNO,
and both C runtimes set the option at startup whenever the program links
errno. Assembly programs must set RIA_ATTR_ERRNO_OPT themselves
before any API call that can fail.
cc65 |
llvm-mos |
|
|---|---|---|
option |
1 |
2 |
ENOENT |
1 |
2 |
ENOMEM |
2 |
12 |
EACCES |
3 |
13 |
ENODEV |
4 |
19 |
EMFILE |
5 |
24 |
EBUSY |
6 |
16 |
EINVAL |
7 |
22 |
ENOSPC |
8 |
28 |
EEXIST |
9 |
17 |
EAGAIN |
10 |
11 |
EIO |
11 |
5 |
EINTR |
12 |
4 |
ENOSYS |
13 |
38 |
ESPIPE |
14 |
29 |
ERANGE |
15 |
34 |
EBADF |
16 |
9 |
ENOEXEC |
17 |
8 |
EDOM |
18 |
33 |
EILSEQ |
18 |
84 |
EUNKNOWN |
18 |
85 |
Launcher¶
A ROM is the whole state of the machine as it comes out of reset, like a cartridge, so running one normally replaces whatever ran before. A ROM also takes arguments through ARGV and returns an exit status through EXIT, like a program. The launcher puts the two together: a ROM that starts other ROMs with EXEC gets control back when each one stops.
A ROM registers as the launcher by setting RIA_ATTR_LAUNCHER to 1
with ria_attr_set(). From then on, when a ROM it started stops,
whether it calls exit(), returns from main() or fails, the launcher ROM
runs again from the start, and RIA_ATTR_EXIT_CODE holds the exit
status of the ROM that stopped. The launcher starts fresh each time, so
it keeps anything it needs between runs in a file. When the launcher
itself stops, the registration clears.
For example, a shell ROM can run a compiler, a linker and a packager, each a ROM of its own, as three steps. It starts each one with EXEC and its arguments, reads the exit code when it runs again, and ends the chain when a step fails. The same mechanism serves a menu for an anthology of games, which comes back when a game exits. That works best when every game in it has a way to exit, such as an Exit item in its menu.
Application Binary Interface¶
See also
RIA registers — the hardware register map referenced throughout this section.
A compiler turns each call of a C function into machine code in a standard way: where each argument goes, in what order, and where the result comes back. That byte-level convention is an Application Binary Interface (ABI). This section describes the ABI of the API calls: how a 6502 program passes the arguments to the RIA, starts the call, and reads the result back from the host.
The ABI is based on fastcall from the cc65 internals. The compiler’s library follows it for every C program, so a C programmer can skip this section. An assembly programmer, or anyone bringing another compiler to the Picocomputer, needs all of it.
At its core, the ABI is four rules:
Stack arguments are pushed left to right.
Last argument passed by register A, AX, or AXSREG.
Return value in register AX or AXSREG.
May return data on the stack.
A and X are the 6502 registers. The pseudo-register AX combines them into 16 bits, and AXSREG extends that to 32 bits with the 16 SREG bits. Every API call is specified as a C declaration, like so:
-
int doit(int arg0, int arg1);¶
The RIA has registers called RIA_A, RIA_X, and RIA_SREG. An
int is 16 bits, so arg1 goes into the RIA_A and RIA_X
registers. Throughout this explanation, “A” means the 6502 register and
“RIA_A” means the RIA register.
arg0 goes on the extended stack (XSTACK), 512 bytes of memory in the
RIA. Reading RIA_XSTACK pops bytes; writing pushes them. It’s a
top-down stack, so push the arguments left to right, and push each value
high byte first so that it lies in memory low byte first.
To execute the call, store the operation ID in RIA_OP; the operation
begins immediately. You can keep the 6502 busy with other work, such as a
loading animation, by polling RIA_BUSY, or just JSR to RIA_SPIN
to block until it’s done.
JSR RIA_SPIN can unblock within 3 clock cycles and loads A and X for
you. Sequential operations run fastest this way. Under the hood, you’re
jumping into a self-modifying program that runs out of the RIA registers.
FFF1: BRA #$?? ; RIA_BUSY {-2 or 0}
FFF3: LDA #$?? ; RIA_A
FFF5: LDX #$?? ; RIA_X
FFF7: RTS
Polling is just snooping on that same program. The RIA_BUSY register
is the -2 or 0 in the BRA above. Per the RIA registers, bit 7 signals busy, which the 6502 can test quickly
with the BIT operator to set flag N. Once it clears, read RIA_A and
RIA_X with absolute instructions.
wait: BIT RIA_BUSY
BMI wait
LDA RIA_A
LDX RIA_X
Any operation that returns RIA_A also returns RIA_X to help with
C integer promotion. Loading X last allows fast testing for negative
return values. RIA_SREG is updated only for 32-bit returns, and
RIA_ERRNO only when there’s an error.
Some operations return strings or structures on the stack. Pull the entire stack before the next call, or use ria_drop() to abandon the stack in O(1) time without a loop. One operation’s output can also be the next one’s input. read_xstack() leaves its data on the XSTACK where write_xstack() takes it, so the two copy a file without touching any RAM or XRAM.
The time operations chain the same way, without cycling the XSTACK: TIME_GET returns seconds positioned as the input to GMTIME, LOCALTIME, or TIME_SET; their struct tm feeds MKTIME directly, or STRFTIME after pushing only the zero-terminated format on top; and MKTIME returns seconds ready for another conversion.
Short Stacking¶
In the pursuit of saving every cycle, you can trim a few off the stack push when you don’t need the full range. This applies only to the first stack argument pushed. Take LSEEK:
ABI long f_lseek(long offset, unsigned char whence, int fildes)
Here you push a 32-bit value, and — not by coincidence — it sits in the right position for short stacking. If the offset always fits in 16 bits, push two bytes instead of four.
Signed arguments are sign-extended, so two bytes carry -32768 to 32767. Unsigned arguments are zero-filled.
Warning
Size a short push by the signed range. An offset of 200 pushed as the single byte 0xC8 arrives as -56, because the top bit of 0xC8 is the sign. Push 0x00 and then 0xC8 to send 200.
Shorter AX¶
A program can save a few cycles by leaving RIA_X alone. Returned
integers are always at least 16 bits, to help with C integer promotion,
but many operations ignore RIA_X on the way in and keep their return
value within RIA_A. Those are listed under a regs in each
operation of the Application Programming Interface.
Bulk Data¶
Functions that move bulk data come in two flavors, depending on where the data lives. A RAM pointer means nothing to the RIA, since it can’t touch 6502 RAM, so bulk data moves through the XSTACK or XRAM instead.
Bulk XSTACK Operations¶
These work only for sizes of 512 bytes or less — the size of the XSTACK they pass data on. A pointer in the C prototype marks the type and direction (to or from the OS) of the data. A few examples:
int open(const char *path, int oflag);
Send oflag in RIA_A; per the OPEN docs, RIA_X doesn’t need
to be set. Send the path on the XSTACK by pushing the string from its
last character backward. You can skip the terminating zero, but strings
are capped at 255 bytes. In C, the library pushes the string for you.
int read_xstack(void *buf, unsigned count, int fildes)
Send count as a short stack and fildes in RIA_A; per the
READ_XSTACK docs, RIA_X doesn’t need to be set. The value returned
in AX is the number of bytes to pull from the stack. In C, the library
copies the XSTACK into buf[] for you.
int write_xstack(const void *buf, unsigned count, int fildes)
Send fildes in RIA_A; per the WRITE_XSTACK docs, RIA_X
doesn’t need to be set. Push the buf data onto the XSTACK. Don’t send
count; the OS takes it from the XSTACK pointer. In C, the library
copies count bytes of buf[] onto the XSTACK for you.
Note that read() and write() are part of the C library, not API calls. C requires them to handle counts larger than the XSTACK can return, so the implementation makes as many API calls as it takes.
Bulk XRAM Operations¶
These load and save XRAM directly through READ_XRAM and WRITE_XRAM, so you can pull assets straight in without routing them through 6502 RAM.
int read_xram(unsigned buf, unsigned count, int fildes)
int write_xram(unsigned buf, unsigned count, int fildes)
The OS takes buf and count on the XSTACK as integers, with
fildes in RIA_A. The 6502 reads and writes XRAM through
RIA_RW0 or RIA_RW1.
These operations stand out for their speed and for running in the background while the 6502 does other work. Depending on the request size, expect up to 800 KB/sec. A full 64 KB of XRAM loads or saves multiple times per second with no wait states or 6502 work.
Bulk XRAM operations are why the Picocomputer 6502 has no paged memory. You don’t need it when “disk” access has zero seek time and DMA to XRAM.