天天看點

OpenOCD安裝與使用(JTAG調試)

本文介紹openocd開源軟體的安裝以及搭配JTAG對Xilinx u500VC707devkit的調試

PC OS: Ubuntu20.04 LTS

Target ARCH: riscv64

JTAG: Olimex-ARM-USB-TINY-H

OpenOCD version: OpenOCD v0.10.0

1、OpenOCD簡介

  

OpenOCD(Open On-Chip Debugger)

是一款開源的開放式片上調試軟體,需要在調試擴充卡(如: JTAG、SWD等)的配合下可以對片上系統進行相應調試,以及在嵌入式裝置上測試系統内程式或邊界接掃描測試。

2、下載下傳OpenOCD

  可以通過OpenOCD官網下載下傳源碼,已經有很多平台提供配套目标平台的

OpenOCD

源碼,也可以通過這些來下載下傳帶有相應目标平台配置檔案的

OpenOCD

,本文主要介紹支援

riscv64

OpenOCD

下載下傳和使用。

riscv-openocd

下載下傳連結: https://github.com/sifive/riscv-openocd

通過

git

下載下傳:

git clone https://github.com/sifive/riscv-openocd.git
           

3、編譯與安裝

<1> 進入

riscv-openocd

源碼目錄

imaginemiracle@:openocd$ cd riscv-openocd
imaginemiracle@:riscv-openocd$ ls
AUTHORS            ChangeLog         COPYING       HACKING      NEWS-0.10.0  NEWS-0.5.0  NEWS-0.9.0  README.Windows  TODO
AUTHORS.ChangeLog  config_subdir.m4  doc           jimtcl       NEWS-0.2.0   NEWS-0.6.0  NEWTAPS     src             tools
bootstrap          configure.ac      Doxyfile.in   Makefile.am  NEWS-0.3.0   NEWS-0.7.0  README      tcl             uncrustify.cfg
BUGS               contrib           guess-rev.sh  NEWS         NEWS-0.4.0   NEWS-0.8.0  README.OSX  testing
           

<2> 執行

bootstrap

生成

configure

檔案,通過

configure

配置

OpenOCD

,主要需要配置

OpenOCD

支援的調試器的類型,筆者使用的

JTAG

FTDI

類型,是以需要

OpenOCD

支援

FTDI

[注] 通過檢視JTAG手冊了解所使用的JTAG是什麼類型,通過./configure --help 指令檢視所需要開啟的類型以及其它配置參數

#建立安裝目錄
imaginemiracle@:riscv-openocd$ mkdir install_IM
#執行bootstrap
imaginemiracle@:riscv-openocd$ ./bootstrap
           

bootstrap

執行的正常輸出:

+ aclocal
+ libtoolize --automake --copy
+ autoconf
+ autoheader
+ automake --gnu --add-missing --copy
configure.ac:26: installing './compile'
configure.ac:37: installing './config.guess'
configure.ac:37: installing './config.sub'
configure.ac:16: installing './install-sh'
configure.ac:16: installing './missing'
Makefile.am:46: warning: wildcard $(srcdir: non-POSIX variable name
Makefile.am:46: (probably a GNU make extension)
Makefile.am: installing './INSTALL'
Makefile.am: installing './depcomp'
Makefile.am:23: installing './mdate-sh'
Makefile.am:23: installing './texinfo.tex'
Setting up submodules
Submodule 'jimtcl' (https://github.com/msteveb/jimtcl) registered for path 'jimtcl'
Cloning into '/media/imaginemiracle/Disk_D/Linux_Workspace/riscv-project/File_System_test/openocd/riscv-openocd/jimtcl'...
Submodule path 'jimtcl': checked out '51f65c6d38fbf86e1f0b036ad336761fd2ab7fa0'
Submodule path 'jimtcl': checked out '51f65c6d38fbf86e1f0b036ad336761fd2ab7fa0'
Generating build system...
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, 'build-aux'.
libtoolize: copying file 'build-aux/config.guess'
libtoolize: copying file 'build-aux/config.sub'
libtoolize: copying file 'build-aux/install-sh'
libtoolize: copying file 'build-aux/ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIRS, 'm4'.
libtoolize: copying file 'm4/libtool.m4'
libtoolize: copying file 'm4/ltoptions.m4'
libtoolize: copying file 'm4/ltsugar.m4'
libtoolize: copying file 'm4/ltversion.m4'
libtoolize: copying file 'm4/lt~obsolete.m4'
configure.ac:42: installing 'build-aux/ar-lib'
configure.ac:37: installing 'build-aux/compile'
configure.ac:30: installing 'build-aux/missing'
Makefile.am: installing './INSTALL'
libjaylink/Makefile.am: installing 'build-aux/depcomp'
Bootstrap complete. Quick build instructions:
./configure ....
           

成功生成

configure

檔案

#配置安裝目錄路徑必須為絕對路徑
imaginemiracle@:riscv-openocd$ ./configure --prefix=/home/imaginemiracle/Disk_D/Linux_Workspace/riscv-project/File_System_test/openocd/openocd-0.10.0/install_IM/ --enable-ftdi
###################隻顯示關鍵輸出####################
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating libjaylink/Makefile
config.status: creating libjaylink/version.h
config.status: creating libjaylink.pc
config.status: creating Doxyfile
config.status: creating config.h
config.status: executing depfiles commands
config.status: executing libtool commands
           

看到成功成生

Makefile

檔案且沒有報錯,則說明配置成功。

<3> 配置成功後直接編譯并安裝即可

直接使用

make; make install

編譯并安裝

#編譯後并且安裝
imaginemiracle@:riscv-openocd$ make; make install
           

make; make install

直接通過,則跳過

<4>

這一節直接看下一節的

openocd

使用介紹。

<4> 編譯

openocd

可能會遇到如下幾種錯誤

<4.1> 報錯 1:

src/svf/svf.c:663:7: error: this statement may fall through [-Werror=implicit-fallthrough=]

#錯誤1
src/svf/svf.c: In function ‘svf_read_command_from_file’:
src/svf/svf.c:663:7: error: this statement may fall through [-Werror=implicit-fallthrough=]
  663 |     i = -1;
      |     ~~^~~~
src/svf/svf.c:664:4: note: here
  664 |    case '\r':
      |    ^~~~
src/svf/svf.c:667:8: error: this statement may fall through [-Werror=implicit-fallthrough=]
  667 |     if (!cmd_pos)
      |        ^
src/svf/svf.c:669:4: note: here
  669 |    default:
      |    ^~~~~~~
cc1: all warnings being treated as errors
           

解決方案 1: 通過源碼分析可以看出,這塊的報錯隻是因為在

switch case

語句中一個

case

沒有寫

break

,編譯器識别到可能會跳到下一個

case

語句中,是以在這裡直接忽略該錯誤繼續編譯即可。

imaginemiracle@:openocd$ make -j8 CFLAGS='-Wno-implicit-fallthrough'
           

<4.2> 報錯 2:

src/target/arm_disassembler.c:1499:30: error: bitwise comparison always evaluates to false [-Werror=tautological-compare]

#錯誤2
src/target/arm_disassembler.c: In function ‘evaluate_misc_instr’:
src/target/arm_disassembler.c:1499:30: error: bitwise comparison always evaluates to false [-Werror=tautological-compare]
 1499 |   if (((opcode & 0x00600000) == 0x00100000) && (x == 0)) {
      |                              ^~
src/target/arm_disassembler.c:1521:29: error: bitwise comparison always evaluates to false [-Werror=tautological-compare]
 1521 |   if ((opcode & 0x00600000) == 0x00300000) {
      |                             ^~
src/target/arm_disassembler.c:1542:30: error: bitwise comparison always evaluates to false [-Werror=tautological-compare]
 1542 |   if (((opcode & 0x00600000) == 0x00100000) && (x == 1)) {
      |                              ^~
           

解決方案 2: 按照道理說這種寫法是沒什麼問題的,但還是會報錯,是以将報錯的三個位置進行修改,修改後的代碼如下。

imaginemiracle@:openocd$ vim src/target/arm_disassembler.c +1499
           
//File src/target/arm_disassembler.c +1499:In function 'evaluate_misc_instr'
        /* SMLAW < y> */
//============================Alter by me==============================
        if (!(((opcode & 0x00600000) - 0x00100000)) && (x == 0)) {
//============================ End Alter ==============================
            uint8_t Rd, Rm, Rs, Rn;
            instruction->type = ARM_SMLAWy;
            Rd = (opcode & 0xf0000) >> 16;
            Rm = (opcode & 0xf);
            Rs = (opcode & 0xf00) >> 8;
            Rn = (opcode & 0xf000) >> 12;

            snprintf(instruction->text,
                    128,
                    "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLAW%s%s r%i, r%i, r%i, r%i",
                    address,
                    opcode,
                    (y) ? "T" : "B",
                    COND(opcode),
                    Rd,
                    Rm,
                    Rs,
                    Rn);
        }

        /* SMUL < x><y> */
//============================Alter by me==============================                
        if (!((opcode & 0x00600000) - 0x00300000)) {
//============================ End Alter ==============================        
            uint8_t Rd, Rm, Rs;
            instruction->type = ARM_SMULxy;
            Rd = (opcode & 0xf0000) >> 16;
            Rm = (opcode & 0xf);
            Rs = (opcode & 0xf00) >> 8;

            snprintf(instruction->text,
                    128,
                    "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s%s r%i, r%i, r%i",
                    address,
                    opcode,
                    (x) ? "T" : "B",
                    (y) ? "T" : "B",
                    COND(opcode),
                    Rd,
                    Rm,
                    Rs);                                                                                                                                                                                                                                                                  
        }

        /* SMULW < y> */
//============================Alter by me==============================        
        if (!(((opcode & 0x00600000) - 0x00100000)) && (x == 1)) {
//============================ End Alter ==============================        
            uint8_t Rd, Rm, Rs;
            instruction->type = ARM_SMULWy;
            Rd = (opcode & 0xf0000) >> 16;
            Rm = (opcode & 0xf);
            Rs = (opcode & 0xf00) >> 8;

            snprintf(instruction->text,
                    128,
                    "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s r%i, r%i, r%i",
                    address,
                    opcode,
                    (y) ? "T" : "B",
                    COND(opcode),
                    Rd,
                    Rm,
                    Rs);
        }
           

<4.3> 報錯 3:

src/target/nds32_cmd.c:824:21: error: ‘sprintf’ writing a terminating nul past the end of the destination [-Werror=format-overflow=]

#錯誤3
src/target/nds32_cmd.c: In function ‘jim_nds32_bulk_read’:
src/target/nds32_cmd.c:824:21: error: ‘sprintf’ writing a terminating nul past the end of the destination [-Werror=format-overflow=]
  824 |   sprintf(data_str, "0x%08" PRIx32 " ", data[i]);
      |                     ^~~~~~~
src/target/nds32_cmd.c:824:38: note: format string is defined here
  824 |   sprintf(data_str, "0x%08" PRIx32 " ", data[i]);
      |                                      ^
src/target/nds32_cmd.c:824:3: note: ‘sprintf’ output 12 bytes into a destination of size 11
  824 |   sprintf(data_str, "0x%08" PRIx32 " ", data[i]);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           

解決方案 3: 從錯誤類型

format-overflow

,格式溢出,一看就是不重要的錯誤,直接忽略就好繼續編譯。

imaginemiracle@:openocd$ make -j8 CFLAGS='-Wno-implicit-fallthrough -Wno-format-overflow'
           

<4.4> 報錯 4:

/usr/include/x86_64-linux-gnu/sys/sysctl.h:21:2: error: #warning "The <sys/sysctl.h> header is deprecated and will be removed." [-Werror=cpp]

#錯誤4
In file included from src/helper/options.c:38:
/usr/include/x86_64-linux-gnu/sys/sysctl.h:21:2: error: #warning "The <sys/sysctl.h> header is deprecated and will be removed." [-Werror=cpp]
   21 | #warning "The <sys/sysctl.h> header is deprecated and will be removed."
      |  ^~~~~~~
cc1: all warnings being treated as errors
           

解決方案 4: 可以看出這裡是使用了

Linux

已經移除的頭檔案

<sys/sysctl.h>

報錯的,是以進入報錯檔案,做以下修改。

imaginemiracle@:openocd$ vim src/helper/options.c +38
           
//File src/helper/options.c +38
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "configuration.h"
#include "log.h"
#include "command.h"

#include <getopt.h>

#include <limits.h>
#include <stdlib.h>
#if IS_DARWIN
#include <libproc.h>
#endif
//===================Alter by me===================
#ifdef HAVE_SYS_SYSCTL_H
//#include <sys/sysctl.h>
#endif
#if IS_WIN32 && !IS_CYGWIN
#include <windows.h>
#endif
//=================== End  Alter ===================
static int help_flag, version_flag;
           

4、OpenOCD的使用

4.1、OpenOCD的配置

安裝成功後則會在配置的安裝目錄裡生成如下檔案,這裡的

openocd

就是需要用到的可執行程式将它拷貝到需要執行的目錄,或者直接在目前目錄使用也可以。(

[注]: 若未配置安裝路徑,預設安裝到“./src目錄”中

)

imaginemiracle@:openocd$ cd install_IM/
imaginemiracle@:install_IM$ ls
bin  share
imaginemiracle@:install_IM$ ls bin/
openocd
imaginemiracle@:openocd$ cp install_IM/bin/openocd ./
           

使用

openocd+JTAG

需要用到兩個配置檔案,分别是

JTAG

的配置檔案和目标平台的配置檔案。一般

JTAG

廠商都會提供購買到的

JTAG

openocd

配置檔案,這裡就可以直接使用。

<1> JTAG裝置配置檔案

前文提到筆者所使用的

JTAG

型号為

Olimex-ARM-USB-TINY-H

,其配置檔案如下:

# File olimex-arm-usb-tiny-h.cfg
#
# Olimex ARM-USB-TINY-H
#
# http://www.olimex.com/dev/arm-usb-tiny-h.html
#

interface ftdi
#interface jlink
ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H"
ftdi_vid_pid 0x15ba 0x002a

ftdi_layout_init 0x0808 0x0a1b
ftdi_layout_signal nSRST -oe 0x0200
ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100
ftdi_layout_signal LED -data 0x0800
           

當電腦連結上

JTAG

後,還需要安裝

JTAG

的驅動,若“

lsusb

”可以檢視到

JTAG

裝置,則說明驅動安裝成功。

imaginemiracle@:openocd$ lsusb
Bus 002 Device 002: ID 0424:5744 Microchip Technology, Inc. (formerly SMSC) Hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 001 Device 003: ID 0424:2744 Microchip Technology, Inc. (formerly SMSC) Hub
Bus 001 Device 007: ID 413c:2113 Dell Computer Corp. Dell KB216 Wired Keyboard
Bus 001 Device 006: ID 413c:301a Dell Computer Corp. Dell MS116 USB Optical Mouse
Bus 001 Device 008: ID 15ba:002a Olimex Ltd. ARM-USB-TINY-H JTAG interface
Bus 001 Device 002: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
           

這裡的

ID

後面的值分别為

USB

裝置的

VID

PID

,這裡的值應該與

JTAG

配置檔案中的

vid_pid

相同才可。

<2> 目标平台配置檔案

OpenOCD

的配置檔案使用的是

tcl

語言,這裡的目标平台配置檔案是筆者仿照其它配置檔案修改的。

# File riscv64_IM.cfg
proc init_targets {} {
	adapter_khz 1000
	reset_config trst_and_srst
	set _CHIPNAME riscv
	jtag newtap $_CHIPNAME cpu -irlen 5

	set _TARGETNAME $_CHIPNAME.cpu
	target create $_TARGETNAME riscv -endian little -chain-position $_TARGETNAME -coreid 0
	# $_TARGETNAME configure -rtos riscv
	# $_TARGETNAME configure -work-area-phys 0x3ff0000 -work-area-size 0x10000 -work-area-backup 1
	# $_TARGETNAME riscv expose_csrs 3008-3015,4033-4034
}

proc sw_reset_halt {} {
    reset halt
}
           

4.2、OpenOCD連結JTAG

有了

JTAG

和目标平台的兩個配置檔案後,就可以啟動

OpenOCD

連接配接本地

JTAG

裝置了,啟動指令如下:

imaginemiracle@:riscv-openocd$ sudo ./src/openocd -s ./tcl -f ./tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f ./tcl/target/riscv64_IM.cfg
[sudo] password for imaginemiracle: 
Open On-Chip Debugger 0.10.0+dev-01145-gb7bd3f8d4 (2021-01-12-17:54)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
sw_reset_halt
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
0
Info : clock speed 1000 kHz
Info : TAP riscv.cpu has invalid IDCODE (0xfffffffe)
Info : datacount=2 progbufsize=16
Info : Disabling abstract command reads from CSRs.
Info : Examined RISC-V core; found 4 harts
Info :  hart 0: XLEN=64, misa=0x800000000014112d
Info :  hart 1: currently disabled
Info :  hart 2: currently disabled
Info :  hart 3: currently disabled
Info : Listening on port 3333 for gdb connections
           

連接配接到本地:

imaginemiracle@:riscv-openocd$ telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
> 
           

如上進入

openocd

的指令行則說明

OpenOCD+JTAG

的整個軟體環境搭建完成。

4.3、OpenOCD的一些簡單指令

OpenOCD

常用指令

halt	-暫停CPU
reset	-複位目标闆
resume 	-恢複運作
resume 0x123456   -從0x123456位址恢複運作
reg <register>    -列印register寄存器的值

load_image <File Name> <Addr>		    -燒寫二進制檔案到指定位址
例: load_image image.bin 0x4000000  	-燒寫image.bin到0x4000000

dump_image <File Name> <Addr> <Size>    -将記憶體從位址Addr開始的Size位元組資料讀出,儲存到檔案File Name中

verify_image <File Name> <Addr> [bin|ihex|elf] 	-将檔案File Name與記憶體Addr開始的資料進行比較,格式可選,bin、ihex、elf

step [Addr]		-不加位址:從目前位置單步執行; 加位址:從Addr處單步執行
poll		    -查詢目标闆目前狀态
bp <Addr> <Length> [hw] 	-在Addr位址設定斷點,指令長度為Length,hw代表硬體斷點
rbp <Addr>		 -删除Addr處的斷點

mdw <Addr> [Count]	 -顯示從實體位址Addr開始的Count(預設則預設為1)個字(4Bytes)
mdh <Addr> [Count]	 -顯示從實體位址Addr開始的Count(預設則預設為1)個半字(2Bytes)
mdb <Addr> [Count]	 -顯示從實體位址Addr開始的Count(預設則預設為1)個位元組(1Byte)
mww <Addr> <Value>   -向實體位址Addr寫入Value,大小:一個字(4Bytes)
mwh <Addr> <Value>   -向實體位址Addr寫入Value,大小:一個半字(2Bytes)
mwb <Addr> <Value>   -向實體位址Addr寫入Value,大小:一個位元組(1Bytes)