The C64 OS Programmer's Guide is being written

This guide is being written and released and few chapters at a time. If a chapter seems to be empty, or if you click a chapter in the table of contents but it loads up Chapter 1, that's mostly likely because the chapter you've clicked doesn't exist yet.

Discussion of development topics are on-going about what to put in this guide. The discusssions are happening in the C64 OS Community Support Discord server, available to licensed C64 OS users.

C64 OS PROGRAMMER'S GUIDE


Chapter 4: Using the KERNAL → Memory (module)

General Usage

These routines are general purpose; they can be used for anything. They are offered by the KERNAL because other parts of the KERNAL need to use this functionality.

memcpy

Purpose To copy 256-bytes of memory from one page to another.
Module offset 0
Communication registers A, Y
Stack requirements 2 bytes
Registers affected None
Input parameters A → Source page address
Y → Destination page address
Output parameters None

Description: This routine is used to copy 256-bytes of page-aligned memory from one page to another. It could be used, for example, to make a copy of a file reference or some other page-sized, page-aligned, memory structure. Load the source page number into the accumulator. Load the destination page number into the Y register.

memset

Purpose Fill a 256-byte page of memory with a byte.
Module offset 3
Communication registers A, Y
Stack requirements 2 bytes
Registers affected None
Input parameters A → Fill byte value
Y → Page address to fill
Output parameters None

Description: This routine is used to fill a page with a given byte. It is called automatically by pgalloc to clear the previous contents of the page. It can be used to pre-zero a page before reading data into it, such that the data, if less than 256 bytes, is guaranteed to be null terminated. Load the page address to fill into the Y register and the byte to fill the page with into the accumulator.

memfree

Purpose Count the number of unallocated memory pages.
Module offset 6
Communication registers X
Stack requirements 2 bytes
Registers affected A, X, Y
Input parameters None
Output parameters X ← Number of free pages

Description: This routine loops over the paged-memory allocation table and counts up all the pages that are marked as free (unallocated.) It returns the total number of free pages. The pages are not necessarily contiguous, and in fact, probably are not.


Memory Allocation

The following routines are for doing arbitrarily sized memory allocations. They require the existence of a memory pool from which to find and make the allocations. These routines are analogous to the C functions malloc and free. Realloc is available in the library mem.lib.r.

free

Purpose Deallocate a block of memory previously allocated using malloc.
Module offset 9
Communication registers X, Y
Stack requirements 2 bytes
Zero page usage $31, $32
Registers affected A, X, Y
Input parameters RegPtr → pointer to malloc'd memory.
Output parameters None

Description: This routine deallocates a block of memory that was previously allocated by malloc. The RegPtr must point to the exact address that was returned by malloc. You must only call free on a block of memory that has not previously been freed.

malloc

Purpose Allocate an arbitrarily sized block of memory.
Module offset 12
Communication registers A, X, Y
Stack requirements 6 bytes
Zero page usage $31, $32, $33, $34
Registers affected A, X, Y
Input parameters A → Memory pool (start page)
RegWrd → 16-bit length to allocate
Output parameters C ← Set on error
RegPtr ← Pointer to start of allocated memory

Description: This routine allocates a block of memory that has an arbitrary size, from 1 byte to multiple kilobytes. It requires a memory pool from which to make the allocation. Every call to pgalloc results in a block of one or more contiguous pages that, together, are initialized as a memory pool. When calling the malloc the first page byte of a valid memory pool must be provided in the accumulator.

A memory pool is only valid if its initialized memory pool header hasn't been overwritten, and the memory within the pool has been properly allocated with malloc rather than just being arbitrarily written to.

Free marks a previously allocated block as unallocated but leaves the allocation headers in place. Malloc starts at the beginning of the memory pool looking for an unallocated block equal or greater in size to the size being requested. If it encounters a block that is too small, it immediately attempts to merge the current block with another unallocated block following it. If the merge is successful, it checks again to see if this block is big enough, and repeatedly merges in blocks until one of two things has happened: The last merge resulted in a block big enough to use, or it was unable to do a merge because the following block is allocated. At this point it continues the search through the memory pool. When it finally finds a block big enough to use, it splits the block into the size it needs followed by a smaller block containing the remainder. Finally, if it is unable to find a block big enough to allocate, it returns with the carry set to indicate a failure.


Paged-Memory Allocation

These three routines are used for managing the paged-memory allocation system. This is a lower-level memory allocation system than malloc. The paged memory allocation uses a paged-memory allocation map, defined at memmap by //os/s/:memory.s

pgfree

Purpose Deallocate a range of pages previously allocated using pgalloc.
Module offset 15
Communication registers X, Y
Stack requirements 4 bytes
Zero page usage None
Registers affected A, X, Y
Input parameters Y → Page address to free
X → Number of consecutive pages to free
Output parameters C ← Set on error

Description: This routine is used to mark pages in the paged allocation table as free. It should be used to reverse the action of pgalloc, however it is less stringent than free. While free can only be used on a pointer that was previously allocated with malloc, and it always deallocates the exact size that was originally allocated, pgfree doesn't care how the pages were originally allocated or who allocated them. It just does exactly what it's told and marks X number of pages free starting at page Y.

If a block of pages is allocated with pgalloc, that block gets initialized automatically as a memory pool. If any part of that pool is subsequently freed using pgfree, the memory pool is no longer valid for use with malloc and free.

This routine calls updstat in the service module, to mark the status bar as dirty and requiring a redraw.

pgmark

Purpose Manually mark a range of pages as allocated.
Module offset 18
Communication registers X, Y
Stack requirements 4 bytes
Zero page usage None
Registers affected A, X, Y
Input parameters Y → First page to mark
X → Last page to mark
Output parameters None

Description: This routine is used to manually mark a range of pages as allocated by the Application. It does not do any validation checking, it just writes #mapapp to the page allocation table for all pages from Y to X, inclusive.

This routine calls updstat in the service module, to mark the status bar as dirty and requiring a redraw.

pgalloc

Purpose Allocate a set of contiguous pages.
Module offset 21
Communication registers A, X, Y
Stack requirements 4 bytes
Zero page usage $31, $32
Registers affected A, X, Y
Input parameters A → Allocation type
X → Number of contiguous pages to allocate
Output parameters Y ← First allocated page address
C ← Set on errror

Description: This routine is used to allocate a contiguous range of pages. You put the allocation type in the accumulator, and the number of pages to allocate in the X register. Upon return, the carry is set if it was unable to find the requested number of contiguous free pages. Nothing is allocated on error. If the carry is clear, the Y register holds the first page address of the range that was allocated.

Pages allocated using pgalloc are automatically zeroed, clearing their previous contents, and initialized as a memory pool, suitable for use with malloc and free.

This routine calls updstat in the service module, to mark the status bar as dirty and requiring a redraw.

The available allocation types are defined by //os/s/:memory.s. One byte for each page appears in the paged-memory allocation map. The map only covers page $09 to page $a0. The pages outside of this range are either implicitly unavailable or managed in a different way.

Allocation Type Value Description
mapfree $00 Page is unallocated
mapsys $01 Page is allocated by the system
maputil $02 Page is allocated by a Utility
mapapp $ff Page is allocated by an Application

REU Helper Routines

These routines help with storing and retrieving page-sized blocks of memory to and from an REU. These routines honor the number of 64K banks that have been reserved for fast app switching, and abstract which banks are actually being used.

reuconf

Purpose Configure the REU for a pgfetch or pgstash transfer.
Module offset 24
Communication registers A, X, Y
Stack requirements 2 bytes
Zero page usage None
Registers affected A, X, Y
Input parameters RegPtr → REU bank and page
A → Configure flags
Output parameters C ← Set on no REU available
A ← Number of banks available to the Application

Description: This routine prepares the REU for a pgfetch or pgstash transfer. The RegPtr sets the bank and page numbers, these are the REU's high and mid bytes for its internal storage. The high byte gets internally offset by adding to it the number of reserved banks for fast app switching.

The only configuration flag available is reu_inc, defined in //os/s/:io_rec.s. If this is set, then after any pgstash or pgfetch the REU's internal bank and page are incremented. This allows you to set the start bank/page and then call pgfetch repeatedly to continually get the next page of data.

pgfetch

Purpose Fetch a 256-byte page of data from an REU.
Module offset 27
Communication registers X, Y
Preparatory routines reuconf
Stack requirements 2 bytes
Zero page usage None
Registers affected A, X, Y
Input parameters RegPtr → C64 memory buffer to fetch to
Output parameters C ← Set on error

Description: This routine fetches a 256-byte page of memory from an REU to the C64's main memory. The RegPtr passed to this routine specifies where in the C64's memory the fetched data should be put. I/O is mapped in for this transfer. The C64's memory buffer does not need to be page aligned. You must call reuconf prior to calling pgfetch. If reuconf was configured to auto increment the bank and page, then after calling pgfetch the REU's page number is incremented. If the page number rolls over from $ff to $00, then the bank number is incremented. pgfetch can be called multiple times after calling reuconf only once in preparation.

pgstash

Purpose Stash 256-bytes from main memory to a page-aligned block of memory in an REU.
Module offset 30
Communication registers X, Y
Preparatory routines reuconf
Stack requirements 2 bytes
Zero page usage None
Registers affected A, X, Y
Input parameters RegPtr → C64 memory buffer to stash from
Output parameters C ← Set on error

Description: This routine stashes 256-bytes from the C64's main memory to a page-aligned block of memory in the REU. The RegPtr passed to this routine specifies where in the C64's memory the stashed data should come from. I/O is mapped in for this transfer. The KERNAL and/or BASIC ROMs may or may not be mapped in for this transfer. The C64's memory source does not need to be page aligned. You must call reuconf prior to calling pgstash. If reuconf was configured to auto increment the bank and page, then after calling pgstash the REU's page number is incremented. If the page number rolls over from $ff to $00, then the bank number is incremented. pgstash can be called multiple times after calling reuconf only once in preparation.



KERNAL Modules in Alphabetical Order

KERNAL Modules in Module Lookup Table Order

Return to Using the KERNAL → KERNAL Modules


Table of Contents



This document is subject to revision updates.

Last modified: Apr 20, 2023