Keil Logo


Information in this article applies to:

  • C51 Version 6.20
  • C51 Version 7.07 and later


How can I generate absolute memory accesses to the far memory type in Dallas 390 Contiguous Mode? The following program should access the memory byte at 0x12000, but it does not work.

unsigned char far *p;

void test (void)  {
  p = 0x12000;
  *p = 0x5A;        // does NOT write 0x5A to 0x12000


Absolute memory accesses to the far memory type on the Dallas 390 in contiguous mode can be performed by far pointers, by macros, or with the _at_ keyword. There are certain restrictions with each method.

Far memory is addressed using 3-byte generic pointers. Far and const far memory types are limited to 64KB to 8MB (0x010000 to 0x7F0000) address space. This memory space restriction allows more compact code and avoids using 4-bytes to address memory locations.

Regular Generic pointers use an uppermost (4th) byte called the Memory Type Byte. For the Dallas 400 the memory type byte values are:

  • 0x01 - 0x7F XDATA Memory (X:0 - X:0x7EFFFF)
  • 0x80 - Unused
  • 0x81 - 0xFF CODE Memory (C:0 - C:0x7EFFFF)

Pointer arithmetic for far objects is performed using 16-bit math operations by default. The upper byte of the complete 24-bit address is unchanged even if the operation's result is larger than 0xFFFF. Use long types or cast constants to long types in pointer manipulations to create 24-bit math code.

Absolute memory locations in extended (far) memory spaces can be accessed with the macros (FVAR, FCVAR, FARRAY, FCARRAY) defined in ABSACC.H. These macros are explained in detail in the Cx51 Compiler User's Guide, Chapter 8, Absolute Memory Access Macros. Using these macros give the correct results. For example:

#include <absacc.h>

unsigned char far *p;

void test (void)  {
  p = &FVAR(unsigned char, 0x12000);
  *p = 0x5A;        // writes 0x5A to 0x12000

In C51 Version 7.07 or higher it is even possible to use the _at_ keyword for locating absolute memory. For example:

unsigned char far IO_PORT        _at_ 0xC00000;
unsigned char far my_array[0x10] _at_ 0x400000;

unsigned char c;

void test (void)  {
  c = IO_PORT;
  my_array[5] = 0x55;
  my_array[c] = 1;

Far memory access above the memory range 0x7F0000 is more restricted. Only scalar variables (which have a fixed memory address) can be used to access memory above 0x7F0000 and are defined with the _at_ in the complete 16MB address space.

Pointer access is restricted to the Far and const far address space (0x010000 to 0x7F0000). Arrays must be located below 0x7F0000 when using the _at_ keyword. The Compiler uses pointer arithmetic for indirect access for memory above 0x7F0000.

As long as you access arrays directly in your C source (without using pointer constructs), you may bypass the 0x7F0000 limitation using the an Assembler Source file that defines the absolute memory location as shown in the following example:

Assembler Source File:


CAN_REG XDATA 0xFFDB00    ; absolute location of the CAN register

C Source File:

extern unsigned char xdata CAN_REG[256];

void main (void)  {
  unsigned char i;

  for (i = 0; i < 100; i++)  {
    CAN_REG[i] = 0;

Note: This trick works only when there are no pointer accesses to the array.




The following Discussion Forum threads may provide information related to this topic.

Last Reviewed: Monday, July 25, 2005

Did this article provide the answer you needed?
Not Sure
  Arm logo
Important information

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies.

Change Settings

Privacy Policy Update

Arm’s Privacy Policy has been updated. By continuing to use our site, you consent to Arm’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.