Aerospace



Citadel Forums

Home

Company Information

Information Request

Linux How-to Guides

ADSP 21xx
Digital Signal Processing
Tutorials

SW Utilities

On-line Order Form


bonk

Have you found this site useful? Did we save you time? Did we cure your head-ache? Is your hair growing back now?

Please make a donation to help with maintenance.


Objective Real-Time Software on the ADSP21XX

Memory Overlays on the ADSP 218X

General

The ADSP 218X offers a program and data memory overlay feature, which is used to double the addressable memory space. These extra memory spaces are controlled by the PMS (probably a very apt name for it...) and A13 lines, together with the PMOVLAY and DMOVLAY registers.

The PM overlays can be swapped for the upper half (above address 2000H) of internal PM and the DM overlays can be swapped for the lower half (below address 2000H) of internal DM. This ensures that the interrupt vector table in lower PM and the memory mapped registers at the top of DM will always be directly available.

PM overlay zero is the on chip upper PM, while overlays one and two are off chip RAM. All three overlays start at address 2000H. DM overlay zero is the on chip lower DM and overlays one and two are off chip RAM. All three DM overlays start at address 0000H.

This extra memory comes with a price attached - there is no free lunch. The cost being increased complexity to call procedures located in overlays. The complexity is further compounded by the available tools, which do not directly cater for overlay linking. This chapter outlines an approach that will minimize the trauma associated with overlay systems and which will allow the various overlays to be linked independently.

Caveats

The BDMA only works between on chip memory and external byte memory, independent of the overlay settings. To load the overlay RAM from EPROM, one needs to copy data with BDMA from EPROM to lower PM, then use a copy loop to copy the data from lower PM to the PM overlays. DM usually don't need much initialization and is best initialized at runtime.

Note that interrupts should only be enabled once the overlay memory is loaded, since it may disrupt the loading process.

Also bear in mind that the speed of the off chip overlay RAM may be slower than the on chip RAM and may require wait states to be inserted. If so, it would be prudent to keep time critical routines in on-chip memory.

Calls Near and Far

Function calls are divided into two types: near calls and far calls. Near calls work as normal. Far calls are calls requiring an overlay switch. In order to keep one's sanity, it would be wise to use an overlay switching function for far function calls and the code should be structured such that a minimal amount of overlay switching would result.

In a real-time system, code is usually divided into tasks. Multi tasking is controlled from a scheduler, which could be a compact round-robin loop. A simple overlay management structure could be achieved by ensuring that a task will fit completely on a single overlay. This simplification is very significant and means that the only far calls would be the small number of calls from the scheduler to the task synchronization modules, while all calls inside a task would be ordinary near calls. This minimizes the complexity and the speed penalty.

Returns Near and Far

The trouble with a far call is that the call itself is only one part of the problem. The flip side concerns the far return from the far call.

If the code is structured on a multi tasking basis as suggested above, then the whole scheduler and all interrupt service routines would reside in lower PM and far calls would only be executed in one direction: from the fixed lower PM to overlay PM. The far return problem would then disappear. In this case, a procedure in overlay memory would be unaware that it is the subject of a far call and can perform a regular return. This is extremely important and ensures that any procedure can be either near or far called without any problems.

PM Overlays

A task with both near and far procedures in multiple overlays would be very hard to manage and is not recommended, unless you are a masochist! If a task won't fit in a single overlay, then it is clearly too big and should be subdivided.

All common code such as the Basic Input Output System (BIOS), should be located in lower PM to ensure universal access from any overlay. This also applies to the interrupt handlers. In order to keep things simple, it would be best to locate the ISRs in lower PM and keep their data buffers in upper DM, so that they will remain static and won't require overlay switching. That would also allow any task to access its ISR data buffers with simple near data accesses to fixed upper DM.

DM Overlays

This brings us to the next problem, that of DM overlays. Again, it would be prudent to find a simple solution, things being complicated enough as they are. One way would be to tie the DM and PM overlays together and switch them at the same time. Each task can then read and write its data as normal, without having to worry about a near and far data problem.

Linking it Together

Great, but how on earth does one build such a system? With the available tools, the only way is to link each segment as a standalone application. The overlay task entry points and overlay numbers should be fixed by using a constant lookup table in the scheduler module. Each overlay segment should start with a vector table to ensure that the various lookup tables in other overlay segments would not need to change whenever the code in a specific segment is changed.

Each overlay would correspond to an EPROM BDMA access segment and can thus be linked and located on its own and downloaded as one block.

The BDMA startup and overlay copy code could be duplicated in all overlay segments. That way, each BDMA loader could be tailored to load the whole segment, then transfer control to the loader of the next segment once it has completed loading and finally overwrite itself with the final version of the lower PM code in a recursive fashion. All versions of the loader would then be identical, but for the EPROM BDMA sector numbers, which will keep things simple. Four BDMA load cycles would be required to load the whole chip and 2 sets of overlays.

Call Vector Tables

Crucial to an overlay system, is the use of indirect call vector tables. This isolates the various overlays from each other and ensures that one needs to set up the far call lookup tables once only. This is a classic example where the basic engineering tenets of information hiding and minimum coupling have to be adhered to, to keep the system manageble. Each overlay should form a cleanly defined object with the tasks as sub objects.

Consider a system with two tasks in overlay one. The task synchronization modules are called ser_tsm and aud_tsm and the scheduler in lower PM needs to call these task synchronization modules.

Define a pair of entry points at fixed addresses at the start of overlay one as shown below, to form a cleanly defined overlay object, very much like the interrupt vector table at the bottom of PM:

Example1. Overlay Vectors
.MODULE/RAM/ABS=0x2000 OVL1;

ser_tsm_entry:          /* fixed address 0x2000 */
   call ser_tsm;
   rts;

aud_tsm_entry:          /* fixed address 0x2002 */
   call aud_tsm;
   rts;

ser_tsm:
   MAC_ENTER

   /* Serial Port Task code goes here */

   MAC_EXIT
   rts;

aud_tsm:
   MAC_ENTER

   /* Audio Task code goes here */

   MAC_EXIT
   rts;

.ENDMOD;

The labels ser_tsm_entry and aud_tsm_entry, will always be in a fixed position at addresses 0x2000 and 0x2002 respectively, while the actual task synchronization modules ser_tsm and aud_tsm can be moved around by the linker as the code grows or changes. The scheduler which is in lower PM, needs to perform far calls to the fixed addresses only. To do this, the scheduler needs to know the overlay number and the fixed address in overlay PM. Since this information won't ever change thanks to the above trick, it can be preset in a two dimensional constant lookup table.

Here is an example far call object definition:

Example 2. Far Call Lookup Table
#define SHD_SER_TSM_ADDR        0x2000
#define SHD_AUD_TSM_ADDR        0x2002
#define SHD_OVL1                0x0001
#define SHD_FAR_CALL_SIZE       0x0004
#define SHD_CALL_SER_TSM        0x0000
#define SHD_CALL_AUD_TSM        0x0002

.VAR/DM/RAM/SEG=INT_PM
   SHD_FAR_CALL_TBL[SHD_FAR_CALL_SIZE];

.INIT SHD_FAR_CALL_TBL: SHD_SER_TSM_ADDR, SHD_OVL1,
                        SHD_AUD_TSM_ADDR, SHD_OVL1;

Finally, we get to the far call itself. This is performed with an indirect call, using the TOPPCSTACK instruction and a RTS, to load the program counter and cause an indirect call, as shown in the following example:

Example 3. Register Indirect Far Call
/****************************************************************************
* Name:          shd_far_call
* Description:   Far call procedure, for calls from lower PM to overlay PM
* Constraints:   ar = Procedure index 
*                switch both PM and DM overlays
*
* Example:       ar = SHD_CALL_SER_TSM;
*                call shd_far_call;
****************************************************************************/
shd_far_call:
   MAC_ENTER

   m4 = ar;                     /* index into the call lookup table */
   i4 = ^SHD_FAR_CALL_TBL;   
   modify(i4, m4);              

   m4 = 1;      
   ax1 = pm(i4, m4);            /* get the address */
   i5 = ar;
   ar = pm(i4, m4);             /* get the overlay number */

   ax0 = PMOVLAY;               /* save and set the overlay control bits */
   ay0 = DMOVLAY;
   PMOVLAY = ar;
   DMOVLAY = ar;

   TOPPCSTACK = ax1;            /* indirect call to a far procedure */
   nop;                         /* one cycle delay */
   rts;                         /* the RTS load the PC and cause a procedure call */
      
   PMOVLAY = ax0;               /* restore the overlay control bits */
   DMOVLAY = ay0;

   MAC_EXIT
   rts;

As suggested above, BIOS functions should reside in lower PM. This would allow any overlay to call a BIOS function with a near call. The only problem is that the overlays are independently linked and thus are unaware of the actual BIOS procedure addresses. This problem should be handled in the same way as the above far call example, except that the overlay switching would not be required and the lookup table would therefore be a one dimensional table.

Example 4. BIOS Near Call
/****************************************************************************
* Name:          bios_call
* Description:   Near BIOS call procedure, for calls from overlay PM to lower PM
* Constraints:   ar = Procedure index 
*                Each overlay would need a copy of this procedure and its
*                lookup table
*
* Example:       ar = BIOS_GET_CHAR;
*                call bios_call;
****************************************************************************/
bios_call:
   MAC_ENTER

   m4 = ar;                     /* index into the call lookup table */
   i4 = ^BIOS_CALL_TBL;   
   modify(i4, m4);              

   ar = pm(i4, m4);             /* get the address */
   TOPPCSTACK = ar;             /* put the address on the PC stack */
   nop;                         /* one cycle delay */
   rts;                         /* perform the indirect call using RTS */

   MAC_EXIT
   rts;

Debugging

The debugger discussed elsewhere in this book, would require some modifications to allow it to work in an overlay system. It would need to be aware of the overlay in which a breakpoint has to be set or cleared. Furthermore, the calls to the breakpoint handlers would require indirection, similar to a BIOS call.

Clearly, the development of an overlay system should not be attempted by the faint hearted!



Copyright © 1995-2010, Aerospace Software Ltd., GPL.