RP6502-OS

RP6502 - Operating System

Introduction

The RP6502-RIA runs a 32-bit protected operating system that you can call from the 6502. The RP6502-OS does not use any 6502 system RAM and will not interfere with developing a native 6502 OS.

The RP6502-OS is loosely based on POSIX with an Application Binary Interface (ABI) similar to cc65’s fastcall. It provides stdio.h and unistd.h services to both cc65 and llvm-mos compilers. There are also calls to access RP6502 features and manage FAT32 filesystems. ExFAT is ready to go and will be enabled when the patents expire.

Memory Map

There is no ROM. Nothing in zero page is used or reserved. The Picocomputer starts as a clean slate for every project. VGA, audio, storage, keyboards, mice, gamepads, RTC, and networking are all accessed using only the 32 registers of the RIA.

Address

Description

$0000-$FEFF

RAM, 63.75K

$FF00-$FFCF

Unassigned

$FFD0-$FFDF

VIA, see the WDC datasheet

$FFE0-$FFFF

RIA, see the RP6502-RIA datasheet

$10000-$1FFFF

XRAM, 64K for RP6502-RIA and RP6502-VGA

The unassigned space is available for hardware experimenters. You will need to design your own chip select hardware to use this address space. It is recommended that additional VIAs be added “down” and other hardware added “up”. For example: VIA0 at $FFD0, VIA1 at $FFC0, SID0 at $FF00, and SID1 at $FF20.

Application Binary Interface

The ABI for calling the operating system is based on fastcall from the cc65 internals. The RP6502-OS does not use or require anything from cc65 and is easy for assembly programmers to use. At its core, the OS ABI is four simple 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 for 16 bits. AXSREG allows 32 bits with the 16 additional SREG bits. Let’s look at how to make an OS call through the RIA registers. All OS calls are 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 we set the RIA_A and RIA_X registers with arg1. I’ll use “A” for the 6502 register and “RIA_A” for the RIA register in this explanation.

We use the XSTACK for arg0. Reading or writing data to the RIA_XSTACK register removes or adds bytes to the XSTACK. It’s a top-down stack, so push each argument from left to right and maintain little endian-ness in memory.

To execute the call, store the operation ID in RIA_OP. The operation begins immediately. You can keep doing 6502 things, like running a loading animation, by polling RIA_BUSY. Or, JSR RIA_SPIN to block.

The JSR RIA_SPIN method can unblock in less than 3 clock cycles and does an immediate load of A and X. Sequential operations will run fastest with this technique. Under the hood, you’re jumping into a self-modifying program that runs on the RIA registers.

BRA #$??      ; RIA_BUSY {-2 or 0}
LDA #$??      ; RIA_A
LDX #$??      ; RIA_X
RTS

Polling is simply snooping on the above program. The RIA_BUSY register is the -2 or 0 in the BRA above. The RIA datasheet specifies bit 7 indicates busy, which the 6502 can check quickly by using the BIT operator to set flag N. Once clear, we read RIA_A and RIA_X with absolute instructions.

wait:
BIT RIA_BUSY
BMI wait
LDA RIA_A
LDX RIA_X

All operations returning RIA_A will also return RIA_X to assist with C integer promotion. RIA_SREG is only updated for 32-bit returns. RIA_ERRNO is only updated if there is an error.

Some operations return strings or structures on the stack. You must pull the entire stack before the next call. However, tail call optimizations are possible. For example, you can chain read_xstack() and write_xstack() to copy a file without using any RAM or XRAM.

Short Stacking

In the never ending pursuit of saving all the cycles, it is possible to save a few on the stack push if you don’t need all the range. This only works on the stack argument that gets pushed first. For example:

long f_lseek(long offset, char whence, int fildes)

Here we need to push a 32 bit value. Not coincidentally, it’s in the right position for short stacking. If, for example, the offset always fits in 16 bits, push only two bytes instead of four.

Shorter AX

Many operations can save a few cycles by ignoring REG_X. All returned integers are always available as at least 16 bits to assist with C integer promotion. However, many operations will ignore REG_X in the register parameter and limit their return to fit in REG_A. These will be documented below as “A regs”.

Bulk Data

Functions that move bulk data may come in two flavors. These are any function with a mutable pointer parameter. A RAM pointer is meaningless to the RIA because it can not change 6502 RAM. Instead, we use the XSTACK or XRAM to move data.

Bulk XSTACK Operations

These only work if the size is 512 bytes or less. Bulk data is passed on the XSTACK, which is 512 bytes. A pointer appears in the C prototype to indicate the type and direction of this data. Let’s look at some examples.

int open(const char *path, int oflag);

Send oflag in RIA_A. RIA_X doesn’t need to be set according the to docs below. Send the path on XSTACK by pushing the string starting with the last character. You may omit pushing the terminating zero, but strings are limited to a length of 255. Calling this from the C SDK will “just work” because there’s an implementation that 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. RIA_X doesn’t need to be set according the to docs below. The returned value in AX indicates how many values must be pulled from the stack. If you call this from the C SDK then it will copy XSTACK to buf[] for you.

int write_xstack(const void *buf, unsigned count, int fildes)

Send fildes in RIA_A. RIA_X doesn’t need to be set according the to docs below. Push the buf data to XSTACK. Do not send count, the OS knows this from its internal stack pointer. If you call this from the C SDK then it will copy count bytes of buf[] to XSTACK for you.

Note that read() and write() are part of the C SDK, not an OS operation. C requires these to support a count larger than the XSTACK can return so the implementation makes multiple OS calls as necessary.

Bulk XRAM Operations

These load and save XRAM directly. You can load game assets without going through 6502 RAM or capture a screenshot with ease.

int read_xram(xram_addr buf, unsigned count, int fildes)
int write_xram(xram_addr buf, unsigned count, int fildes)

The OS expects buf and count on the XSTACK as integers with filedes in RIA_A. The RP6502-OS has direct access to XRAM so internally it will use something like &XRAM[buf]. You will need to use RIA_RW0 or RIA_RW1 to access this memory from the 6502.

These operations are interesting because of their high performance and ability to work in the background while the 6502 is doing something else. You can expect close to 64KB/sec, which means loading a game level’s worth of assets will take less than a second.

Bulk XRAM operations are why the Picocomputer 6502 was designed without paged memory.

Application Programmer Interface

Much of this API is based on POSIX and FatFs. In particular, filesystem and console access should feel extremely familiar. However, some operations will have a different argument order or data structures than what you’re used to. The reason for this becomes apparent when you start to work in assembly and fine tune short stacking and integer demotions. You might not notice the differences if you only work in C because the standard library has wrapper functions and familiar prototypes. For example, the f_lseek() described below has reordered arguments that are optimized for short stacking the long argument. But you don’t have to call f_lseek() from C, you can call the usual lseek() which has the traditional argument order.

The RP6502-OS is built around FAT filesystems, which is the defacto standard for unsecured USB storage devices. POSIX filesystems are not fully compatible with FAT but there is a solid intersection of basic IO that is 100% compatible. You will see some familiar POSIX functions like open() and others like f_stat() which are similar to the POSIX function but tailored to FAT. Should it ever become necessary to have a POSIX stat(), it can be implemented in the C standard library or in an application by translating f_stat() data.

ZXSTACK

void zxstack (void);

Abandon the xstack by resetting the xstack pointer. This is the only operation that doesn’t require waiting for completion. You do not need to call this for failed operations. It can be useful if you want to quickly ignore part of a returned structure.

Op code

RIA_OP_ZXSTACK 0x00

C proto

rp6502.h

XREG

int xreg (char device, char channel, unsigned char address, ...);
int xregn (char device, char channel, unsigned char address, unsigned count, ...);

Using xreg() from C is preferred to avoid making a counting error. Count doesn’t need to be sent in the ABI so both prototypes are correct.

The variadic argument is a list of ints to be stored in extended registers starting at address on the specified device and channel. See the RP6502-RIA and RP6502-VGA documentation for what each register does. Setting extended registers can fail, which you can use for feature detection. EINVAL means the device responded with a negative acknowledgement. EIO means there was a timeout waiting for ack/nak.

This is how you add virtual hardware to extended RAM. Both the RP6502-RIA and RP6502-VGA have a selection of virtual devices you can install. You can also make your own hardware for the PIX bus and configure it with this call.

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

EINVAL, EIO

PHI2

int phi2(void)

Retrieves the PHI2 setting from the RIA. Applications can use this for adjusting to or rejecting different clock speeds.

Op code

RIA_OP_PHI2 0x02

C proto

rp6502.h

Returns

The 6502 clock speed in kHz. Typically 800 <= x <= 8000.

Errno

will not fail

CODE_PAGE

int code_page(int cp)

Temporarily overrides the code page if non zero. Returns to system setting when 6502 stops. This is the encoding the filesystem is using and, if VGA is installed, the console and default font. If zero, the system CP setting is selected and returned. If the requested code page is unavailable, a different code page will be selected and returned. For example: if (850!=code_page(850)) puts("error");

Op code

RIA_OP_CODE_PAGE 0x03

C proto

rp6502.h

Parameters
  • cp – code page or 0 for system setting.

Returns

The code page. One of: 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950.

Errno

will not fail

LRAND

long lrand(void)

Generates a random number starting with entropy on the RIA. This is suitable for seeding a RNG or general use. The 16-bit rand() in the cc65 library can be seeded with this by calling its non-standard _randomize() function.

Op code

RIA_OP_LRAND 0x04

C proto

rp6502.h

Returns

Chaos. 0x0 <= x <= 0x7FFFFFFF

Errno

will not fail

STDIN_OPT

int stdin_opt(unsigned long ctrl_bits, unsigned char str_length)

Additional options for the STDIN line editor. Set the str_length to your buffer size - 1 to make gets() safe. This can also guarantee no split lines when using fgets() on STDIN.

* Experimental * Likely to be replaced with stty-like something. Drop your thoughts on the forums if you have specific needs.

Op code

RIA_OP_STDIN_OPT 0x05

C proto

rp6502.h

Parameters
  • ctrl_bits – Bitmap of ASCII 0-31 defines which CTRL characters can abort an input. When CTRL key is pressed, any typed input remains on the screen but the applicaion receives a line containing only the CTRL character. e.g. CTRL-C + newline.

  • str_length – 0-255 default 254. The input line editor won’t allow user input greater than this length.

A regs

return, str_length

Returns

0 on success

Errno

will not fail

ERRNO_OPT

int errno_opt(char option)

RP6502-OS calls will set RIA_ERRNO when an error occurs. This is used to select which set of values to use because the compiler libraries each use different constants in errno.h. Both cc65 and llvm-mos call this automatically in the C runtime. The RIA_ERRNO behavior is undefined until it is set. Note that the C errno maps directly to RIA_ERRNO.

RP6502-OS will map FatFs errors onto errno. RP6502 emulation and simulation software is expected to map their native errors as well. The table below shows the FatFs mappings. Because FatFs is so integral to the OS, calls are documented here with their native FatFs errors to assist when cross referencing the FatFs documentation.

Op code

RIA_OP_ERRNO_OPT 0x06

C proto

None

Parameters
  • option – One of the values from the table below.

A regs

return, option

Returns

0 on success

Errno

EINVAL

cc65

llvm_mos

FatFs

option

1

2

ENOENT

1

2

FR_NO_FILE, FR_NO_PATH

ENOMEM

2

12

FR_NOT_ENOUGH_CORE

EACCES

3

23

FR_DENIED, FR_WRITE_PROTECTED

ENODEV

4

19

FR_NOT_READY, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM

EMFILE

5

24

FR_TOO_MANY_OPEN_FILES

EBUSY

6

16

FR_LOCKED

EINVAL

7

22

FR_INVALID_NAME, FR_INVALID_PARAMETER

ENOSPC

8

28

EEXIST

9

17

FR_EXIST

EAGAIN

10

11

FR_TIMEOUT

EIO

11

5

FR_DISK_ERR, FR_INT_ERR, FR_MKFS_ABORTED

EINTR

12

4

ENOSYS

13

38

ESPIPE

14

29

ERANGE

15

34

EBADF

16

9

FR_INVALID_OBJECT

ENOEXEC

17

8

EDOM

18

33

EILSEQ

18

84

EUNKNOWN

18

85

CLOCK

unsigned long clock(void)

Obtain the value of a monotonic clock that updates 100 times per second. Wraps approximately every 497 days.

Op code

RIA_OP_CLOCK 0x0F

C proto

time.h

Returns

1/100 second monotonic clock

Errno

will not fail

CLOCK_GETRES

int clock_getres(clockid_t clock_id, struct timespec *res)

struct timespec {
   uint32_t tv_sec; /* seconds */
   int32_t tv_nsec; /* nanoseconds */
};

Obtains the clock resolution.

Op code

RIA_OP_CLOCK_GETRES 0x10

C proto

time.h

Parameters
  • clock_id – 0 for CLOCK_REALTIME.

Returns

0 on success. -1 on error.

A regs

return, clock_id

Errno

EINVAL

CLOCK_GETTIME

int clock_gettime(clockid_t clock_id, struct timespec *tp)

Obtains the current time.

Op code

RIA_OP_CLOCK_GETTIME 0x11

C proto

time.h

Parameters
  • clock_id – 0 for CLOCK_REALTIME.

Returns

0 on success. -1 on error.

A regs

return, clock_id

Errno

EINVAL, EUNKNOWN

CLOCK_SETTIME

int clock_settime(clockid_t clock_id, const struct timespec *tp)

Sets the current time.

Op code

RIA_OP_CLOCK_SETTIME 0x12

C proto

time.h

Parameters
  • clock_id – 0 for CLOCK_REALTIME.

Returns

0 on success. -1 on error.

A regs

return, clock_id

Errno

EINVAL, EUNKNOWN

CLOCK_GETTIMEZONE

int clock_gettimezone(uint32_t time, clockid_t clock_id, struct _timezone *tz)
struct _timezone
{
   int8_t daylight;  /* >0 if daylight savings time active */
   int32_t timezone; /* Number of seconds behind UTC */
   char tzname[5];   /* Name of timezone, e.g. CET */
   char dstname[5];  /* Name when daylight true, e.g. CEST */
};

Returns a cc65 _timezone structure for the requested time. Use help set tz on the monitor to learn about configuring your time zone.

* Experimental * time zones in cc65 are incomplete probably because no other 6502 OS supports them.

Op code

RIA_OP_CLOCK_GETTIMEZONE 0x13

C proto

None, Experimental

Parameters
  • time – time_t compatible integer.

  • clock_id – 0 for CLOCK_REALTIME.

Returns

0 on success. -1 on error.

A regs

return, clock_id

Errno

EINVAL

OPEN

int open(const char *path, int oflag)

Create a connection between a file and a file descriptor. Up to 8 files may be open at once.

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

EINVAL, EMFILE, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_DENIED, FR_EXIST, FR_INVALID_OBJECT, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_LOCKED, FR_NOT_ENOUGH_CORE, FR_TOO_MANY_OPEN_FILES

Options
O_RDONLY 0x01
Open for reading only.
O_WRONLY 0x02
Open for writing only.
O_RDWR 0x03
Open for reading and writing.
O_CREAT 0x10
Create the file if it does not exist.
O_TRUNC 0x20
Truncate the file length to 0 after opening.
O_APPEND 0x40
Read/write pointer is set end of the file.
O_EXCL 0x80
If 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. File descriptor will rejoin the pool available for use by open().

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

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT

READ

int read(int fildes, void *buf, unsigned count)

Read count bytes from a file to a buffer. This is implemented in the compiler library as a series of calls to read_xstack().

Op code

None

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

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT

READ_XSTACK

int read_xstack(void *buf, unsigned count, int fildes)

Read count bytes from a file to 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. 0x100 max.

  • fildes – File descriptor from open().

Returns

On success, number of bytes read is returned. On error, -1 is returned.

A regs

fildes

Errno

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT

READ_XRAM

int read_xram(unsigned buf, unsigned count, int fildes)

Read count bytes 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

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT

WRITE

int write(int fildes, const void *buf, unsigned count)

Write count bytes from buffer to a file. This is implemented in the compiler library as a series of calls to write_xstack().

Op code

None

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

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT

WRITE_XSTACK

int write_xstack(const void *buf, unsigned count, int fildes)

Write count bytes from 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. 0x100 max.

  • fildes – File descriptor from open().

Returns

On success, number of bytes written is returned. On error, -1 is returned.

A regs

fildes

Errno

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT

WRITE_XRAM

int write_xram(unsigned buf, unsigned count, int fildes)

Write count bytes 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

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_DENIED, FR_INVALID_OBJECT, FR_TIMEOUT

LSEEK

static long f_lseek(long offset, char whence, int fildes)
off_t lseek(int fildes, off_t offset, int whence)

Move the read/write pointer. The OS uses the ABI format of f_seek(). An lseek() compatible wrapper is provided with the compiler library.

This can also be used to obtain the current read/write position with f_lseek(0, SEEK_CUR, fd).

Op code

See table below.

C proto

f_lseek: rp6502.h, lseek: unistd.h

Parameters
  • offset – How far you wish to seek.

  • whence – From whence you wish to seek. See table below.

  • fildes – File descriptor from open().

Returns

Read/write position. -1 on error. If this value would be too large for a long, the returned value will be 0x7FFFFFFF.

A regs

fildes

Errno

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT

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

RENAME

int rename(const char* oldname, const char* newname)

Renames and/or moves a file or directory.

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.

Errno

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_EXIST, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_LOCKED, FR_NOT_ENOUGH_CORE

SYNCFS

int syncfs(int fildes)

Finish pending writes for the file descriptor.

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

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT

STAT

int f_stat(const char* path, f_stat_t* dirent)
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;

Returns file or directory info for requested path. See the FatFs documentation for details about the data structure.

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, dirent

Errno

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE

OPENDIR

int f_opendir(const char* name)

Create a connection between a directory and a directory descriptor. Up to 8 directories may be open at once.

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

EINVAL, EMFILE, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_PATH, FR_INVALID_NAME, FR_INVALID_OBJECT, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE, FR_TOO_MANY_OPEN_FILES

READDIR

int f_readdir(f_stat_t* dirent, int dirdes)

Returns file or directory info for directory descriptor.

Op code

RIA_OP_READDIR 0x21

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, dirent

Errno

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT, FR_NOT_ENOUGH_CORE

CLOSEDIR

int f_closedir(int dirdes)

Release the directory descriptor. Directory descriptor will rejoin the pool available for use by f_opendir().

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

EINVAL, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT

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

EINVAL, EBADF

SEEKDIR

int f_seekdir(long offs, int dirdes)

Set the read position for the directory descriptor. Internally, the FatFs directory read position can only move forward by one, so use this for convienence, not performance.

Op code

RIA_OP_SEEKDIR 0x24

C proto

rp6502.h

Parameters
  • dirdes – Directory descriptor from f_opendir().

Returns

Read position. -1 on error.

A regs

return, dirdes

Errno

EINVAL, EBADF, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT, FR_NOT_ENOUGH_CORE

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

dirdes

Errno

EINVAL, EBADF, FR_DISK_ERR, FR_INT_ERR, FR_INVALID_OBJECT, FR_TIMEOUT, FR_NOT_ENOUGH_CORE

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

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE

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, mask

Errno

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_FILE, FR_NO_PATH, FR_INVALID_NAME, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE

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

FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_PATH, FR_INVALID_NAME, FR_DENIED, FR_EXIST, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE

CHDIR

int chdir(const char* name)

Change to a directory entry.

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

FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NO_PATH, FR_INVALID_NAME, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE

CHDRIVE

int f_chdrive(const char* name)

Change durrent drive. Eight USB MSC drives are formally named “USB0:” to “USB7:” with shortcuts “0:” to “7:”.

Op code

RIA_OP_CHDRIVE 0x2A

C proto

rp6502.h

Parameters
  • name – Pathname of the directory to make.

Returns

0 on success. -1 on error.

A regs

return

Errno

FR_INVALID_DRIVE

GETCWD

int f_getcwd(char* name, int size)

Get the current working directory. Size is ignored by the OS but the C wrapper will use it.

Op code

RIA_OP_GETCWD 0x2B

C proto

rp6502.h

Parameters
  • name – The returned directory.

Returns

Size of returned name. -1 on error.

Errno

ENOMEM, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT, FR_NOT_ENOUGH_CORE

SETLABEL

int f_setlabel(const char* name)

Change the volume label. Max 11 characters.

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

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_INVALID_NAME, FR_WRITE_PROTECTED, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT

GETLABEL

int f_getlabel(const char* path, char* label)

Get the volume label. Label must have room for (11+1) characters.

Op code

RIA_OP_GETLABEL 0x2D

C proto

rp6502.h

Parameters
  • name – Volume name.

  • label – Storage for returned label.

Returns

Size of returned label. -1 on error.

A regs

return

Errno

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT

GETFREE

int f_getfree(const char* name, unsigned long* free, unsigned long* total)
struct {
   unsigned long free;
   unsigned long total;
};

Get the volume free and total space in number of 512 bytes blocks.

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

EINVAL, FR_DISK_ERR, FR_INT_ERR, FR_NOT_READY, FR_INVALID_DRIVE, FR_NOT_ENABLED, FR_NO_FILESYSTEM, FR_TIMEOUT

EXIT

void exit(int status)

Halt the 6502 and return the console to RP6502 monitor control. This is the only operation that does not return. RESB will be pulled down before the next instruction can execute. Status is currently ignored but will be used in the future.

In general, dropping the user back to the monitor is discouraged. But calling exit() or falling off main() is preferred to locking up.

Op code

RIA_OP_EXIT 0xFF

C proto

stdlib.h

A regs

status

Parameters
  • status – 0 is success, 1-255 for error.