Embedded Design Handbook

ID 683689
Date 8/28/2023
Public
Document Table of Contents

4.2.2.5.2. Recommended Architecture Practice

Many of the hardware and software coherency issues that arise during the creation of the application software are problems of misplaced peripheral addresses. Because of the flexibility provided by Platform Designer, almost any peripheral in the system can be assigned an arbitrary address, or have its address modified during system creation. Implement the following practices to prevent this type of coherency issue during the creation of your software application:

  • Peripheral and Memory Addressing—The Nios® II Software Build Tools automatically generate a system header file, system.h, that defines a set of #define symbols for every peripheral in the system. These definitions specify the peripheral name, base address location, and address span. If the Memory Management Unit (MMU) is enabled in your Nios® II system, verify that the address span for all peripherals is located in direct-mapped memory, outside the memory address range managed by the MMU.

    To protect against coherency issues, access all system peripherals and memory components with their system.h name and address span symbols. This method guarantees successful peripheral register access even after a peripheral's addressable location changes.

    For example, if your system includes a UART peripheral named UART1, located at address 0x1000, access the UART1 registers using the system.h address symbol (iowr_32(UART1_BASE, 0x0, 0x10101010)) rather than using its address (iowr_32(0x1000, 0x0, 0x10101010)).

  • Checking peripheral values with the preprocessor—If you work in a large team environment, and your software has a dependency on a particular hardware address, you can create a set of C preprocessor #ifdef statements that validate the hardware during the software compilation process. These #ifdef statements validate the #define values in the system.h file for each peripheral.

    For example, for the peripheral UART1, assume the #define values in system.h appear as follows:

    #define UART1_NAME "/dev/uart1"
    #define UART1_BASE 0x1000
    #define UART1_SPAN 32
    #define UART1_IRQ 6
    . . .

    In your C/C++ source files, add a preprocessor macro to verify that your expected peripheral settings remain unchanged in the hardware configuration. For example, the following code checks that the base address of UART1 remains at the expected value:

    #if (UART1_BASE != 0x1000)
    #error UART should be at 0x1000, but it is not
    #endif
  • Ensuring coherency with the System ID core—Use the System ID core. The System ID core is an Platform Designer peripheral that provides a unique identifier for a generated hardware system. This identifier is stored in a hardware register readable by the Nios® II processor. This unique identifier is also stored in the .sopcinfo file, which is then used to generate the BSP project for the system. You can use the system ID core to ensure coherency between the hardware and software by either of the following methods:
    • The first method is optionally implemented during system software development, when the Executable and Linking Format (.elf) file is downloaded to the Nios® II target. During the software download process, the value of the system ID core is checked against the value present in the BSP library file. If the two values do not match, this condition is reported. If you know that the system ID difference is not relevant, the system ID check can be overridden to force a download. Use this override with extreme caution, because a mismatch between hardware and software can lead you to waste time trying to resolve nonexistent bugs.
    • The second method for using the system ID peripheral is useful in systems that do not have a Nios® II debug port, or in situations in which running the Nios® II software download utilities is not practical. In this method you use the C function alt_avalon_sysid_test(). This function reports whether the hardware and software system IDs match.

    For more information about the System ID core, refer to the System ID Core chapter of the Embedded Peripherals IP User Guide.