Skip to content

Latest commit

 

History

History
378 lines (321 loc) · 16.5 KB

README.md

File metadata and controls

378 lines (321 loc) · 16.5 KB

agon512k

Access 512KB RAM from within BASIC on AgonLight (TM)

Memory: BASIC (64KB) + CUSTOM (384KB) + MOS (64KB)

This collection of assembler functions provide access to the extended memory (including and beyond the first 64KB) attached to the EZ80 CPU. The entire external RAM resides at addresses &40000 to &BFFFF, with BASIC normally using the lower 64KB (&40000 to &4FFFF), and MOS using the upper 64KB (&B0000 to &BFFFF). Now, you have another 384KB of RAM accessible from BASIC, ranging from &50000 to &AFFFF. You can access any part of the whole 512KB, if you are very careful not to clobber memory that will cause BASIC or MOS to crash.

For example, the empCMBI% procedure, detailed further below, is designed to copy memory blocks, and can be used to copy between RAM in the BASIC area (lower 64KB), and RAM in the extended area (above 64KB).

Versions:
V0.4 - 30-Apr-2023 - Couple of doc edits; no code changes.
V0.3 - 27-Apr-2023 - All tests performed to the extent designated by the "emtests.bas" program.
V0.2 - More tests added, but still testing "block" routines.
V0.1 - Initial release of code for beta testing of a number of routines.

NOTE: The provided routines do not modify or enhance the BASIC language, nor provide an easy way to allow you to write BASIC programs that are larger than would normally fit within the 40+KB available for programs. They provide a way to store data variables and/or blocks of data bytes in the upper RAM. This extends the variable/array capacity greatly. When used with the CHAIN command in BASIC, you could write large programs with lots of data.

The assembler functions can read or write the entire memory range, implying that you should be very careful not to clobber any memory used by BASIC, unless you know what effect it will have. It is up to you how to arrange or manage the upper memory. No allocation, deallocation, or garbage collection is provided. You simply call routines that write or read using specific addresses determined by your application.

In the following descriptions, the prefix "emp" means "extended memory procedure". The prefix "emf" means "extended memory function". The prefix "emd" means "extended memory data", and refers to a data parameter passed into or out of one of the extended memory procedures. The name "var" is a placeholder for a variable name of your choosing.

Regarding parameters, with the exception of string values, numeric expressions are typically expected, and may be constants, variables, computation results, function results, etc.

Many of the routines work with arrays. When working with 8-, 16-, 24-, or 32-bit array item values, the code automatically assumes the size of an array item to be 1, 2, 3, or 4 bytes, respectively. When working with float values, each item is 5 bytes in size. When working with an array of string values, the maximum item size must be specified manually, because strings have various lengths. The maximum item size in a string array is 256 bytes, meaning that the maximum string length inside an item is 255 bytes, because of the trailing CR character stored with the string.

The maximum array index size for any array is 65535 (&FFFF). This does not prevent you from having larger arrays, because you can arrange two or more arrays in memory such that they are physically together. It only means that you may need to reference the second (or third) array separately from the first array, and be sure to use base zero indexes in each array (i.e., range 0 to 65535).

The code does not presently support storing record-oriented data fields in an obvious manner; however, you can mimic that behavior in a couple of ways: (1) store data fields in subsequent memory locations such that they form a "record" (a set of consecutive data values of various types), and store a series of records in consecutive memory locations, or (2) use multiple arrays, with one array per data field, where each array holds only items of a particular data type. Typically, such arrays would have equal lengths (the same number of array items). Method (1) requires you to manage the memory yourself, but method (2) helps with array indexing, and only requires that the arrays do not overlap in memory.

PROC_empInit - Initialize routine addresses

This BASIC procedure will initialize the variables that are described in the following sections, with the addresses of the various assembler routines that may be called to read and to write extended memory. Call this procedure before calling the others.

Usage: PROC_empInit

emdSA% - Source address parameter

This parameter is a 24-bit source address that is required by some routines, as specified below. To access the first 64KB of memory, the address must be in the range &40000 to &4FFFF, not &00000 to &0FFFF. Any address in the range &40000 to &BFFFF is allowed. Be careful when specifying addresses within the BASIC or MOS areas!

Usage: !emdSA% = sourceaddress

emdDA% - Destination address parameter

This parameter is a 24-bit destination address that is required by some routines, as specified below. To access the first 64KB of memory, the address must be in the range &40000 to &4FFFF, not &00000 to &0FFFF. Any address in the range &40000 to &BFFFF is allowed. Be careful when specifying addresses within the BASIC or MOS areas!

Usage: !emdDA% = destinationaddress

emdAI% - Array index parameter

This parameter is a 16-bit array index that is required by some routines, as specified below. The array index ranges from 0 to 65535 (&FFFF). See comments above about splitting large arrays.

Usage: !emdAI% = arrayindex

emdIS% - Array item size parameter

This parameter is a 16-bit array item size that is required by some routines, as specified below. The item size ranges from 1 to 256 (&100). See comments above about splitting large arrays.

Usage: !emdIS% = itemsize

emdRC% - Repeat count parameter

This parameter is a 24-bit repeat count that is required by some routines, as specified below.

Usage: !emdRC% = repeatcount

emdV8% - Value parameter as 8 bits

This parameter is an 8-bit value that is required by some routines, as specified below.

Usage: ?emdV8% = value
Or: !emdV8% = value

emdV16% - Value parameter as 16 bits

This parameter is a 16-bit value that is required by some routines, as specified below.

Usage: !emdV16% = value

emdV24% - Value parameter as 24 bits

This parameter is a 24-bit value that is required by some routines, as specified below.

Usage: !emdV24% = value

emdV32% - Value parameter as 32 bits

This parameter is a 32-bit value that is required by some routines, as specified below.

Usage: !emdV32% = value

emdVS% - Value parameter as string

This parameter is a string value that is required by some routines, as specified below. When stored in memory, the string will be terminated by a carriage-return (CR, 0DH) character; therefore, the original string should not contain a carriage-return.

Usage: $emdVS% = stringvalue

empI% - Initialize upper RAM

This procedure clears (to zero) the middle 384KB of memory.

Usage: CALL empI%

emfG8% - Get 8-bit value

This function reads an 8-bit value from memory.

Usage: !emdSA% = sourceaddress: var%=USR(emfG8%)

emfG16% - Get 16-bit value

This function reads a 16-bit value from memory.

Usage: !emdSA% = sourceaddress: var%=USR(emfG16%)

emfG24% - Get 24-bit value

This function reads a 24-bit value from memory.

Usage: !emdSA% = sourceaddress: var%=USR(emfG24%)

emfG32% - Get 32-bit value

This function reads a 32-bit value from memory.

Usage: !emdSA% = sourceaddress: var%=USR(emfG32%)

empGS% - Get String (0..255 characters)

This procedure reads a string value from memory.

Usage: !emdSA% = sourceaddress: CALL empGS%: var$=$emdVS%

empGF% - Get Float (40 bits)

This procedure reads a float value from memory, and copies the value into the specified variable.

Usage: !emdSA% = sourceaddress: CALL empGF%,floatvariable

emfG8AI% - Get 8-bit item from array

This function reads an 8-bit array item from memory.

Usage: !emdSA% = arrayaddress: !emdAI% = array index: var%=USR(emfG8AI%)

emfG16AI% - Get 16-bit item from array

This function reads a 16-bit array item from memory.

Usage: !emdSA% = arrayaddress: !emdAI% = array index: var%=USR(emfG16AI%)

emfG24AI% - Get 24-bit item from array

This function reads a 24-bit array item from memory.

Usage: !emdSA% = arrayaddress: !emdAI% = array index: var%=USR(emfG24AI%)

emfG32AI% - Get 32-bit item from array

This function reads a 32-bit array item from memory.

Usage: !emdSA% = arrayaddress: !emdAI% = array index: var%=USR(emfG32AI%)

empGSAI% - Get String (0..255 characters) item from array

This function reads a string array item from memory. The given start address points to the start of the array (at item #0). The item size tells how big each array item is, which determines the maximum size of the string that can be stored there. For example, using an item size of 21, the maximum string length is 20, because of the trailing CR at the end of the string, while stored.

Usage: !emdSA% = arrayaddress: !emdIS% = itemsize: !emdAI% = array index: CALL empGSAI%: var$ = $emdVS%

empGFAI% - Get Float (40 bits) item from array

This procedure reads a float array item from memory, and copies the value into the specified variable.

Usage: !emdSA% = arrayaddress: !emdAI% = array index: CALL empGFAI%,floatvariable

empP8% - Put 8-bit value

This procedure writes an 8-bit value to memory.

Usage: !emdDA% = destinationaddress: !emdV8% = value: CALL empP8%
Or: !emdDA% = destinationaddress: ?emdV8% = value: CALL empP8%

empP16% - Put 16-bit value

This procedure writes a 16-bit value to memory.

Usage: !emdDA% = destinationaddress: !emdV16% = value: CALL empP16%

empP24% - Put 24-bit value

This procedure writes a 24-bit value to memory.

Usage: !emdDA% = destinationaddress: !emdV24% = value: CALL empP24%

empP32% - Put 32-bit value

This procedure writes a 32-bit value to memory.

Usage: !emdDA% = destinationaddress: !emdV32% = value: CALL empP32%

empPS% - Put String (0..255 characters)

This procedure writes a string value to memory. The original string must not contain a carriage-return (CR, 0DH) character, because BASIC will append one as a terminator when the $emdVS% construct is used in an assignment.

Usage: !emdDA% = destinationaddress: $emdVS% = stringvalue: CALL empPS%

empPF% - Put Float (40 bits)

This procedure copies the value from the specified float variable into memory.

Usage: !emdDA% = destinationaddress: CALL empPF%,floatvariable

empP8AI% - Put 8-bit item into array

This procedure writes an 8-bit array item to memory.

Usage: !emdDA% = arrayaddress: !emdAI% = array index: !emdV8% = value: CALL empP8AI%
Or: !emdDA% = arrayaddress: !emdAI% = array index: ?emdV8% = value: CALL empP8AI%

empP16AI% - Put 16-bit item into array

This procedure writes a 16-bit array item to memory.

Usage: !emdDA% = arrayaddress: !emdAI% = array index: !emdV16% = value: CALL empP16AI%

empP24AI% - Put 24-bit item into array

This procedure writes a 24-bit array item to memory.

Usage: !emdDA% = arrayaddress: !emdAI% = array index: !emdV24% = value: CALL empP24AI%

empP32AI% - Put 32-bit item into array

This procedure writes a 32-bit array item to memory.

Usage: !emdDA% = arrayaddress: !emdAI% = array index: !emdV32% = value: CALL empP32AI%

empPSAI% - Put String (0..255 characters) item into array

This procedure writes a string array item to memory. The given start address points to the start of the array (at item #0). The item size tells how big each array item is, which determines the maximum size of the string that can be stored there. For example, using an item size of 21, the maximum string length is 20, because of the trailing CR at the end of the string, while stored.

Usage: !emdDA% = arrayaddress: !emdIS% = itemsize: !emdAI% = array index: $emdVS% = stringvalue: CALL empPSAI%

empPFAI% - Put Float (40 bits) item into array

This procedure copies the value from the specified float variable into a float array item in memory.

Usage: !emdDA% = arrayaddress: !emdAI% = array index: CALL empPFAI%,floatvariable

empCMBI% - Copy memory block by incrementing addresses

This procedure copies a memory block from one location to another location, while incrementing addresses. It expects that either the source block or the destination block do not overlap, or the source address is greater than (or equal to) the destination address. If you know that the two blocks overlap, and the source address is less than the destination address, use the empCMBD% routine instead.

The source address must equal the lowest address in the source memory block. The destination address must equal the lowest address in the destination memory block. When this routine completes, the addresses will each point just past the high end of each block.

This procedure copies bytes, so the repeat count is a number of bytes. To copy N entities of size M, set the repeat count to N*M.

To set an address to the start of a particular array item, set the address to A+I*S, where A is the address of the array, I is the array index, and S is the size of one array item.

Usage: !emdSA% = sourceaddress: !emdDA% = destinationaddress: !emdRC% = repeatcount: CALL empCMBI%

empCMBD% - Copy memory block by decrementing addresses

This procedure copies a memory block from one location to another location, while decrementing addresses. It expects that either the source block or the destination block do not overlap, or the source address is less than (or equal to) the destination address. If you know that the two blocks overlap, and the source address is greater than the destination address, use the empCMBI% routine instead.

The source address must equal the highest address in the source memory block, plus 1. The destination address must equal the highest address in the destination memory block, plus 1. When this routine completes, the addresses will each point at the low end of each block.

This procedure copies bytes, so the repeat count is a number of bytes. To copy N entities of size M, set the repeat count to N*M.

To set an address to the start of a particular array item, set the address to A+I*S, where A is the address of the array, I is the array index, and S is the size of one array item. Note that to copy array item #I, you would set the address to point to array item #(I+1), because this routine copies bytes in reverse.

Usage: !emdSA% = sourceaddress: !emdDA% = destinationaddress: !emdRC% = repeatcount: CALL empCMBD%

empXMB% - Exchange (swap) memory blocks

This procedure moves the data from the source memory block into the destination memory block, and vice versa. The two blocks must not overlap.

This procedure copies bytes, so the repeat count is a number of bytes. To exchange N entities of size M, set the repeat count to N*M.

To set an address to the start of a particular array item, set the address to A+I*S, where A is the address of the array, I is the array index, and S is the size of one array item.

Usage: !emdSA% = sourceaddress: !emdDA% = destinationaddress: !emdRC% = repeatcount: CALL empXMB%

empZMB% - Zero memory block

This procedure fills the destination memory block with zeros, erasing any data that were there.

This procedure fills bytes, so the repeat count is a number of bytes. To fill N entities of size M, set the repeat count to N*M.

To set an address to the start of a particular array item, set the address to A+I*S, where A is the address of the array, I is the array index, and S is the size of one array item.

Usage: !emdDA% = destinationaddress: !emdRC% = repeatcount: CALL empZMB%