.defpage

.defpage number, size [, origin]

This defines a binary page for the output. By default, the output is configured to be a single, 64KB page (with a page number of 0), which is usually enough for simple programs/platforms. Breaking up your program into a series of pages is usually the way around the 64KB addressable memory limit of the Z80 CPU. How your device pages different areas of memory is entirely device specific, but these routines try to help you.

Let us suppose our mythical device uses 8KB pages. It has 16KB total memory; the first 8KB of memory is fixed as page 0; the last 8KB is swappable by writing the required page number to port $40. We could set up the paging like this:

.defpage 0, $2000, $0000 ; $2000 is 8KB
.defpage 1, $2000, $2000 ; \_ both pages are 8KB, and both 
.defpage 2, $2000, $2000 ; /  start at address $2000.

.page 0 ; This is page 0.

; Swap in page #1:
    ld a,1
    out ($40),a
    call $2000 ; C will now be 1.

    ld a,2
    out ($40),a
    call $2000 ; C will now be 2.
    
    ; ...

.page 1 ; Page 1...
    ld c,1
    ret

.page 2 ; Page 2...
    ld c,2
    ret

I'm sorry if this seems a little confusing, I'll try to explain it as best as I can.

For our imaginary device, there is only memory addresses $0000 up to $3FFF. The first $2000 bytes are always occupied by page 0. The $2000-$3FFF range will either be page 1 or page 2; regardless of which page is loaded in there, the range of addresses is $2000 to $3FFF. We cannot store binary files in this manner, sadly, which means that when we output the file we put page 2 after page 1. The addresses of page 2 are still calculated as if they were in the $2000-$3FFF range, even though the data is stored at $4000-$5FFF. We assume that the ROM burner or emulator will be able to work out how to arrange the file on the media correctly.