Changes between Version 1 and Version 2 of Debugging/OpenOCD/Xilinx_Zynq


Ignore:
Timestamp:
08/04/15 00:29:52 (9 years ago)
Author:
Chris Johns
Comment:

Updates.

Legend:

Unmodified
Added
Removed
Modified
  • Debugging/OpenOCD/Xilinx_Zynq

    v1 v2  
    77Xilinx define the JTAG access to the Zynq part with a 14-pin header while suitable adaptors such as the Flyswatter2 have the standard ARM 20pin header. You can buy from Avnet a [http://www.em.avnet.com/en-us/design/drc/Pages/ZedBoard-Processor-Debug-Adapter.aspx  ZedBoard Processor Debug Adapter].
    88
    9 
     9JTAG access to the Zynq only operates if the board is in a suitable JTAG mode and it is not in a secure boot mode. Please refer to the Xilinx Zynq-7000 Technical Reference Manual and any user manul for your hardware for details on how to set the board's mode into JTAG.
     10
     11== Xilinx SDK PS7 Initialisation ==
     12
     13The Xilinx design tools and SDK produce initialisation code. The System design tool lets you specific the type of memory, clocks and bus structures and the tools generate C code for use in the First Stage Boot Loader (FSBL) and TCL code for use with the Xilinx XDM JTAG tool.  Save the following code as `xilinx-tcl.cfg`:
     14
     15{{{
     16#
     17# TCL to allow the Xilinx PS7 Init TCL code to run in OpenOCD.
     18#
     19
     20proc mrd { addr } {
     21    mem2array x 32 $addr 1
     22    return $x(0)
     23}
     24
     25proc mask_write { addr mask value } {
     26    set curval "[mrd $addr]"
     27    set maskedval [expr {$curval & ~$mask}]
     28    #echo "curval = [format 0x%08x $curval] maskedval = [format 0x%08x $maskedval]"
     29    set writeval(0) [expr {$maskedval | $value}]
     30    #echo " $addr <= [format 0x%08x $writeval(0)] ([format 0x%08x $curval]: [format 0x%08x $mask]/[format 0x%08x $value])"
     31    array2mem writeval 32 $addr 1
     32}
     33
     34proc xilinx_ps7_init { } {
     35   poll off
     36   reset init
     37   reset halt
     38   targets zc706.cpu.0
     39   sleep 100
     40   halt
     41   ps7_debug
     42   ps7_init
     43   ps7_post_config
     44   poll on
     45}
     46}}}
     47
     48This file will allow you to run the TCL script from the Xilinx SDK using OpenOCD. There are some instances around some parts of the initialisation that may not work. Uncomment the `echo` lines, location the writes that fail and comment those out from your PS7 init TCL script.
     49
     50The main purpose of this initialisation process is to get working clocks and DDR memory so you can load your code and run it.
     51
     52== First Stage Boot Loader Initialisation ==
     53
     54A second approach to initialisation is to use the FSBL. The FSBL contains the C version of the PS7 initialisation produced by the SDK. The FSBL should detect the mode is JTAG and place the ARM code in a state where JTAG access is enabled. To do this you create an OpenOCD TCL script that loads the FSBL as an ELF file into the OCM and run it, pause for a small amount of time then halt the ARM code. At this point in time the Zynq will be initialised and you can download your application into DDR RAM.
     55
     56== Xilinx Zynq-7000 Configuration File ==
     57
     58The following is a target configuration for the Xilinx Zynq-7000. Copy this to a file called `zynq-7000.cfg`:
     59
     60{{{
     61#
     62# Xilinx Zynq 7000 SoC
     63#
     64#  Chris Johns <chrisj@rtems.org>
     65#
     66# Setup
     67# -----
     68#
     69# Create a user configuration following the "Configuration Basics" in the user
     70# documentation. In the file have:
     71#
     72#    source [find interface/ftdi/flyswatter2.cfg]
     73#    source [find board/zynq-zc706-eval.cfg]
     74#    adapter_khz 2000
     75#    init
     76#
     77
     78if { [info exists CHIPNAME] } {
     79    global _CHIPNAME
     80    set _CHIPNAME $CHIPNAME
     81} else {
     82    global _CHIPNAME
     83    set _CHIPNAME zc706
     84}
     85
     86if { [info exists ENDIAN] } {
     87    set _ENDIAN $ENDIAN
     88} else {
     89    # this defaults to a bigendian
     90    set _ENDIAN little
     91}
     92
     93if { [info exists SMP] } {
     94    global _SMP
     95    set _SMP 1
     96} else {
     97    global _SMP
     98    set _SMP 0
     99}
     100
     101#
     102# PL Tap.
     103#
     104# ZC706 devices:
     105#   0x03731093 - Eval board 1.1
     106#   0x23731093 - ??
     107#
     108# Set in your configuration file or board specific file.
     109#
     110if { [info exists PL_TAPID] } {
     111    set _PL_TAPID $PL_TAPID
     112} else {
     113    set _PL_TAPID 0x03731093
     114}
     115
     116jtag newtap $_CHIPNAME tap -irlen 6 -ircapture 0x001 -irmask 0x003 \
     117    -expected-id $_PL_TAPID
     118
     119#
     120# CoreSight Debug Access Port
     121#
     122if { [info exists DAPTAPID] } {
     123    set _DAP_TAPID $DAP_TAPID
     124} else {
     125    set _DAP_TAPID 0x4ba00477
     126}
     127
     128jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x01 -irmask 0x03 \
     129    -expected-id $_DAP_TAPID
     130
     131#
     132# GDB target: Cortex-A9, using DAP, configuring only one core
     133# Base addresses of cores:
     134# core 0  -  0xF8890000
     135# core 1  -  0xF8892000
     136#
     137# Read from the ROM table with the patch to read the nested table.
     138#
     139
     140set _TARGETNAME_0 $_CHIPNAME.cpu.0
     141set _TARGETNAME_1 $_CHIPNAME.cpu.1
     142
     143target create $_TARGETNAME_0 cortex_a -coreid 0 \
     144    -endian $_ENDIAN \
     145    -chain-position $_CHIPNAME.dap \
     146    -dbgbase 0x80090000
     147if { $_SMP } {
     148    echo "Zynq CPU1."
     149    target create $_TARGETNAME_1 cortex_a -coreid 1 \
     150        -endian $_ENDIAN \
     151        -chain-position $_CHIPNAME.dap \
     152        -dbgbase 0x80092000
     153    target smp $_TARGETNAME_0 $_TARGETNAME_1
     154}
     155
     156#
     157# Hack to get the registers into a stable state when first booting a zynq in
     158# JTAG mode. If r11 is pointing to an invalid address and you use gdb to set a
     159# register the write will fail because gdb attempts to scan or unwind the
     160# current frame and the bad address seems to lock the bus up. This code puts
     161# the registers into the OCM and hopefull safe.
     162#
     163proc zynq_clear_registers { target } {
     164    echo "Zynq-7000 Series setup: $target"
     165    set _OCM_END 0x0003FFF0
     166    mww phys 0xF8007000 0x4E00E07F
     167    reg r0 0
     168    reg r1 0
     169    reg r2 0
     170    reg r3 0
     171    reg r4 0
     172    reg r5 0
     173    reg r6 0
     174    reg r7 0
     175    reg r8 0
     176    reg r9 0
     177    reg r10 0
     178    reg r11 $_OCM_END
     179    reg sp_svc $_OCM_END
     180    reg lr_svc $_OCM_END
     181    reg sp_abt $_OCM_END
     182    reg lr_abt $_OCM_END
     183    reg sp_und $_OCM_END
     184    reg lr_und $_OCM_END
     185}
     186
     187proc zynq_disable_mmu_and_caches { target } {
     188    # arm mcr pX op1 CRn CRm op2 value
     189    echo "Disable MMU and caches"
     190    # Invalidate caches
     191    catch {
     192        $target arm mcr 15 0 7 5 0 0
     193        $target arm mcr 15 0 7 7 0 0
     194        # Invalidate all TLBs
     195        $target arm mcr 15 0 8 5 0 0
     196        $target arm mcr 15 0 8 6 0 0
     197        $target arm mcr 15 0 8 7 0 0
     198        $target arm mcr 15 4 8 3 0 0
     199        $target arm mcr 15 4 8 7 0 0
     200        set cp [$target arm mrc 15 0 1 0 0]
     201        echo "SCTRL => [format 0x%x $cp]"
     202        set mask [expr 1 << 29 | 1 << 12 | 1 << 11 | 1 << 2 | 1 << 1 | 1 << 0]
     203        set cp [expr ($cp & ~$mask)]
     204        $target arm mcr 15 0 1 0 0 $cp
     205        echo "SCTRL <= [format 0x%x $cp]"
     206    }
     207}
     208
     209proc zynq_boot_ocm_setup { } {
     210    #
     211    # Enable the OCM
     212    #
     213    echo "Zynq Boot OCM setup"
     214    catch {
     215      mww phys 0xF8000008 0xDF0D
     216      mww phys 0xF8000238 0
     217      mww phys 0xF8000910 0xC
     218    }
     219}
     220
     221proc zynq_restart { wait } {
     222    global _SMP
     223    global _TARGETNAME_0
     224    global _TARGETNAME_1
     225    set target0 $_TARGETNAME_0
     226    set target1 $_TARGETNAME_1
     227    echo "Zynq reset, resetting the board ... "
     228    poll off
     229    #
     230    # Issue the reset via the SLCR
     231    #
     232    catch {
     233        mww phys 0xF8000008 0xDF0D
     234        mww phys 0xF8000200 1
     235    }
     236    echo "Zynq reset waiting for $wait msecs ... "
     237    sleep $wait
     238    #
     239    # Reconnect the DAP etc due to the reset.
     240    #
     241    $target0 cortex_a dbginit
     242    $target0 arm core_state arm
     243    if { $_SMP } {
     244        $target1 arm core_state arm
     245        $target1 cortex_a dbginit
     246        cortex_a smp_off
     247    }
     248    poll on
     249    #
     250    # We can now halt the core.
     251    #
     252    if { $_SMP } {
     253        targets $target1
     254        halt
     255    }
     256    targets $target0
     257    halt
     258}
     259
     260proc zynq_zc706_gdb_attach { target } {
     261    catch {
     262      halt
     263    }
     264}
     265}}}
     266
     267== Custom Board Configuration ==
     268
     269Create a directory somewhere on your host and create a `target` directory and place the `zynq-7000.cfg` file in it. Create a board configuration file. In this example we will create `zynq-zc706-eval.cfg` with the contents of:
     270
     271{{{
     272#
     273# Xilinx Zynq ZC706 Evaluation Board
     274#
     275#  Chris Johns <chrisj@rtems.org>
     276#
     277
     278set PL_TAPID 0x23731093
     279
     280source [find target/zynq-7000.cfg]
     281source [find xilinx-tcl.cfg]
     282
     283#
     284# Configure the reset.
     285#
     286reset_config srst_only
     287adapter_nsrst_assert_width 250
     288adapter_nsrst_delay 400
     289}}}
     290
     291Finally I have more than one Flyswatter2 connected so I create a configuration file for each pod. The `zynq-zc706-1.cfg` is:
     292
     293{{{
     294source [find interface/ftdi/flyswatter2.cfg]
     295source [find zynq-zc706-eval.cfg]
     296
     297ftdi_serial FS01
     298
     299# Set the speed
     300adapter_khz 10000
     301
     302init
     303}}}
     304
     305== Running OpenOCD ==
     306
     307Start OpenOCD using:
     308
     309{{{
     310$ openocd -f ps7_init.tcl -f zynq-zc706-1.cfg -c reset
     311}}}
     312
     313The PS7 TCL file is passed on the command line so you can vary the initialisation for specific boards as you need by changing how to start OpenOCD.
     314
     315== GDB Configuration ==
     316
     317This configuration allow you to commit into your repository a standard configuration placing the host specific configuration in your home directory.
     318
     319Create a `$HOME/.gdbinit` file and place in it:
     320
     321{{{
     322def zynq-connect
     323  target remote :3334
     324end
     325
     326def zynq-fsbl-restart
     327 mon xilinx_ps7_init
     328end
     329
     330def zynq-restart
     331 mon xilinx_ps7_init
     332 mon load_image /my/path/fsbl.elf 0x00000000 elf
     333 mon resume 0
     334 mon sleep 2000
     335 mon halt
     336end
     337}}}
     338
     339To debug an FSBL create a file called `zynq-gdbinit` and have your build system copy it to a suitable place in your build tree calling it `.gdbinit`. It should contain:
     340
     341{{{
     342#
     343# Zynq FSBL Support.
     344#
     345
     346zynq-connect
     347zynq-fsbl-restart
     348
     349load
     350
     351b _exit
     352}}}
     353
     354For an RTEMS application create another `zynq-gdbinit` file and also have your build system copy it to your build tree calling it `.gdbinit` and place in it:
     355
     356{{{
     357#
     358# Zynq debug start up.
     359#
     360
     361zynq-connect
     362zynq-restart
     363
     364load
     365
     366b _exit
     367b bsp_reset
     368
     369tb main
     370c
     371}}}
     372
     373== Issues ==
     374
     3751. The latest OpenOCD may have problems when the L2 cache is enabled. This is being looked into as time permits.
     3761. SMP support is not well tested.