Using paged RAM

From Spectrum
Jump to navigation Jump to search

The Spectranet hardware in its standard form not only provides the ethernet hardware, it also provides extra general purpose memory. 128K of this is flash ROM - which can be programmed by the Spectrum, without any need to muck around with separate programming hardware, or UV erasure - and 128K of this is static RAM.

The paged memory on the Spectranet is organized as 4K pages, and the hardware supports up to 256 pages of memory (for a total of 1MB of address space). Two pages are permanently mapped - 4K of flash is mapped to 0x0000 - 0x0FFF, and provides things such as the socket library, utility routines, buffer handlers etc. A page of RAM is permanently mapped to 0x3000 - 0x3FFF and provides temporary workspace and Spectranet system variables. Between 0x1000 and 0x2FFF, however, any memory page can be mapped in. The memory is general purpose and may be used for programs and data.

The total memory map stretches from 0x00:000 to 0xFF:FFF - the number before the colon being one of the 256 4K pages, and the number afterwards being the address within that page. The 1MB of address space looks like this:

Key: Red = flash ROM. Yellow = W5100. Blue = static RAM. Grey = no connected hardware

The two paging areas in the Z80's address space between 0x1000 and 0x2FFF are referred to as paging area A (0x1000-0x1FFF) and paging area B (0x2000-0x2FFF). Generally, the base Spectranet functions tend to page data memory into paging area A (for instance, the 42 column character set, or the W5100 register/buffer areas) and programs into area B - but there are no hard and fast rules. If you intend to call socket functions from within this space, however, you need to remember this as your program will crash if it's trying to run out of paging area A (without using a call dispatcher that ensures that paging area A is reset to its original state, more on this later).

Paging in memory

Firstly, please resist the temptation to directly use OUT instructions to page the memory unless it is absolutely necessary. At this stage, it's not only possible but likely that the ports used to page the memory will be changed, as more hardware is tested for compatibility. Your program will stop working if the I/O port is changed in a later CPLD revision.

Two functions are provided for changing which page of memory is in which area, and is available to both assembly language and C programs. The paging functions are called setpagea and setpageb, and as their name suggests, select which page appears in paging area A (0x1000-0x1FFF) and paging area B (0x2000-0x2FFF). These functions also keep the system variables up to date. There are also similar functions that additionally save the current page on the stack, called pushpagea and poppagea (and pageb, of course).

The current page that's in each paging area is stored in the system variables v_pga and v_pgb (0x3F05 and 0x3F06, respectively). You'll note from the below 16K address that these aren't in the ZX system variables area, but the Spectranet system variables area (which occupies most of the memory between 0x3F00 and 0x3FF7).

Here is an example of the usage of the setpagea routine, in asm:

    ld a, 0xC2     ; page 0xC2
    call SETPAGEA

And here's an example in C:

    setpagea(0xC2);

It's very simple.

If your program is running from the Spectrum's main RAM, you are going to need to be able to page out the Spectrum's ROM and put the Spectranet memory in its place. This is done with the pagein and pageout entry points. These are very simple, and trigger the CPLD's CALL trap mechanism. When the CPLD decodes the CALL 0x3FF9 (CALL PAGEIN) instruction, it pages in the Spectranet address space. The instruction at 0x3FF9 is just a RET instruction. Similarly, when the CPLD sees the CPU fetch an instruction at address 0x007C, it causes the memory to be paged out. Again, this is a RET instruction.

It is important not to use a conditional call or a jump for the pagein operation. This is because the CPLD is decoding the CALL instruction rather than just an instruction fetch at this address - this is to avoid compatibility problems with ROMs that have code at this address. The pagein operation can only be CALL 0x3FF9. (The hardware intercepts a CALL to an address between 0x3FF8 and 0x3FFF. 0x3FFA is used for the HLCALL entry point, and 0x3FFD is used for the IXCALL entry point).

Calling Spectranet functions while Spectranet memory is paged in

You will see all the various function calls documented with the IXCALL or HLCALL mechanism. However, if you want Spectranet memory to remain paged in (for example, when your code is running from Spectranet memory, or for code that's running in main memory that needs to make more accesses to Spectranet memory), do not use IXCALL and HLCALL, because when the function call ends, the Spectranet memory will be paged out. For example:

    ; Normal method - use HLCALL for auto paging
    ld c, SOCK_STREAM
    ld hl, SOCKET
    call HLCALL
    ; Call method when Spectranet memory is paged in, and needs to remain paged in
    ld c, SOCK_STREAM
    call SOCKET

If you are using C, link to libsock_nopage.lib or libspectranet_nopage.lib (instead of libsock.lib and spectranet.lib).

If you aren't going to be using the Spectrum ROM in your program, you'll also save a few CPU cycles by paging in the Spectranet ROM explicitly with CALL PAGEIN, then making direct calls to the indirect jump table. Don't forget to call PAGEOUT before returning to BASIC, though.

Reading and writing RAM

The static RAM is accessed no differently to the dynamic RAM on board the Spectrum - just use the normal instructions as you would anywhere else.