Platform HAL Porting

This is the type of port that takes the least effort. It basically consists of describing the platform (board) for the HAL: memory layout, early platform initialization, interrupt controllers, and a simple serial device driver.

Doing a platform port requires a preexisting architecture and possibly a variant HAL port.

HAL Platform Porting Process

Brief overview

The easiest way to make a new platform HAL is simply to copy an existing platform HAL of the same architecture/variant and change all the files to match the new one. In case this is the first platform for the architecture/variant, a platform HAL from another architecture should be used as a template.

The best way to start a platform port is to concentrate on getting RedBoot to run. RedBoot is a simpler environment than full eCos, it does not use interrupts or threads, but covers most of the basic startup requirements.

RedBoot normally runs out of FLASH or ROM and provides program loading and debugging facilities. This allows further HAL development to happen using RAM startup configurations, which is desirable for the simple reason that downloading an image which you need to test is often many times faster than either updating a flash part, or indeed, erasing and reprogramming an EPROM.

There are two approaches to getting to this first goal:

  1. The board is equipped with a ROM monitor which allows "load and go" of ELF, binary, S-record or some other image type which can be created using objcopy. This allows you to develop RedBoot by downloading and running the code (saving time).

    When the stub is running it is a good idea to examine the various hardware registers to help you write the platform initialization code.

    Then you may have to fiddle a bit going through step two (getting it to run from ROM startup). If at all possible, preserve the original ROM monitor so you can revert to it if necessary.

  2. The board has no ROM monitor. You need to get the platform initialization and stub working by repeatedly making changes, updating flash or EPROM and testing the changes. If you are lucky, you have a JTAG or similar CPU debugger to help you. If not, you will probably learn to appreciate LEDs. This approach may also be needed during the initial phase of moving RedBoot from RAM startup to ROM, since it is very unlikely to work first time.

Step-by-step

Given that no two platforms are exactly the same, you may have to deviate from the below. Also, you should expect a fair amount of fiddling - things almost never go right the first time. See the hints section below for some suggestions that might help debugging.

The description below is based on the HAL layout used in the MIPS, PC and MN10300 HALs. Eventually all HALs should be converted to look like these - but in a transition period there will be other HALs which look substantially different. Please try to adhere to the following as much is possible without causing yourself too much grief integrating with a HAL which does not follow this layout.

Minimal requirements

These are the changes you must make before you attempt to build RedBoot. You are advised to read all the sources though.

  1. Copy an existing platform HAL from the same or another architecture. Rename the files as necessary to follow the standard: CDL and MLT related files should contain the <arch>_<variant>_<platform> triplet.

  2. Adjust CDL options. Primarily option naming, real-time clock/counter, and CYGHWR_MEMORY_LAYOUT variables, but also other options may need editing. Look through the architecture/variant CDL files to see if there are any requirements/features which where not used on the platform you copied. If so, add appropriate ones. See the Section called HAL Platform CDL for more details.

  3. Add the necessary packages and target descriptions to the top-level ecos.db file. See the Section called eCos Database. Initially, the target entry should only contain the HAL packages. Other hardware support packages will be added later.

  4. Adjust the MLT files in include/pkgconf to match the memory layout on the platform. For initial testing it should be enough to just hand edit .h and .ldi files, but eventually you should generate all files using the memory layout editor in the configuration tool. See the Section called Platform Memory Layout for more details.

  5. Edit the misc/redboot_<STARTUP>.ecm for the startup type you have chosen to begin with. Rename any platform specific options and remove any that do not apply. In the cdl_configuration section, comment out any extra packages that are added, particularly packages such as CYGPKG_IO_FLASH and CYGPKG_IO_ETH_DRIVERS. These are not needed for initial porting and will be added back later.

  6. If the default IO macros are not correct, override them in plf_io.h. This may be necessary if the platform uses a different endianness from the default for the CPU.

  7. Leave out/comment out code that enables caches and/or MMU if possible. Execution speed will not be a concern until the port is feature complete.

  8. Implement a simple serial driver (polled mode only). Make sure the initialization function properly hooks the procedures up in the virtual vector IO channel tables. RedBoot will call the serial driver via these tables.

    By copying an existing platform HAL most of this code will be already done, and will only need the platform specific hardware access code to be written.

  9. Adjust/implement necessary platform initialization. This can be found in platform.inc and platform.S files (ARM: hal_platform_setup.h and <platform>_misc.c, PowerPC: <platform>.S). This step can be postponed if you are doing a RAM startup RedBoot first and the existing ROM monitor handles board initialization.

  10. Define HAL_STUB_PLATFORM_RESET (optionally empty) and HAL_STUB_PLATFORM_RESET_ENTRY so that RedBoot can reset-on-detach - this is very handy, often removing the need for physically resetting the board between downloads.

You should now be able to build RedBoot. For ROM startup:

% ecosconfig new <target_name> redboot
% ecosconfig import $(ECOS_REPOSITORY)/hal/<architecture>/<platform>/<version>/misc/redboot_ROM.ecm
% ecosconfig tree
% make

You may have to make further changes than suggested above to get the make command to succeed. But when it does, you should find a RedBoot image in install/bin. To program this image into flash or EPROM, you may need to convert to some other file type, and possibly adjust the start address. When you have the correct objcopy command to do this, add it to the CYGBLD_BUILD_GDB_STUBS custom build rule in the platform CDL file.

Having updated the flash/EPROM on the board, you should see output on the serial port looking like this when powering on the board:

RedBoot(tm) bootstrap and debug environment [ROMRAM]
Non-certified release, version UNKNOWN - built 15:42:24, Mar 14 2002

Platform: <PLATFORM> (<ARCHITECTURE> <VARIANT>)
Copyright (C) 2000, 2001, 2002, Red Hat, Inc.

RAM: 0x00000000-0x01000000, 0x000293e8-0x00ed1000 available
FLASH: 0x24000000 - 0x26000000, 256 blocks of 0x00020000 bytes each.
RedBoot> 

If you do not see this output, you need to go through all your changes and figure out what's wrong. If there's a user programmable LED or LCD on the board it may help you figure out how far RedBoot gets before it hangs. Unfortunately there's no good way to describe what to do in this situation - other than that you have to play with the code and the board.

Adding features

Now you should have a basic RedBoot running on the board. This means you have a the correct board initialization and a working serial driver. It's time to flesh out the remaining HAL features.

  1. Reset. As mentioned above it is desirable to get the board to reset when GDB disconnects. When GDB disconnects it sends RedBoot a kill-packet, and RedBoot first calls HAL_STUB_PLATFORM_RESET(), attempting to perform a software-invoked reset. Most embedded CPUs/boards have a watchdog which is capable of triggering a reset. If your target does not have a watchdog, leave HAL_STUB_PLATFORM_RESET() empty and rely on the fallback approach.

    If HAL_STUB_PLATFORM_RESET() did not cause a reset, RedBoot will jump to HAL_STUB_PLATFORM_RESET_ENTRY - this should be the address where the CPU will start execution after a reset. Re-initializing the board and drivers will usually be good enough to make a hardware reset unnecessary.

    After the reset caused by the kill-packet, the target will be ready for GDB to connect again. During a days work, this will save you from pressing the reset button many times.

    Note that it is possible to disconnect from the board without causing it to reset by using the GDB command "detach".

  2. Single-stepping is necessary for both instruction-level debugging and for breakpoint support. Single-stepping support should already be in place as part of the architecture/variant HAL, but you want to give it a quick test since you will come to rely on it.

  3. Real-time clock interrupts drive the eCos scheduler clock. Many embedded CPUs have an on-core timer (e.g. SH) or decrementer (e.g. MIPS, PPC) that can be used, and in this case it will already be supported by the architecture/variant HAL. You only have to calculate and enter the proper CYGNUM_HAL_RTC_CONSTANTS definitions in the platform CDL file.

    On some targets it may be necessary to use a platform-specific timer source for driving the real-time clock. In this case you also have to enter the proper CDL definitions, but must also define suitable versions of the HAL_CLOCK_XXXX macros.

  4. Interrupt decoding usually differs between platforms because the number and type of devices on the board differ. In plf_intr.h (ARM: hal_platform_ints.h) you must either extend or replace the default vector definitions provided by the architecture or variant interrupt headers. You may also have to define HAL_INTERRUPT_XXXX control macros.

  5. Caching may also differ from architecture/variant definitions. This maybe just the cache sizes, but there can also be bigger differences for example if the platform supports 2nd level caches.

    When cache definitions are in place, enable the caches on startup. First verify that the system is stable for RAM startups, then build a new RedBoot and install it. This will test if caching, and in particular the cache sync/flush operations, also work for ROM startup.

  6. Asynchronous breakpoints allow you to stop application execution and enter the debugger. Asynchronous breakpoint details are described in .

You should now have a completed platform HAL port. Verify its stability and completeness by running all the eCos tests and fix any problems that show up (you have a working RedBoot now, remember! That means you can debug the code to see why it fails).

Given the many configuration options in eCos, there may be hidden bugs or missing features that do not show up even if you run all the tests successfully with a default configuration. A comprehensive test of the entire system will take many configuration permutations and many many thousands of tests executed.

Hints

  • JTAG or similar CPU debugging hardware can greatly reduce the time it takes to write a HAL port since you always have full visibility of what the CPU is doing.

  • LEDs can be your friends if you don't have a JTAG device. Especially in the start of the porting effort if you don't already have a working ROM monitor on the target. Then you have to get a basic RedBoot working while basically being blindfolded. The LED can make it little easier, as you'll be able to do limited tracking of program flow and behavior by switching the LED on and off. If the board has multiple LEDs you can show a number (using binary notation with the LEDs) and sprinkle code which sets different numbers throughout the code.

  • Debugging the interrupt processing is possible if you are careful with the way you program the very early interrupt entry handling. Write it so that as soon as possible in the interrupt path, taking a trap (exception) does not harm execution. See the SH vectors.S code for an example. Look for cyg_hal_default_interrupt_vsr and the label cyg_hal_default_interrupt_vsr_bp_safe, which marks the point after which traps/single-stepping is safe.

    Being able to display memory content, CPU registers, interrupt controller details at the time of an interrupt can save a lot of time.

  • Using assertions is a good idea. They can sometimes reveal subtle bugs or missing features long before you would otherwise have found them, let alone notice them.

    The default eCos configuration does not use assertions, so you have to enable them by switching on the option CYGPKG_INFRA_DEBUG in the infra package.

  • The idle loop can be used to help debug the system.

    Triggering clock from the idle loop is a neat trick for examining system behavior either before interrupts are fully working, or to speed up "the clock".

    Use the idle loop to monitor and/or print out variables or hardware registers.

  • hal_mk_defs is used in some of the HALs (ARM, SH) as a way to generate assembler symbol definitions from C header files without imposing an assembler/C syntax separation in the C header files.

HAL Platform CDL

The platform CDL both contains details necessary for the building of eCos, and platform-specific configuration options. For this reason the options differ between platforms, and the below is just a brief description of the most common options.

See Components Writers Guide for more details on CDL. Also have a quick look around in existing platform CDL files to get an idea of what is possible and how various configuration issues can be represented with CDL.

eCos Database

The eCos configuration system is made aware of a package by adding a package description in ecos.db. As an example we use the TX39/JMR3904 platform:

package CYGPKG_HAL_MIPS_TX39_JMR3904 {
	alias		{ "Toshiba JMR-TX3904 board" hal_tx39_jmr3904 tx39_jmr3904_hal }
	directory	hal/mips/jmr3904
	script		hal_mips_tx39_jmr3904.cdl
	hardware
	description "
           The JMR3904 HAL package should be used when targeting the
           actual hardware. The same package can also be used when
           running on the full simulator, since this provides an
           accurate simulation of the hardware including I/O devices.
           To use the simulator in this mode the command
           `target sim --board=jmr3904' should be used from inside gdb."
}

This contains the title and description presented in the Configuration Tool when the package is selected. It also specifies where in the tree the package files can be found (directory) and the name of the CDL file which contains the package details (script).

To be able to build and test a configuration for the new target, there also needs to be a target entry in the ecos.db file.

target jmr3904 {
        alias		{ "Toshiba JMR-TX3904 board" jmr tx39 }
	packages        { CYGPKG_HAL_MIPS
                          CYGPKG_HAL_MIPS_TX39
                          CYGPKG_HAL_MIPS_TX39_JMR3904
        }
        description "
           The jmr3904 target provides the packages needed to run
           eCos on a Toshiba JMR-TX3904 board. This target can also
           be used when running in the full simulator, since the simulator provides an
           accurate simulation of the hardware including I/O devices.
           To use the simulator in this mode the command
           `target sim --board=jmr3904' should be used from inside gdb."
}

The important part here is the packages section which defines the various hardware specific packages that contribute to support for this target. In this case the MIPS architecture package, the TX39 variant package, and the JMR-TX3904 platform packages are selected. Other packages, for serial drivers, ethernet drivers and FLASH memory drivers may also appear here.

CDL File Layout

All the platform options are contained in a CDL package named CYGPKG_HAL_<architecture>_<variant>_<platform>. They all share more or less the same cdl_package details:

cdl_package CYGPKG_HAL_MIPS_TX39_JMR3904 {
    display       "JMR3904 evaluation board"
    parent        CYGPKG_HAL_MIPS
    requires      CYGPKG_HAL_MIPS_TX39
    define_header hal_mips_tx39_jmr3904.h
    include_dir   cyg/hal
    description   "
           The JMR3904 HAL package should be used when targeting the
           actual hardware. The same package can also be used when
           running on the full simulator, since this provides an
           accurate simulation of the hardware including I/O devices.
           To use the simulator in this mode the command
           `target sim --board=jmr3904' should be used from inside gdb."

    compile       platform.S plf_misc.c plf_stub.c

    define_proc {
        puts $::cdl_system_header "#define CYGBLD_HAL_TARGET_H   <pkgconf/hal_mips_tx39.h>"
        puts $::cdl_system_header "#define CYGBLD_HAL_PLATFORM_H <pkgconf/hal_mips_tx39_jmr3904.h>"
    }

    ...
}

This specifies that the platform package should be parented under the MIPS packages, requires the TX39 variant HAL and all configuration settings should be saved in cyg/hal/hal_mips_tx39_jmt3904.h.

The compile line specifies which files should be built when this package is enabled, and the define_proc defines some macros that are used to access the variant or architecture (the _TARGET_ name is a bit of a misnomer) and platform configuration options.

Startup Type

eCos uses an option to select between a set of valid startup configurations. These are normally RAM, ROM and possibly ROMRAM. This setting is used to select which linker map to use (i.e., where to link eCos and the application in the memory space), and how the startup code should behave.

cdl_component CYG_HAL_STARTUP {
    display       "Startup type"
    flavor        data
    legal_values  {"RAM" "ROM"}
    default_value {"RAM"}
	no_define
	define -file system.h CYG_HAL_STARTUP
    description   "
       When targeting the JMR3904 board it is possible to build
       the system for either RAM bootstrap, ROM bootstrap, or STUB
       bootstrap. RAM bootstrap generally requires that the board
       is equipped with ROMs containing a suitable ROM monitor or
       equivalent software that allows GDB to download the eCos
       application on to the board. The ROM bootstrap typically
       requires that the eCos application be blown into EPROMs or
       equivalent technology."
}

The no_define and define pair is used to make the setting of this option appear in the file system.h instead of the default specified in the header.

Build options

A set of options under the components CYGBLD_GLOBAL_OPTIONS and CYGHWR_MEMORY_LAYOUT specify how eCos should be built: what tools and compiler options should be used, and which linker fragments should be used.


cdl_component CYGBLD_GLOBAL_OPTIONS {
    display "Global build options"
    flavor  none
    parent  CYGPKG_NONE
    description   "
	    Global build options including control over
	    compiler flags, linker flags and choice of toolchain."


    cdl_option CYGBLD_GLOBAL_COMMAND_PREFIX {
        display "Global command prefix"
        flavor  data
        no_define
        default_value { "mips-tx39-elf" }
        description "
            This option specifies the command prefix used when
            invoking the build tools."
    }

    cdl_option CYGBLD_GLOBAL_CFLAGS {
        display "Global compiler flags"
        flavor  data
        no_define
        default_value { "-Wall -Wpointer-arith -Wstrict-prototypes -Winline -Wundef -Woverloaded-virtual -g -O2 -ffunction-sections -fdata-sections -fno-rtti -fno-exceptions -fvtable-gc -finit-priority" }
        description   "
            This option controls the global compiler flags which
            are used to compile all packages by
            default. Individual packages may define
            options which override these global flags."
    }

    cdl_option CYGBLD_GLOBAL_LDFLAGS {
        display "Global linker flags"
        flavor  data
        no_define
        default_value { "-g -nostdlib -Wl,--gc-sections -Wl,-static" }
        description   "
            This option controls the global linker flags. Individual
            packages may define options which override these global flags."
    }
}

cdl_component CYGHWR_MEMORY_LAYOUT {
    display "Memory layout"
    flavor data
    no_define
    calculated { CYG_HAL_STARTUP == "RAM" ? "mips_tx39_jmr3904_ram" : \
                                            "mips_tx39_jmr3904_rom" }

    cdl_option CYGHWR_MEMORY_LAYOUT_LDI {
        display "Memory layout linker script fragment"
        flavor data
        no_define
        define -file system.h CYGHWR_MEMORY_LAYOUT_LDI
        calculated { CYG_HAL_STARTUP == "RAM" ? "<pkgconf/mlt_mips_tx39_jmr3904_ram.ldi>" : \
                                                "<pkgconf/mlt_mips_tx39_jmr3904_rom.ldi>" }
    }

    cdl_option CYGHWR_MEMORY_LAYOUT_H {
        display "Memory layout header file"
        flavor data
        no_define
        define -file system.h CYGHWR_MEMORY_LAYOUT_H
        calculated { CYG_HAL_STARTUP == "RAM" ? "<pkgconf/mlt_mips_tx39_jmr3904_ram.h>" : \
                                                "<pkgconf/mlt_mips_tx39_jmr3904_rom.h>" }
    }
}

Common Target Options

All platforms also specify real-time clock details:

# Real-time clock/counter specifics
cdl_component CYGNUM_HAL_RTC_CONSTANTS {
    display       "Real-time clock constants."
    flavor        none

    cdl_option CYGNUM_HAL_RTC_NUMERATOR {
        display       "Real-time clock numerator"
        flavor        data
        calculated    1000000000
    }
    cdl_option CYGNUM_HAL_RTC_DENOMINATOR {
        display       "Real-time clock denominator"
        flavor        data
        calculated    100
    }
    # Isn't a nice way to handle freq requirement!
    cdl_option CYGNUM_HAL_RTC_PERIOD {
        display       "Real-time clock period"
        flavor        data
        legal_values  { 15360 20736 }
        calculated     { CYGHWR_HAL_MIPS_CPU_FREQ == 50 ? 15360 : \
                         CYGHWR_HAL_MIPS_CPU_FREQ == 66 ? 20736 : 0 }
    }
}

The NUMERATOR divided by the DENOMINATOR gives the number of nanoseconds per tick. The PERIOD is the divider to be programmed into a hardware timer that is driven from an appropriate hardware clock, such that the timer overflows once per tick (normally generating a CPU interrupt to mark the end of a tick). The tick default rate is typically 100Hz.

Platforms that make use of the virtual vector ROM calling interface (see the Section called Virtual Vectors (eCos/ROM Monitor Calling Interface)) will also specify details necessary to define configuration channels (these options are from the SH/EDK7707 HAL) :

cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS {
    display      "Number of communication channels on the board"
    flavor       data
    calculated   1
}

cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL {
    display          "Debug serial port"
    flavor data
    legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
    default_value    0
    description      "
       The EDK/7708 board has only one serial port. This option
       chooses which port will be used to connect to a host
       running GDB."
}

cdl_option CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL {
    display          "Diagnostic serial port"
    flavor data
    legal_values     0 to CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS-1
    default_value    0
    description      "
       The EDK/7708 board has only one serial port.  This option
       chooses which port will be used for diagnostic output."
}

The platform usually also specify an option controlling the ability to co-exist with a ROM monitor:

cdl_option CYGSEM_HAL_USE_ROM_MONITOR {
    display       "Work with a ROM monitor"
    flavor        booldata
    legal_values  { "Generic" "CygMon" "GDB_stubs" }
    default_value { CYG_HAL_STARTUP == "RAM" ? "CygMon" : 0 }
    parent        CYGPKG_HAL_ROM_MONITOR
    requires      { CYG_HAL_STARTUP == "RAM" }
    description   "
        Support can be enabled for three different varieties of ROM monitor.
        This support changes various eCos semantics such as the encoding
        of diagnostic output, or the overriding of hardware interrupt
        vectors.
        Firstly there is \"Generic\" support which prevents the HAL
        from overriding the hardware vectors that it does not use, to
        instead allow an installed ROM monitor to handle them. This is
        the most basic support which is likely to be common to most
        implementations of ROM monitor.
        \"CygMon\" provides support for the Cygnus ROM Monitor.
        And finally, \"GDB_stubs\" provides support when GDB stubs are
        included in the ROM monitor or boot ROM."
}

Or the ability to be configured as a ROM monitor:

cdl_option CYGSEM_HAL_ROM_MONITOR {
    display       "Behave as a ROM monitor"
    flavor        bool
    default_value 0
    parent        CYGPKG_HAL_ROM_MONITOR
    requires      { CYG_HAL_STARTUP == "ROM" }
    description   "
        Enable this option if this program is to be used as a ROM monitor,
        i.e. applications will be loaded into RAM on the board, and this
        ROM monitor may process exceptions or interrupts generated from the
        application. This enables features such as utilizing a separate
        interrupt stack when exceptions are generated."
}

The latter option is accompanied by a special build rule that extends the generic ROM monitor build rule in the common HAL:

cdl_option CYGBLD_BUILD_GDB_STUBS {
    display "Build GDB stub ROM image"
    default_value 0
    requires { CYG_HAL_STARTUP == "ROM" }
    requires CYGSEM_HAL_ROM_MONITOR
    requires CYGBLD_BUILD_COMMON_GDB_STUBS
    requires CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
    requires ! CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
    requires ! CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
    requires ! CYGDBG_HAL_COMMON_INTERRUPTS_SAVE_MINIMUM_CONTEXT
    requires ! CYGDBG_HAL_COMMON_CONTEXT_SAVE_MINIMUM
    no_define
    description "
        This option enables the building of the GDB stubs for the
        board. The common HAL controls takes care of most of the
        build process, but the final conversion from ELF image to
        binary data is handled by the platform CDL, allowing
        relocation of the data if necessary."

    make -priority 320 {
        <PREFIX>/bin/gdb_module.bin : <PREFIX>/bin/gdb_module.img
        $(OBJCOPY) -O binary $< $@
    }
}

Most platforms support RedBoot, and some options are needed to configure for RedBoot.

    cdl_component CYGPKG_REDBOOT_HAL_OPTIONS {
        display       "Redboot HAL options"
        flavor        none
        no_define
        parent        CYGPKG_REDBOOT
        active_if     CYGPKG_REDBOOT
        description   "
            This option lists the target's requirements for a valid Redboot
            configuration."
    
        cdl_option CYGBLD_BUILD_REDBOOT_BIN {
            display       "Build Redboot ROM binary image"
            active_if     CYGBLD_BUILD_REDBOOT
            default_value 1
            no_define
            description "This option enables the conversion of the Redboot ELF
                         image to a binary image suitable for ROM programming."
    
            make -priority 325 {
                <PREFIX>/bin/redboot.bin : <PREFIX>/bin/redboot.elf
                $(OBJCOPY) --strip-debug $< $(@:.bin=.img) 
                $(OBJCOPY) -O srec $< $(@:.bin=.srec)
                $(OBJCOPY) -O binary $< $@
            }
        }
    }

The important part here is the make command in the CYGBLD_BUILD_REDBOOT_BIN option which emits makefile commands to translate the .elf file generated by the link phase into both a binary file and an S-Record file. If a different format is required by a PROM programmer or ROM monitor, then different output formats would need to be generated here.

Platform Memory Layout

The platform memory layout is defined using the Memory Configuration Window in the Configuration Tool.

Note: If you do not have access to a Windows machine, you can hand edit the .h and .ldi files to match the properties of your platform. If you want to contribute your port back to the eCos community, ask someone on the list to make proper memory map files for you.

Layout Files

The memory configuration details are saved in three files:

.mlt

This is the Configuration Tool save-file. It is only used by the Configuration Tool.

.ldi

This is the linker script fragment. It defines the memory and location of sections by way of macros defined in the architecture or variant linker script.

.h

This file describes some of the memory region details as C macros, allowing eCos or the application adapt the memory layout of a specific configuration.

These three files are generated for each startup-type, since the memory details usually differ.

Reserved Regions

Some areas of the memory space are reserved for specific purposes, making room for exception vectors and various tables. RAM startup configurations also need to reserve some space at the bottom of the memory map for the ROM monitor.

These reserved areas are named with the prefix "reserved_" which is handled specially by the Configuration Tool: instead of referring to a linker macro, the start of the area is labeled and a gap left in the memory map.

Platform Serial Device Support

The first step is to set up the CDL definitions. The configuration options that need to be set are the following:

CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS

The number of channels, usually 0, 1 or 2.

CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL

The channel to use for GDB.

CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL_BAUD

Initial baud rate for debug channel.

CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL

The channel to use for the console.

CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_BAUD

The initial baud rate for the console channel.

CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL_DEFAULT

The default console channel.

The code in hal_diag.c need to be converted to support the new serial device. If this the same as a device already supported, copy that.

The following functions and types need to be rewritten to support a new serial device.

struct channel_data_t;

Structure containing base address, timeout and ISR vector number for each serial device supported. Extra fields my be added if necessary for the device. For example some devices have write-only control registers, so keeping a shadow of the last value written here can be useful.

xxxx_ser_channels[];

Array of channel_data_t, initialized with parameters of each channel. The index into this array is the channel number used in the CDL options above and is used by the virtual vector mechanism to refer to each channel.

void cyg_hal_plf_serial_init_channel(void *__ch_data)

Initialize the serial device. The parameter is actually a pointer to a channel_data_t and should be cast back to this type before use. This function should use the CDL definition for the baud rate for the channel it is initializing.

void cyg_hal_plf_serial_putc(void * __ch_data, char *c)

Send a character to the serial device. This function should poll for the device being ready to send and then write the character. Since this is intended to be a diagnostic/debug channel, it is often also a good idea to poll for end of transmission too. This ensures that as much data gets out of the system as possible.

bool cyg_hal_plf_serial_getc_nonblock(void* __ch_data, cyg_uint8* ch)

This function tests the device and if a character is available, places it in *ch and returns TRUE. If no character is available, then the function returns FALSE immediately.

int cyg_hal_plf_serial_control(void *__ch_data, __comm_control_cmd_t __func, ...)

This is an IOCTL-like function for controlling various aspects of the serial device. The only part in which you may need to do some work initially is in the __COMMCTL_IRQ_ENABLE and __COMMCTL_IRQ_DISABLE cases to enable/disable interrupts.

int cyg_hal_plf_serial_isr(void *__ch_data, int* __ctrlc, CYG_ADDRWORD __vector, CYG_ADDRWORD __data)

This interrupt handler, called from the spurious interrupt vector, is specifically for dealing with Ctrl-C interrupts from GDB. When called this function should do the following:

  1. Check for an incoming character. The code here is very similar to that in cyg_hal_plf_serial_getc_nonblock().

  2. Read the character and call cyg_hal_is_break().

  3. If result is true, set *__ctrlc to 1.

  4. Return CYG_ISR_HANDLED.

void cyg_hal_plf_serial_init()

Initialize each of the serial channels. First call cyg_hal_plf_serial_init_channel() for each channel. Then call the CYGACC_COMM_IF_* macros for each channel. This latter set of calls are identical for all channels, so the best way to do this is to copy and edit an existing example.