Making Effective Use of Memory
The PDQ Board’s memory map
The Freescale 9S12 (HCS12) microcontroller has a native address space of 64 Kbytes, but it can address up to 1 megabyte of memory implemented as 64 pages of 16 Kbyte each. The PDQ Single Board Computer (SBC) includes a variety of convenient memory types, including:
- sector-programmable Flash on the processor chip (onchip Flash),
- byte-programmable nonvolatile EEPROM,
- paged RAM backed up by an onboard Flash chip (shadowed RAM), and
- common RAM that is available regardless of the current page for variable storage, buffers and stacks.
Part of the common RAM is on the processor chip (onchip RAM), and the rest is implemented by an external RAM chip on the board. The memory and memory-mapped hardware on the PDQ Board fills the processor’s 1 Mbyte memory space, so there is no external memory bus brought out. However, if you need more memory you can simply plug in a Compact Flash Wildcard module to add 512 Mbytes or more of removable mass memory.
Flash memory is nonvolatile, so it retains its contents even when power is removed. Simple write-cycles do not modify the Flash memory contents, so program code stored in Flash is safe even if the processor gets lost and overwrites memory. Flash memory is also re-programmable, and the Flash programming functions are present in the PDQ Board’s onboard software library. Flash is ideal for storing compiled program code.
Code can also be compiled into paged RAM and saved to a shadow Flash device. Much as your desktop PC loads pre-compiled code from the hard drive into RAM each time you turn it on, you can configure the PDQ Board to load specified pages from the shadow Flash into paged RAM upon each power-up, reset or restart. The RAM has fast access time and can support full speed program execution, while the slower external shadow Flash provides nonvolatile storage of the contents when power is removed. Designated page regions (pages 0x00-0F and/or pages 0x10-13) of this shadowed RAM can be automatically write protected after the contents are loaded from the shadow Flash, so that an unexpected processor crash can not corrupt the RAM contents. Like Flash, write-protected shadowed RAM is an ideal place to store a compiled application program. Regions of shadowed RAM that are not needed for code storage can be dedicated to the storage of arrays of volatile data.
The PDQ Board includes 512K onchip Flash memory, 14K onchip RAM, 1K useable onchip EEPROM, and 496K off-chip RAM with Flash backup. Code can be located in the write-protectable Flash-backed RAM or the onchip Flash. Some memory is reserved for use by the Kernel (operating system), and the remaining memory is available for use by your application program.
Figure 5-1.
The paged memory space of the PDQ Board showing its 1MB paged memory and 48KB common memory. Pages 00-1D of RAM are transparently backed up by shadow Flash.
Figure 5-1 illustrates the memory map. The processor’s native address space is only 64K, so a paging architecture is used to expand the addressable memory to 1 Mbyte. “Common memory” is accessible from any page, and “paged memory” comprises sixty four 16K pages located at addresses 0x8000 to 0xBFFF on pages 0x00 through 0x3F. The current page is specified by the contents of the processor’s PPAGE register, also called the PAGE_LATCH. As shown in the figure, the top 16K of the memory space is reserved for the common Kernel Flash. The bottom 32K of the memory space is common memory that is accessible regardless of the page, and comprises the 1K processor registers, 1K of useable common EEPROM, 14K of internal (onchip) common RAM, and 16K of external common RAM. The application program can use 10K of common onchip RAM at 0x0800-0x0FFF and 0x2000-0x3FFF, plus the 16K of common RAM at 0x4000-0x7FFF.
The HCS12 processor chip contains 4 Kbytes of EEPROM at 0x0000-0x0FFF, but fully 3 Kbytes are hidden by higher priority onchip resources (1K of registers at 0x0000-0x3FF and 2K of onchip RAM at 0x0800-0x0FFF). The kernel reserves decimal 640 bytes of EEPROM at 0x0400-0x067F. Your application program can store calibration constants and other nonvolatile data in the remaining 384 bytes of available common EEPROM at addresses 0x680 to 0x7FF. EEPROM can be written one to four bytes at a time using Kernel drivers declared in the memory.h file, and the memory EEPROM contents are retained even when power is removed.
The paged memory is located in the 16 Kbyte region at addresses 0x8000-0xBFFF. Pages 0x00 through 0x1D (decimal page 29) are implemented as fast RAM shadowed by Flash. Of these pages, pages 0x00 through 0x13 can be optionally write-protected in two regions: pages 0x00-0F (region 1), and pages 0x10-13 (region 2), so they are ideal for code and non-volatile data. If these pages are not needed for program code, they can be left as write-enabled RAM and used for volatile data storage. Pages 0x14 through 0x1D cannot be write-protected, so they are best used for volatile data storage. The kernel reserves page 0x1D: the top portion from 0x9C00 to 0xBFFF holds system arrays and buffers, and the bottom portion from 0x8000 to 0x9BFF is allocated for code and names definitions that can be used for interactive debugging after a COLD restart. The operating system implements a heap memory manager and FORTH_ARRAY operators at pages 0x18–0x1C that make it easy to take advantage of this 80K of contiguous RAM for volatile data storage.
After a COLD restart, the operating system sets DP to 0x8000 and NP to 0x9000 on page 0x1D so that short interactive debugging routines can be compiled in this out of the way location. The COLD restart also initializes an 80K heap to fill pages 0x18 to 0x1C; this heap is useable by either Forth or C.
Forth programmers using the recommended DEFAULT.MAP will compile code (pointed to by dictionary pointer DP) starting at page 0x00, and names (pointed to by names pointer NP) starting at page 0x10. The Forth DEFAULT.MAP function initializes the variable pointer VP to 0x2000, and leaves the heap occupying pages 0x18-1C.
Pages 0x20 through 0x37 provide 384K of onchip Flash inside the HCS12 processor chip that is available for application code and pre-compiled libraries. It is typically used for pre-compiled device driver libraries, graphics images, and other non-volatile data objects, but it can also be used for compiled C application code. Pages 0x38 through 0x3F hold the QED-Forth real-time operating system in write-protected onchip Flash.
To recap, the PDQ Board uses a paged memory system to expand the processor’s native 64 Kbyte address space to 1 Megabyte of addressable memory. The top 16 Kbytes at addresses 0xC000-0xFFFF access the common kernel, and the bottom 32 Kbytes at addresses 0x0000-0x7FFF access the common registers, EEPROM, and common RAM. These common memory areas always visible (i.e., accessible using standard 16-bit addresses) to any code running, no matter where it resides in the memory space. The remaining 16 Kbytes of the address space at addresses 0x8000 to 0xBFFF is duplicated 64 times and addressed through the processor’s 16-bit address bus augmented by a 6-bit page address. Together the address and a padded-out version of the page are held in a 32-bit data type, an xaddress, which is described in more detail in Using Paged Memory below.
Memory allocation
The Mosaic IDE Plus intelligently allocates memory. C source code is compiled into paged memory, and allowed to span across many pages. The PPAGE register is seamlessly managed in the background so that you don't need to worry about it. The only limit is that one function cannot be larger than one 16K page (which is poor coding style anyways). Variables are treated differently, and need to be addressed in common (unpaged) memory. The default memory map is very generous, giving ample space for variables and code.
| Area | Address | Size | Remarks |
|---|---|---|---|
| Variables | 0x2100 | 20K | Due to overhead user variables start at about 0x230C |
| Code | 0x08000-0x0BFFF,on 13 pages | 208K | Code begins on page 0x0 and goes till page 0xD |
| EEPROM | 0x0680–0x07FF | 384 bytes | |
| Debug Headers | 0x108000 | 16K | A header is generated for every _q function |
Kernel versus application memory space
Table 5-1 details the partitioning of the onboard memory between the operating system (the Kernel) and your application functions. Of the 1 MB+ of memory on the PDQ Board, the kernel reserves 128K of onchip flash, 12K of RAM, and 640 bytes of EEPROM. The remaining memory is available for the application program and its data.
| Partition of Flash and RAM among Kernel and Application Functions | ||||
|---|---|---|---|---|
| Function | Size | Memory Page | Memory Address | Physical Location |
| Kernel RAM (12K) | ||||
| Kernel stacks, buffers, task area | 4K | common | 1000 – 1FFF | HCS12 Processor Chip |
| Kernel hash array, buffers | 8K | 1D | A000 – BFFF | PDQ Board RAM |
| Kernel EEPROM (640 bytes) | ||||
| Kernel vectors and structures | 640 b | common | 0400 – 067F | HCS12 Processor Chip |
| Processor Registers (1K) | ||||
| Kernel/HCS12 Hardware Registers | 1K | common | 0000 – 03FF | HCS12 Processor Chip |
| Kernel Flash (128K) | ||||
| Common Kernel Code | 16K | common | C000 – FFFF | HCS12 Processor Chip |
| Kernel Code | 112K | 38 – 3E | 8000 – BFFF | HCS12 Processor Chip |
| Application RAM (26K) | ||||
| Application data and task areas | 2K | common | 0800 – 0FFF | HCS12 Processor Chip |
| Application data and task areas | 8K | common | 2000 – 3FFF | HCS12 Processor Chip |
| Application data | 16K | common | 4000 – 7FFF | PDQ Board RAM |
| Application Non-Write-Protectable Shadowed RAM (144K) | ||||
| Application paged RAM and/or Heap area for FORTH_ARRAYs | 144K | 14 – 1C | 8000 – BFFF | PDQ Board RAM backed by PDQ Board Flash |
| Application paged RAM or Default Forth DP & NP after COLD restart | 8K | 1D | 8000 – 9FFF | PDQ Board RAM |
| Application Write-Protectable Shadowed RAM (320K) | ||||
| Application code and data (Write protect region 1 = pages 00–0F) (Write protect region 2 = pages 10–13) | 320K | 00 – 13 | 0000 – 7FFF | PDQ Board RAM backed by PDQ Board Flash |
| Application EEPROM (384 bytes) | ||||
| EEPROM Variables | 384 b | common | 0680 – 07FF | HCS12 Processor Chip |
| Application Flash (384K) | ||||
| Application code, device drivers | 384K | 20 – 37 | 8000 – BFFF | HCS12 Processor Chip |
| Shadow Flash (480K) | ||||
| Transparently backs-up RAM | 480K | 00 – 1D | 8000 – BFFF | 512K onboard Flash chip |
|
Notes:
| ||||
Common memory
The common memory which is accessible regardless of the page is also partitioned between the operating system and application program. Table 5-2 presents a summary of the common memory addresses used by the operating system, and in bold type those addresses available to the application program.
Referring to Table 5-2, there are four unencumbered common memory areas totaling 26 Kbytes of RAM and 384 bytes of EEPROM that your application can use. The C compiler automatically allocates TASK areas, buffers, C arrays and variables in the common RAM, and you can designate EEPROM variables that are allocated to the user-available EEPROM area as explained later in this Chapter.
Forth programmers typically start their program with the DEFAULT.MAP declaration that initializes the VP (variable pointer) at 0x2000 to take advantage of the common RAM, and the EEP (EEPROM pointer) at 0x0680 to take advantage of available EEPROM.
Available common memory areas
0x0400 – 0x07FF. Locations 0x0400 – 0x067F are reserved by the operating system for use by the interrupt vectors, SAVE and RESTORE utilities, and for segment management data structures. EEPROM at 0x0680 – 0x07FF is available to your programs. The pre-coded Kernel functions StoreEEChar, StoreEEInt, StoreEELong, StoreEEFloat, and ToEEPROM declared in the memory.h header file can store data into the EEPROM. Fetching data from EEPROM uses standard read cycles and does not require the use of special functions.
0x0800 – 0x0FFF and 0x2000 – 0x3FFF: The processor’s 14K of onchip RAM extends from 0x0800 to 0x3FFF, and the kernel reserves a 4K block at 0x1000. The remaining 10K of onchip RAM available for the application program comprises the 2K block at 0x0800-0FFF and the 8K block at 0x2000-0x3FFF. This onchip RAM is ideal for task areas, program-implemented stacks, buffers, arrays, and variables. Task areas as declared by the TASK typedef (see the USER.h file for its definition) are preferentially allocated by the C compiler in onchip RAM to optimize the timing of stack operations.
Note that the 8K block of onchip RAM at 0x2000-0x3FFF is contiguous with the following 16K block of off-chip common RAM, resulting in a 24K block of contiguous common RAM available for your application program.
0x4000 – 0x7FFF: These 16K bytes of common RAM are also available for run-time variables, buffers and arrays. They are useable but not ideal (because of slight timing differences in HCS12 stack push/pull instructions) for implementing TASK areas and stacks.
The remainder of the common memory area is used by either the processor or the kernel. The processor’s 1K register block is located at 0x0000 – 0x03FF, the kernel reserves EEPROM at 0x400-0x067F, and the operating system reserves common RAM at 0x1000-1FFF for user areas, buffers, and stacks.
Using paged memory
The PDQ Board uses a paged memory system to expand the processor’s native 64 Kbyte address space to 1 Megabyte of addressable memory. The 16 Kbyte page window at addresses 0x8000 to 0xBFFF is duplicated 64 times and addressed through the processor’s 16-bit address bus augmented by a 6-bit page address. Although 6 bits are sufficient to address the 64 possible pages in the HCS12 architecture, the page is padded out to a more standard 16-bit date type so that the full address, lower 16 bits plus 16-bit page, occupies 32 bits. We’ll refer to this full address as an xaddress (32-bit extended addresses).
Click here for implementation details.
A subroutine on any page can fetch or store to any address on the same page or in the common memory, or transfer control to another routine in common memory. A routine in paged memory “sees” a 64K address space comprising its own page window at addresses 0x8000 to 0xBFFF, with the common memory filling the rest of the address space. To access data stored on another page, special memory access routines located in the common Kernel Flash are used to change the page, fetch or store the data, restore the page, and return. These routines are declared in the memory.h header file, and include functions such as FetchChar, FetchInt, FetchLong, FetchFloat, StoreChar, StoreInt, StoreLong, and StoreFloat. To move blocks of data from one location to another in paged or common RAM, use the CMoveMany, CmoveManyCheck, or ToMemory routines.
The heap memory manager and array routines allow you to think of the paged memory as contiguous memory for data storage, and include useful paged data access routines such as ArrayFetch, FArrayFetch, ArrayStore, and FArrayStore as declared in the array.h file. To make this easier, three macros are available in the C:\MosaicPlus\c\libraries\include\mosaic\types.h file to manipulate xaddresses and their constituent 16-bit addresses and pages. The TO_XADDR macro combines a specified 16-bit address and page into a single 32-bit extended address. The XADDR_TO_ADDR macro extracts the 16-bit address from a specified 32-bit xaddress, and the XADDR_TO_PAGE macro extracts the page from a specified 32-bit xaddress.
The operating system automatically handles function calls and returns among the pages in both the C and Forth languages. There is very little speed penalty associated with changing pages. The C compiler is configured to use the HCS12’s page-aware CALL and RTC assembly instructions for function invocation, so that functions can be called from anywhere in the paged or common memory space. For its part, the QED-Forth compiler is inherently page aware and compiles page-smart function calls wherever they are required.
While the C compiler can invoke functions on any page, it assumes that all data (such as static variables and strings) are in common memory accessible via simple 16-bit native addresses. Sophisticated programs sometimes need to reference data in paged memory, either using the FORTH_ARRAY approach described above, or using 32-bit xaddr from C. To make this easier, three macros are available in the C:\MosaicPlus\c\libraries\include\mosaic\types.h file to manipulate xaddresses and their constituent 16-bit addresses and pages. The TO_XADDR macro combines a specified 16-bit address and page into a single 32-bit extended address. The XADDR_TO_ADDR macro extracts the 16-bit address from a specified 32-bit xaddress, and the XADDR_TO_PAGE macro extracts the page from a specified 32-bit xaddress.
See also → Real Time Programming
