Dunfield Development Services Inc.
APPLICATION NOTE
Home
Products
Ordering & Status
Free Download Files
Links
Notices
Contact Us

 

Dunfield Development Services Inc.
Customer Support -- Application Note #0007

MICRO-C
Skipping a reserved area of memory

Applies to: [Micro-C Compiler ]
Last updated: Sunday May 04, 2003 .
Application Note Index

Back ] Next ]

PROCEDURE

Occasionally, there is a need to "skip" an area of memory within a MICRO-C program. Typically, this results from a hardware design which places a device register or special memory type (EEPROM etc.) somewhere in the middle of a larger memory block. An example might be a system with RAM from $0000-$7FFF, and ROM from $8000-$FFFF, with EEPROM located at $B600- $B7FF (replacing the ROM at that location). This can cause problem with MICRO-C, because it does not have a means of automatically skipping the special section of memory within the larger block.

There is no automatic way to skip a block of memory with MICRO-C. This design decision is due mainly to the C compiler not knowing exactly how large a given section of code is (it outputs assembly language), and the fact that certain blocks of code cannot be split without modification (for example, short jumps may go out of range).

The easiest solution would be to redesign the hardware to place the special block of memory at a more reasonable location. This may be as easy as re- programming CPU device configuration or memory mapping registers. In the example, if the EEPROM were moved to $8000, there would be no problems, as the remainder of the ROM would be continuously addressable from $8100-$FFFF.

Assuming this is unfeasable, here is a simple method of manually splitting the compiler output code into two (or more) blocks.

First, compile your program once with the -L option, look at the generated .LST file to see which function enters the special memory block ($B600 in the example), and then insert the following lines in the source code, immediately AFTER the PRECEEDING function:

asm {
?SPLIT EQU * Label so that we can check split address
ORG $B800 Reposition to skip the EEPROM area
}

If necessary, you may find that by rearranging large<>small functions, you can get the position of this code block fairly close to $B600 without going over it. If you are really tight on memory, and have to split the code in the middle of a function, your only recourse is to compile with -X, and edit the resulting assembly file to insert the ORG (and fix any short jumps etc.) at the exact point where the code reaches $B600.

The ?SPLIT symbol is to allow you to easily check your address to make sure that it hasn't exceeded $B600. To automate this, create a small 1 line file called SPLIT.SYM, which contains only "?SPLIT" (no spaces). Then, you may wish to use a batch file to run the compiler and produce a listing, and use the PARSESYM utility (from the support package installed from \SUPPORT on your CD ROM) to display the value of ?SPLIT from the LISTING:

CCxx program -L <your usual options>
parsesym program.LST CON S=SPLIT.SYM -V

This will display "?SPLIT <address>" at the end of the compile.

It is important to understand that this inline "ORG" statement will be placed in the output file immediately after the previous item in the source file. In particular, the compiler may output functions (code) and initialized variables (data) in different linker segments which end up at different memory addresses. The compiler will remain in whatever segment it last output into until it finds a source item which requires it to switch to a new segment. Since "asm" does not cause a segment switch, it will be output in the last active segment. Thus, you must insure that you place this line immediately AFTER an item of the memory type that you want to split (code or data).

It is not possible to split the use of uninitialized static data memory due to the compilers use of the $DD: directive to the linker instead of actually generating .ASM code to create these variables. Also note that the library for most CPU's includes a facility to split the use of initialized and un-initialized data (see "middle" file under SLINK, and READ.ME in LIBxx sub- directory). If you must split uninitialized data memory, you may be able to do so by inserting large "dummy" variables to take up the unusable range of addresses. You may also be able to move several larger items to another block. See the application note on "Accessing fixed memory locations."

If you split initialized data memory, you must be careful with those CPUs having memory models which copy the initialized data from ROM to RAM. The split memory will not occur in both segments, and you will have to manually edit the .ASM output file to correct this before assembling.

 

 

Back ] Next ]

© 2008 Dunfield Development Services Inc.     View our Privacy Statement
Refunds given at the discretion of management.
 Last Updated:  Tuesday, March 18, 2008