OpenOCD (3): Learning OpenJTAG Config file configuration

Learn OpenJTAGConfig file configuration

This chapter is aimed at anyone who needs to write configuration files, including OpenOCD developers and integrators and anyone who needs to get a new board running smoothly. It provides guidelines for creating these files.

You should find the following directories under $(INSTALLDIR)/script with configuration files maintained upstream. Use them where possible to provide them as-is; or as models for new documents.

  • interface : These are used for debugging adapters. Files specifying configuration to use specific JTAG, SWD and other adapters are here.
  • board : About circuit board, PWA, PCB, they have many names. The board file contains board-specific initialization entries.
  • target : About the chip. The "target" directory represents the JTAG TAP. Which OpenOCD should control on a chip, not a board. Two common target types are ARM chips and FPGA or CPLD chips. When a chip has multiple TAPs (perhaps it has both ARM and DSP cores), the target profile defines all of them.
  • more : Browse other library files that may be useful. For example, there are various general and CPU-specific utilities.
印制电路板(PCB)、印制线路板(PWB)和印制线路组件(PWA),PCB是印刷电路板本身,PCBA是指印刷电路板的组装过程,而PWA是一种现代化的Web应用程序。它们分别代表了不同的概念和应用领域。

User configuration files can override functionality in any of the above files by setting variables before fetching the target file, or by adding commands specific to their situation.

1. Interface file configuration

A user profile should be able to fetch one of these files with a command like:

source [find interface/FOOBAR.cfg]

A pre-configured interface file should exist for every debug adapter used with OpenOCD today. That said, maybe some of these profiles are only used by the developer who created it.

Another chapter provides information on how to set these settings. See Debug Adapter Configuration. If you have a new hardware interface and need a driver for it, read the OpenOCD source code (and developer's guide).

Command: find 'filename'
prints the full path of the filename according to the OpenOCD search rules.

Command: ocd_find 'filename'
prints the full path of the filename according to the OpenOCD search rules. This is the low-level function used by lookup. Usually you want to use find.

Two, board configuration file

User profiles should be able to source one of these files using the following command:

source [find board/FOOBAR.cfg]

The purpose of a board profile is to package everything a user profile needs to know about a given board. In summary, the board file should contain (if present)

  • One or more source [find target/…cfg] statements
  • NOR flash configuration (see NOR configuration)
  • NAND flash configuration (see NAND configuration)
  • Target reset handler for SDRAM and I/O configuration
  • JTAG adapter reset configuration (see Reset Configuration)
  • Everything that isn't "inside the chip"

Common content inside the target chip belongs to the target configuration file, not the single board configuration file. So, for example, a reset initialization event handler should know the board-specific oscillator and PLL parameters and pass these parameters to the target-specific utility code.

The most complex task in the board configuration file is to create such a reset initialization event handler . Define these handlers last, after verifying that the rest of the board configuration works.

1- Communication between configuration files

In addition to target-specific utility code, another way the board and target configuration files communicate is by following conventions on how certain variables are used.

The full Tcl/Tk language supports "namespaces", but Jim-Tcl does not. Therefore, the rule we follow in OpenOCD is: Variables starting with a leading underscore are temporary in nature and can be modified and used freely in the target configuration file.

For a motherboard with three chips, a complex motherboard profile could do something like this:

# Chip #1: PXA270 for network side, big endian
set CHIPNAME network
set ENDIAN big
source [find target/pxa270.cfg]
# on return: _TARGETNAME = network.cpu
# other commands can refer to the "network.cpu" target.
$_TARGETNAME configure .... events for this CPU..

# Chip #2: PXA270 for video side, little endian
set CHIPNAME video
set ENDIAN little
source [find target/pxa270.cfg]
# on return: _TARGETNAME = video.cpu
# other commands can refer to the "video.cpu" target.
$_TARGETNAME configure .... events for this CPU..

# Chip #3: Xilinx FPGA for glue logic
set CHIPNAME xilinx
unset ENDIAN
source [find target/spartan3.cfg]

The example is oversimplified as it doesn't show any flash memory, nor does it show a reset initialization event handler for initializing the external DRAM or (assuming it needs to) loading the configuration into the FPGA.

These features are often required for the low-level working of many motherboards, where "low-level" means that the motherboard initialization software may not work. (This is a common reason for needing JTAG tools. Another reason is to allow the use of microcontroller-based systems, which typically have no debug support other than a JTAG connector.)

Target profiles can also export utility functions to board and user profiles. Such functions should use a name prefix to help avoid naming conflicts.

Board files can also accept input variables from user configuration files. For example, there might be a J4_jumper setting to identify the type of flash the board is using, or how to set other clocks and peripherals.

2- Variable naming convention

Most single boards have only one instance of the chip. However, it should be easy to create a motherboard with multiple of these chips (as shown in the picture above). Therefore, we encourage these conventions for naming variables associated with different target.cfg files to promote consistency so that board files can override target defaults.

The input to the target configuration file includes:

  • CHIPNAME ... This provides a name for the entire chip and is used as part of the dotted name for the tap identifier. While defaults are usually provided by the chip manufacturer, board documentation may be required to differentiate instances of the chip.
  • ENDIAN...by default, very few – although chips may be hardwired to be large. Chips that cannot change endianness do not need to use this variable.
  • CPUTAPID ... When OpenOCD checks the JTAG chain, it can be told to verify the chip against the JTAG IDCODE register. The target file will hold one or more default values, but sometimes the chip in the motherboard will use a different ID (possibly a newer version).

The output of the target configuration file includes:

  • _TARGETNAME : By convention, this variable is created by the target configuration script. Board configuration files can use this variable to configure things like "reset init" scripts or other things specific to that board and that target. If the chip has 2 targets, the names are _target_name0, _target_name1, ...etc.

3- Reset the initialization event handler

Board configuration files are run during the OpenOCD configure pass; they cannot use TAPs or targets because they have not been fully set up. This means you can't write to memory or access chip registers; you can't even verify that the flash chip exists. This will be done later in the event handlers, of which the target reset initialization handler is one of the most important.

Apart from the microcontroller, the basic job of the reset initialization event handler is to set up the flash memory and DRAM, usually handled by the bootloader. Microcontrollers rarely use bootloaders; they run directly from on-chip flash and SRAM memory. But they might also want to use one of these handlers, if only for developer convenience.

NOTE: Since this is very motherboard and chip specific, no examples are included here. Instead, look at the motherboard configuration files distributed with OpenOCD. If you have a bootloader, its source code will help; configuration files for other JTAG tools will also help (see Translating Configuration Files).

Some of this code may be shareable between different boards. For example, setting up a DRAM controller usually doesn't make much difference other than bus width (16-bit or 32-bit) and memory timings, so a reusable TCL procedure loaded by a target.cfg file might take these as parameters. Oscillator, PLL, and clock settings are similar; and watchdog is disabled. Build the code cleanly, and provide comments to help the next developer do the job. (You might be the next person trying to reuse init code!)

The last thing usually done in a reset init handler is to probe the configured flash memory. For most chips this needs to be done while the associated target is stopped, either because JTAG memory accesses use the CPU, or to prevent conflicting CPU accesses.

4 - JTAG clock rate

You may need to run at a lower JTAG clock rate before the reset initialization handler sets up the PLL and clock. See JTAG speed. You would then increase that rate after the handler makes it possible to use the faster JTAG clock. When the initial low speed is board-specific, e.g. because it depends on the board-specific oscillator speed, then you should probably set it in the board-config file; if it's target-specific, it belongs in the target configuration in the file.

For most ARM-based processors, the fastest JTAG clock is one-sixth of the CPU clock;
for the ARM11 core, the fastest JTAG clock4 is one-eighth of the CPU clock. Consult the chip documentation to determine the peak JTAG clock rate, which may be lower than that.

Warning: On most ARMs, JTAG clock detection is coupled to the core clock, so software using wait-for-interrupt operations will block JTAG access . Adaptive clocks provide a partial solution, but a more complete solution is simply to avoid using this instruction in the JTAG debugger.

If both the chip and the board support adaptive clocking, use the jtag_rclk command in case your board is used with a JTAG adapter, which also supports adaptive clocking . Otherwise, use the adapter speed. The slow rate is set at the beginning of the reset sequence and the faster rate is set immediately when the clock is running at full speed.

5-init_board process

The init_board procedure is very similar in concept to init_target (see init_target procedure.) - it is an alternative to the "linear" configure script. This process is intended to be executed when OpenOCD enters the run phase (see Entering the run phase, after init_targets).

The idea of ​​having separate init_target and init_board processes is to allow

  • The first process configures all target-specific processes (internal flash, internal RAM, etc.),
  • The second procedure configures all board-specific procedures (reset signal, chip frequency, reset initialization event handler, external memory, etc.).

Also, "linear" board configuration files are likely to fail when the target configuration file uses the init_targets scheme ("linear" scripts are executed after init and init_targets-), so it is very convenient to separate these two configuration phases to overcome this problem The easiest way is to convert the board configuration file to use the init_board process. When the board configuration script only needs to add some details, there is no need to override the init_targets defined in the target configuration file.

Just like init_targets, the init_board process can be overridden by "next-level" scripts (whose source is the original script), allowing even more code reuse.

### board_file.cfg ###

# source target file that does most of the config in init_targets
source [find target/target.cfg]

proc enable_fast_clock {} {
    # enables fast on-board clock source
    # configures the chip to use it
}

# initialize only board specifics - reset, clock, adapter frequency
proc init_board {} {
    reset_config trst_and_srst trst_pulls_srst

    $_TARGETNAME configure -event reset-start {
        adapter speed 100
    }

    $_TARGETNAME configure -event reset-init {
        enable_fast_clock
        adapter speed 10000
    }
}

3. Target configuration file

Board configuration files communicate with target configuration files using the naming convention described above, and may source one or more target configuration files, as follows:

source [find target/FOOBAR.cfg]

The purpose of a Target profile is to package everything a motherboard profile needs to know about a given chip . In short, the Target file should contain:

  • set default
  • Add TAP to scan chain
  • Add CPU target (including GDB support)
  • CPU/chip/CPU-core specific functions
  • On-chip flash memory

According to experience, the Target file only sets one chip. For microcontrollers, this usually includes a CPU that requires a GDB target and its on-chip flash memory.

More complex chips may include multiple TAPs, and the target configuration file may need to define all TAPs before OpenOCD can communicate with the chip. For example, some phone chips have a JTAG scan chain that includes an ARM core for the operating system, a DSP, another ARM core embedded in a graphics processing engine, and other processing engines.

1 Default Value Boiler Plate Code

All target configuration files should start with code like this to let board configuration files express environment-specific differences in how settings are made.

# Boards may override chip names, perhaps based on role,
# but the default should match what the vendor uses
if { [info exists CHIPNAME] } {
   set  _CHIPNAME $CHIPNAME
} else {
   set  _CHIPNAME sam7x256
}

# ONLY use ENDIAN with targets that can change it.
if { [info exists ENDIAN] } {
   set  _ENDIAN $ENDIAN
} else {
   set  _ENDIAN little
}

# TAP identifiers may change as chips mature, for example with
# new revision fields (the "3" here). Pick a good default; you
# can pass several such identifiers to the "jtag newtap" command.
if { [info exists CPUTAPID ] } {
   set _CPUTAPID $CPUTAPID
} else {
   set _CPUTAPID 0x3f0f0f0f
}

Remember: a motherboard configuration file may contain multiple target configuration files, or the same target file multiple times (at least change the chip name) .

Likewise, target configuration files should define _TARGETNAME (or _TARGETNAME 0, etc.) and use it later when defining debug targets:

set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME

2 Adding TAPs to the Scan Chain

After setting the "Defaults", add the TAP on each chip to the JTAG scan chain . See TAP Declaration and Naming Conventions for TAP .

In the simplest case, the chip has only one TAP, which may be for the CPU or FPGA . The configuration file (part) of Atmel AT91SAM7X256 looks like this:

jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID

A motherboard with two such at91sam7 chips will be able to source such a configuration file twice and provide a different value for the chip name, thus adding a different TAP each time.

If there are non-zero -expected_id values, OpenOCD will try to verify the actual tap ID against these values. It will issue an error message if there is a mismatch, which can help identify problems in the OpenOCD configuration.

JTAG tap: sam7x256.cpu tap/device found: 0x3f0f0f0f
                (Manufacturer: 0x787, Part: 0xf0f0, Version: 0x3)
ERROR: Tap: sam7x256.cpu - Expected id: 0x12345678, Got: 0x3f0f0f0f
ERROR: expected: mfg: 0x33c, part: 0x2345, ver: 0x1
ERROR:      got: mfg: 0x787, part: 0xf0f0, ver: 0x3

There are also more complex examples where the chip has multiple TAPs. Noteworthy include:

  • target/omap3530.cfg – with disabled ARM and DSP, plus a JRC to enable them
  • target/str912.cfg – with flash, CPU, and boundary scan
  • target/ti_dm355.cfg – with ETM, ARM, and JRC (this JRC is not currently used)

3 Add CPU targets

After adding TAP for the CPU, it should be set up so that GDB and other commands can use it. See CPU configuration. For the at91sam7 example above, the command could be something like this; note that $_ENDIAN is not needed since OpenOCD defaults to little endian and this chip doesn't support changing it.

set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME arm7tdmi -chain-position $_TARGETNAME

A work area is a small RAM area associated with a CPU target. OpenOCD uses them to speed up downloads and to download small code snippets to program flash chips. If the chip includes a form of "on-chip RAM" - and many do - define a work area if you can. Using at91sam7 as an example again, this could look like:

$_TARGETNAME configure -work-area-phys 0x00200000 \
             -work-area-size 0x4000 -work-area-backup 0

4 Define CPU targets that work in SMP

After setting the goals, you can define a list of goals to work in SMP.

set _TARGETNAME_1 $_CHIPNAME.cpu1
set _TARGETNAME_2 $_CHIPNAME.cpu2
target create $_TARGETNAME_1 cortex_a -chain-position $_CHIPNAME.dap \
-coreid 0 -dbgbase $_DAP_DBG1
target create $_TARGETNAME_2 cortex_a -chain-position $_CHIPNAME.dap \
-coreid 1 -dbgbase $_DAP_DBG2
#define 2 targets working in smp.
target smp $_CHIPNAME.cpu2 $_CHIPNAME.cpu1

In the example above, 2 CPUs are working in SMP. In SMP, only one instance of GDB is created, and:

  • A set of hardware breakpoints sets the same breakpoints on all targets in the list.

  • The stop command triggers the stop of all targets in the list.

  • The resume command triggers a restart of the write context and all targets in the list.

  • After a breakpoint: Targets stopped by a breakpoint will be displayed into the GDB session.

  • Implements a dedicated GDB serial protocol package for switching/retrieving objects displayed by a GDB session, see Using OpenOCD SMP with GDB.

  • SMP behavior can be dynamically disabled/enabled. On cortex_a, the following commands have been implemented.

  • cortex_a smp on: enable SMP mode, behavior as described above.

  • cortex_a smp off: SMP mode is disabled, the current target is the one shown in the GDB session, now only this target is controlled by the GDB session. This behavior is useful during system startup.

  • cortex_a smp: Display the current SMP mode.

  • cortex_a smp_gdb: show/fix core id shown in GDB session, see example below.

>cortex_a smp_gdb
gdb coreid  0 -> -1
#0 : coreid 0 is displayed to GDB ,
#-> -1 : next resume triggers a real resume
> cortex_a smp_gdb 1
gdb coreid  0 -> 1
#0 :coreid 0 is displayed to GDB ,
#->1  : next resume displays coreid 1 to GDB
> resume
> cortex_a smp_gdb
gdb coreid  1 -> 1
#1 :coreid 1 is displayed to GDB ,
#->1 : next resume displays coreid 1 to GDB
> cortex_a smp_gdb -1
gdb coreid  1 -> -1
#1 :coreid 1 is displayed to GDB,
#->-1 : next resume triggers a real resume

5 Chip Reset Setup

Normally, you should put the reset_config command into the board file. Most things you think you know about chips can be tuned by the board.

Certain chips have specific ways of managing TRST and SRST signals. In the unusual case that these are chip specific and can never be changed by board routing, they can be here. For example, some chips cannot support JTAG debugging without both signals.

Provide a reset assertion event handler if available. Such a handler resets the target using a JTAG operation, letting this target be configured for use on systems that do not provide the optional SRST signal, or on systems that do not want to reset all targets at once. Such a handler might write to chip registers to force a reset, use a JRC to do so (preferably - the target could be wedged!), or force a watchdog timer to fire. (For Cortex-M targets, this is not necessary. The target driver knows how to use trigger NVIC reset when SRST is not available.)

Some chips require special attention during reset processing if they are to be used with JTAG. For example, it may be desirable to send some commands immediately after the target's TAP resets, providing a reset-deassert-post event handler that writes to chip registers to report that JTAG debugging is being completed. Another way is to reconfigure the watchdog to stop counting when the kernel is stopped in the debugger.

JTAG clock constraints can often change during resets, and in some cases the target configuration file (rather than the board configuration file) is the right place to handle some of these issues. For example, immediately after reset, most chips run on a slower clock than the one used later. This means that, after a reset (and possibly, when OpenOCD is first started), they must use a slower JTAG clock rate than they will use afterwards. See JTAG speed.

IMPORTANT NOTE: Getting these issues right is critical when you're debugging code that runs immediately after a chip reset. In particular, if you see intermittent failures when OpenOCD verifies the scan chain after a reset, look at how you set the JTAG clock.

6 The init_targets procedure

Target configuration files can either be "linear" (scripts executed line by line as the configure phase parses, see configure phases, ), or contain a special procedure called init_targets that will be executed when entering the run phase (after parsing all config file or after the init command), see Entering the run phase. ) such procedures can be overridden by "lower level" scripts (source original scripts).

This concept facilitates code reuse when a base target profile provides a generic configuration procedure and an init_targets procedure, which can then be sourced and enhanced or changed in a "more specific" target profile. This is not possible with "linear" configure scripts, since sourcing them executes every init command they provide.

### generic_file.cfg ###

proc setup_my_chip {chip_name flash_size ram_size} {
    # basic initialization procedure ...
}

proc init_targets {} {
    # initializes generic chip with 4kB of flash and 1kB of RAM
    setup_my_chip MY_GENERIC_CHIP 4096 1024
}

### specific_file.cfg ###

source [find target/generic_file.cfg]

proc init_targets {} {
    # initializes specific chip with 128kB of flash and 64kB of RAM
    setup_my_chip MY_CHIP_WITH_128K_FLASH_64KB_RAM 131072 65536

The easiest way to convert a "linear" configuration file to the init_targets version is to include every line of "code" (i.e. not source commands, procedures, etc.) in the process.

See the LPC2000 target configuration file for an example of this scheme.

The init_boards procedure is a similar concept to board configuration files (see init_board procedure.)

7 The init_target_events procedure

A special procedure named init_target_events runs after init_target (see init_target procedure.) and before init_board (see init_board procedure.). It is used to set default target events for targets that have not been assigned those events.

8 ARM core-specific hacks

If the chip has DCC, please enable DCC. If the chip is an ARM9 with some special high-speed download capabilities, enable it.

If present, MMU, MPU and CACHE should be disabled.

Some ARM cores are equipped with trace support, allowing inspection of instruction and data bus activity. Trace activity is controlled via the **Embedded Trace Module (ETM)** on one of the core scan chains. ETM sends large amounts of data through "trace ports". (See ARM Hardware Trace.) If you are using an external trace port, configure it in the board configuration file.

If you are using the on-chip "Embedded Trace Buffer" (ETB), configure it in the target configuration file.

etm config $_TARGETNAME 16 normal full etb
etb config $_TARGETNAME $_CHIPNAME.etb

9 Internal Flash Configuration

This only applies to microcontrollers with built-in flash memory.

Never define . (For example, boot flash on chip select 0.) Such flash information is in the motherboard file, not the target (chip) file.

Example:

  • at91sam7x256 - has 256K flash YES enable it.
  • str912 - has flash internal YES enable it.
  • imx27 - uses boot flash on CS0 - it goes in the board file.
  • pxa270 - again - CS0 flash - it goes in the board file.

Fourth, the conversion configuration file

If you have a configuration file for another hardware debugger or toolset (Abatron, BDI2000, BDI3000, CCS, Lauterbach, SEGGER, Macraigor, etc.), converting it to OpenOCD syntax is usually fairly straightforward.

The trickiest part of creating a configuration script is usually setting up the reset initialization sequence for the PLL, DRAM, etc.

One trick you can use when translating is to write a small Tcl handler that converts the syntax to OpenOCD syntax. This avoids manual translation errors and makes it easier to translate other scripts later.

Example of turning wacky arguments into a simple search and replace job:

#   Lauterbach syntax(?)
#
#       Data.Set c15:0x042f %long 0x40000015
#
#   OpenOCD syntax when using procedure below.
#
#       setc15 0x01 0x00050078

proc setc15 {regs value} {
    global TARGETNAME

    echo [format "set p15 0x%04x, 0x%08x" $regs $value]

    arm mcr 15 [expr {($regs >> 12) & 0x7}] \
        [expr {($regs >> 0) & 0xf}] [expr {($regs >> 4) & 0xf}] \
        [expr {($regs >> 8) & 0x7}] $value
}

Guess you like

Origin blog.csdn.net/weixin_45264425/article/details/132023395