<< Previous | Index | Next >>

Chapter 5. Rabbit Memory Organization

The Rabbit architecture is derived from the original Z80 microprocessor. The original Z80 instruction set used 16-bit addresses to address a 64K memory space. All code and data had to fit in this 64K space. The Rabbit adopts a scheme similar to that used by the Z180 to expand the available memory space. The 64K space is divided into zones and a memory mapping unit or MMU maps each zone to a block in a larger memory; the larger memory is 1MB in the case of the Z180 or the Rabbit 2000. The zones are effectively windows to the larger memory. The view from the window can be adjusted so that the window looks at different blocks in the larger memory. Figure 5-1 on page 24 shows the memory mapping schematically.

5.1 Physical Memory

The Rabbit has a 1MB physical memory space. In special circumstances more than 1MB of memory can be installed and accessed using auxiliary memory mapping schemes. Typical Rabbit systems have two types of physical memory: flash memory and static RAM memory. Flash memory follows a write-once-in-a-while and read-frequently model. Depending on the particular type of flash used, the flash memory will wear out after it has been written approximately 10,000 to 100,000 times.

5.1.1 Flash Memory

Flash memory in a Rabbit-based system may be small-sector type or large-sector type. Small-sector memory typically has sectors of 128 to 1024 bytes. Individual sectors may be separately erased and written. In large-sector memory the sectors are often 16K or 64K or more. Small-sector memory provides better support for program development and debugging, and large-sector memory is less expensive and has faster access time. The best solution will usually be to lay out a design to accept several different types of flash memory, including the flexible small-sector memories and the fast large-sector memories.

At the present time development support for programs tested in flash memory is confined to flash memories with small sectors. If larger sectors are used, the code must be debugged in RAM and then loaded to flash. Large-sector flash is desirable for the better access time and power consumption specifications that are available. Dynamic C is being modified to handle large sector flash at the time of this writing.

5.1.2 SRAM

Static RAM memory may or may not be battery-backed. If it is battery-backed it retains its data when power is off. Static RAM chips typically used for Rabbit systems are 32K, 64K, 128K, 256K, or 512K. When the memory is battery-backed, power is supplied at 2 V to 3 V from a backup battery. The shutdown circuitry must keep the chip select line high while preserving memory contents with battery power.

5.1.3 Basic Memory Configuration

A basic Rabbit system has two static memory chips: one flash memory chip and one RAM memory chip. Additional static memory chips may be added. If an application requires storing a lot of data in flash memory, another flash memory chip can be added, creating a system with three memory chips--two flash memory chips and one RAM chip.

Trying to use a single flash memory chip to store both the user's program and live data that must be frequently changed can create software problems. When data are written to a small-sector flash memory, the memory becomes inoperative during the 5 ms or so that it takes to write a sector. If the same memory chip is used to hold data and the program, then the execution of code must cease during this write time. The 5 ms is timed out by a small routine executing from root RAM while system interrupts are disabled, effectively freezing the system for 5 ms. The 5 ms lockup period can seriously affect real-time operation.

5.2 Memory Segments

From the point of view of a Dynamic C programmer, there are a number of different uses of memory. Each memory use occupies a different segment in the logical 16-bit address space. The four segments are shown here:

Figure 5-1. Memory Map of 16-bit Addressing Space

Figure 5-1 shows that the Rabbit does not have a flat memory space. The advantage of the Rabbit's memory organization is that the use of 16-bit addresses and pointers is retained, ensuring that the code is compact and executes quickly.

NOTE The relative size of the root memory and data segments can be adjusted in 4K steps.

5.2.1 Definitions

Extended Code: Instructions addressed in the extended memory segment.

Extended Constants: C constants addressed in the extended memory segment. They are mixed together with the extended code.

Extended Memory: Logical addresses above 0xDFFF; also known as xmem.

Extended RAM: RAM not used for root variables or stack. Extended memory in RAM may be used for large buffers to save root RAM space. The function xalloc() allocates space in extended RAM memory.

Root Code: Instructions addressed in the root memory segment.

Root Constants: C constants, such as quoted strings or data tables, addressed in the root memory segment.

Root Memory: Logical addresses below 0xE000.

Root Variables: C variables, including structures and arrays that are not initialized to a fixed value, are addressed in the data segment.

5.2.2 The Root Memory Segment

The root memory segment has a typical size of 24K. The larger the root memory segment, the smaller the data segment and vice-versa. Root memory segment address zero is always mapped to 20-bit address zero. Usually the root memory segment is mapped to flash memory since root code and root constants do not change except when the system is reprogrammed. It may be mapped to RAM for debugging, or to take advantage of the faster access time offered by RAM.

The root memory segment holds a mixture of code and constants. C functions or assembly language programs that are compiled to the root memory segment are interspersed with data constants. Data constants are inserted between blocks of code. Data constants defined inside a C function are put before the end of the code belonging to the function. Data constants defined outside of C functions are stored as encountered in the source code.

Except in small programs, the bulk of the code is executed using the xmem segment. But code in the root memory segment operates slightly faster, also the root memory segment has special properties that make it better for some types of code.

5.2.2.1 Types of Code Best-Suited for the Root Memory Segment

5.2.3 The Data Segment

The data segment is mapped to RAM and contains C variables. Typically it starts at 8K or above and ends at 52K (0xCFFF). Data allocation starts at or near the top and proceeds in a downward direction. It is also possible to place executable code in the data segment if it is copied from flash to the data segment. This can be desirable for code that is self modifying, code to implement debugging aids or code that controls write to the flash memory and cannot execute from flash. In some cases RAM may require fewer wait states so code executes faster if copied to RAM.

5.2.4 The Stack Segment

The stack segment normally is from 52K to 56K (0xD000-0xDFFF). It is always mapped to RAM and holds the system stack. Multiple stacks may be implemented by defining several stacks in the 4k space or by remapping the 4K space to different locations in physical RAM memory, or by using both approaches.

For example, if 16 stacks of 1k length are needed then 4 stacks can be placed in each 4K mapping and 4 different mappings for the window can be used.

5.2.5 The Extended Memory Segment

This 8K segment from 56K to 64K (0xE000-0xFFFF) is used to execute extended code and it is also used by routines that manipulate data located in extended memory. While executing code the mapping is shifted by 4K each time the code passes the 60K point. Up to a megabyte of code can be efficiently executed by moving the mapping of the 8K window using special instructions (long call, long jump and long return) that are designed for this purpose. This uses up only 8K of the 16-bit addressing space.

5.3 How The Compiler Compiles to Memory

The compiler generates code for root code, root constants, extended code and extended constants. It allocates space for data variables, but, except for constants, does not generate data to be stored in memory. Any initialization of variables must be accomplished by code since the compiler is not present when the program starts in the field.

5.3.1 Placement of Code in Memory

Code may be placed in either extended memory or root memory. Functions execute at the same speed, but calls to functions in root memory are slightly more efficient than calls to functions in extended memory.

In all but the smallest programs, most of the code is compiled to extended memory. Since root constants share the memory space needed for root code, as the memory needed for root constants increases, the amount of code that can be stored in root memory decreases, and code must be moved to extended memory.

5.3.2 Paged Access in Extended Memory

The code in extended memory executes in the 8K window from 0xE000 to 0xFFFF. This 8K window uses paged access. Instructions that use 16-bit addressing can jump within the page and also outside of the page to the remainder of the 64K logical space. Special instructions, particularly lcall, ljp, and lret, are used to access code outside of the 8K window. When one of these transfer-of-control instructions is executed, both the address and the view through the 8K window change, allowing transfer to any instruction in the 1M physical memory space. The 8-bit XPC register controls which of two consecutive 4K pages aligns with the 8K window (there are 256 pages). The 16-bit PC controls the address of the instruction, usually in the region 0xE000 to 0xFFFF. The advantage of paged access is that most instructions continue to use 16-bit addressing. Only when a page change is needed does a 20-bit transfer of control need to be made.

As the compiler compiles code in the extended code window, it checks at opportune times to see if the code has passed the midpoint of the window or 0xF000. When the code passes 0xF000, the compiler slides the window down by 4K so that the code at 0xF000+x becomes resident at 0xE000+x. This automatic paging results in the code being divided into segments that are typically 4K long, but which can be very short or as long as 8K. Transfer of control within each segment can be accomplished by 16-bit addressing. Between segments, 20-bit addressing is required.


Rabbit 2000
Designer's Handbook
<< Previous | Index | Next>> rabbit.com