1. 简介
本文分享 JTAG to AXI Master IP Core 的使用教程。
此 IP 用于 AXI 接口向设计输入数据,或者读取数据。通过 Tcl 控制台编写命令来驱动此 IP,通过 JTAG 即可进行操作,而这个 IP 则在 AXI 端口上驱动 AXI 事务。由于这个核心没有自己的地址空间,它对所有从 JTAG 生成的 AXI 事务都是透明的。
与 Vivado 逻辑分析器一起,此 IP 可以用作 AXI 系统调试和测试工具。
IP Feature:
- 最大工作频率为 200MHz
- 协议支持:
- AXI4
- AXI4-Lite
- 地址宽度: 32 位或者 64 位
- ID 宽度支持最多四位,允许用户定义 ID 信号
- AXI4-Lite 数据宽度为 32 位
- AXI4 数据宽度为 32 位或者 64 位
- 支持所有内存映射AXI接口事务,包括:
- 突发类型 - INCR(增量)、FIXED(固定)和WRAP(环绕)
- 突发长度:
- 对于INCR和FIXED为1到256
- 对于WRAP为2、4、8和16
- 支持缓存信号
- 硬件调试运行时 Tcl 控制台控制同时读/写操作
2. JTAG to AXI Master
2.1 添加 IP Core
1). 添加 JTAG to AXI Master v1.2 IP Core:
2). 下载 bitstream 后,可以看到该调试核:
2.2 基本TCL命令
2.2.1 复位 JTAG-to-AXI Master
在创建并发出传输事务之前执行:
reset_hw_axi [get_hw_axis hw_axi_1]
2.2.2 创建并运行写入传输事务
create_hw_axi_txn \
write_txn [get_hw_axis hw_axi_1] \
-type WRITE \
-address 4000_0000 \
-len 1 \
-data {12345678} \
-force
run_hw_axi [get_hw_axi_txns write_txn]
- write_txn,用户定义的传输事务名称
- [get_hw_axis hw_axi_1] ,返回 hw_axi_1 对象
- -address 40000000 是起始地址
- -len 1,会将 AXI 突发长度设置为 1 个字
- -data {12345678},“-data” 为十六进制
2.2.3 创建并运行读取传输事务
create_hw_axi_txn \
read_txn [get_hw_axis hw_axi_1] \
-type READ \
-address 4000_0000 \
-len 1 \
-force
run_hw_axi [get_hw_axi_txns read_txn]
---
INFO: [Labtoolstcl 44-481] READ DATA is: 00000003
- read_txn,用户定义的传输事务名称
- [get_hw_axis hw_axi_1] ,返回 hw_axi_1 对象
- -address 4000_0000 是起始地址
- -len 1,会将 AXI 突发长度设置为 1 个字
- INFO 为读取到的数据。
2.2.4 命令列表
| Tcl 命令 | 描述
|----------------------|------------------------------------------------------------------
| create_hw_axi_txn | 创建硬件 AXI 传输事务对象。
| delete_hw_axi_txn | 删除硬件 AXI 传输事务对象。
| get_hw_axi_txns | 获取硬件 AXI 传输事务对象列表。
| get_hw_axis | 获取硬件 AXI 对象列表。
| refresh_hw_axi | 刷新硬件 AXI 对象状态。
| report_hw_axi_txn | 报告已格式化的硬件 AXI 传输事务数据。
| reset_hw_axi | 复位硬件 AXI 核状态。
| run_hw_axi | 在对应 hw_axi 对象中运行硬件 AXI 读写传输事务并更新传输事务状态。
2.3 帮助信息
查看帮助信息
create_hw_axi_txn -help
---
Description:
Create hardware AXI transaction object
Syntax:
create_hw_axi_txn [-address <arg>] [-data <arg>] [-size <arg>] -type <arg>
[-len <arg>] [-burst <arg>] [-cache <arg>] [-id <arg>]
[-force] [-quiet] [-verbose] <name> <hw_axi>
Returns:
New hardware AXI transaction object.
Usage:
Name Description
-----------------------
2.4 创建TCL读写程序
2.4.1 Read proc
读取一个数据字长(DataBit = 32)。
proc read {address} {
# 移除地址中的 "0x" 前缀(如果存在)和任何下划线
set address [string map {"0x" "" "_" ""} $address]
# 创建读事务
create_hw_axi_txn -quiet -force rd_tx [get_hw_axis hw_axi_1] -address $address -len 1 -type read
run_hw_axi -quiet rd_tx
# 在返回的数据上加上前缀 '0x'
return 0x[get_property DATA [get_hw_axi_txn rd_tx]]
}
使用说明:
read 0x4000_0000
---
0x00000001
2.4.2 Write proc
写入一个数据字长(DataBit = 32)。
proc write {address value} {
# 移除地址中的 "0x" 前缀(如果存在)和任何下划线
set address [string map {"0x" "" "_" ""} $address]
# 创建写事务
create_hw_axi_txn -quiet -force wr_tx [get_hw_axis hw_axi_1] -address $address -data $value -len 1 -type write
run_hw_axi -quiet wr_tx
}
使用说明:
write 0x4000_0000 0x0000_0003
错误提示:
ERROR: [Labtoolstcl 44-224] Invalid option value 'wr_tx' specified for 'hw_axi_txns'.
原因:write 0x4000_0000 0x0000_00003,第二个参数为需要写入的数据,误打多了一位。更正后错误提示消失。
2.4.3 创建复杂过程
创建复杂过程,调用 2.4.2 Write proc 中定义的写过程,实现 LED 闪烁。
proc test_gpio {gpio_BA} {
while {1} {
write $gpio_BA 0x0000_0003
after 1000
write $gpio_BA 0x0000_0000
after 1000
}
}
test_gpio 0x4000_0000
说明:
向 test_gpio 过程中传入gpio 基地址(Base Address)即可。
3. 示例
3.1 AXI-GPIO IP Core
3.1.1 寄存器描述
1)AXI GPIO 寄存器描述
| Address Space Offset | Register Name | Access Type | Default Value | Description
|----------------------|---------------|-------------|---------------|------------------------------------------
| 0x0000 | GPIO_DATA | R/W | 0x0 | Channel 1 AXI GPIO Data Register.
| 0x0004 | GPIO_TRI | R/W | 0x0 | Channel 1 AXI GPIO 3-state Control Register.
| 0x0008 | GPIO2_DATA | R/W | 0x0 | Channel 2 AXI GPIO Data Register.
| 0x000C | GPIO2_TRI | R/W | 0x0 | Channel 2 AXI GPIO 3-state Control.
| 0x011C | GIER | R/W | 0x0 | Global Interrupt Enable Register.
| 0x0128 | IP IER | R/W | 0x0 | IP Interrupt Enable Register (IP IER).
| 0x0120 | IP ISR | R/TOW | 0x0 | IP Interrupt Status Register.
2)AXI GPIO 三态寄存器描述
| Bits | Field Name | Access Type | Reset Value | Description
|---------------------|------------|-------------|----------------------|----------------------
| [GPIOx_Width-1:0] | GPIOx_TRI | Read/Write | Default Tri State |0 = output, 1 = input.
3.1.2 TCL 命令
见 2.2 基本TCL命令。
proc write {address value} {
set address [string range $address 2 [expr {[string length $address]-1}]]
create_hw_axi_txn -quiet -force wr_tx [get_hw_axis hw_axi_1] -address $address -data $value -len 1 -size 32 -type write
run_hw_axi -quiet wr_tx
}
write 0x4000_0004 0x0000_0000 # 设置 GPIO 为输出
write 0x4000_0000 0x0000_0003 # 设置 GPIO 状态。
3.2 驱动 HLS IP
3.2.1 HLS IP
功能:使用 ap_ctrl_hs 协议,控制接口使用 AXI_Llite。
启动该 HLS IP 后,内部代码执行一次,即 led_state 翻转,并传递给 led 顶层接口。
#include <ap_int.h>
void blink_counter(ap_uint<1> *led)
{
#pragma HLS INTERFACE mode=ap_none port=led register
#pragma HLS INTERFACE mode=s_axilite port=return
static ap_uint<1> led_state = 0;
led_state = ~led_state;
*led = led_state;
}
* REGISTER
+-----------+---------+----------+
| Interface | Mode | Bitwidth |
+-----------+---------+----------+
| led | ap_none | 1 |
+-----------+---------+----------+
* TOP LEVEL CONTROL
+-----------+------------+-----------+
| Interface | Type | Ports |
+-----------+------------+-----------+
| ap_clk | clock | ap_clk |
| ap_rst_n | reset | ap_rst_n |
| interrupt | interrupt | interrupt |
| ap_ctrl | ap_ctrl_hs | |
+-----------+------------+-----------+
3.2.2 Block Design
1)构建 Block Design 原理图
2)配置 AXI 总线地址
3.2.3 寄存器描述
// ==============================================================
// control
// 0x0 : Control signals
// bit 0 - ap_start (Read/Write/COH)
// bit 1 - ap_done (Read/COR)
// bit 2 - ap_idle (Read)
// bit 3 - ap_ready (Read/COR)
// bit 7 - auto_restart (Read/Write)
// bit 9 - interrupt (Read)
// others - reserved
// 0x4 : Global Interrupt Enable Register
// bit 0 - Global Interrupt Enable (Read/Write)
// others - reserved
// 0x8 : IP Interrupt Enable Register (Read/Write)
// bit 0 - enable ap_done interrupt (Read/Write)
// bit 1 - enable ap_ready interrupt (Read/Write)
// others - reserved
// 0xc : IP Interrupt Status Register (Read/COR)
// bit 0 - ap_done (Read/COR)
// bit 1 - ap_ready (Read/COR)
// others - reserved
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)
3.2.3 TCL 命令
烧写 bitstream 后,即可通过 TCL 命令控制该 HLS IP。
proc write {address value} {
set address [string range $address 2 [expr {[string length $address]-1}]]
create_hw_axi_txn -quiet -force wr_tx [get_hw_axis hw_axi_1] -address $address -data $value -len 1 -size 32 -type write
run_hw_axi wr_tx
}
write 0x0000_0000 0x0000_0001
3.3 AXI UART Lite
3.3.1 Block Design
1)构建 Block Design 原理图
2)配置 AXI 总线地址
3.3.2 AXI UART 寄存器描述
《DS741 - AXI UART Lite v1.02a》
| Offset (hex) | Register Name | Access Type | Default Value (hex) | Description |
|--------------|---------------|-------------|---------------------|--------------------------------|
| 0x0 | Rx FIFO | Read | 0x0 | Receive data FIFO |
| 0x4 | Tx FIFO | Write | 0x0 | Transmit data FIFO |
| 0x8 | STAT_REG | Read | 0x4 | UART Lite status register |
| 0xC | CTRL_REG | Write | 0x0 | UART Lite control register |
Status Register (STAT_REG)
Control Register (CTRL_REG)
3.3.3 TCL 命令
1)定义 TCL 过程
proc read {address} {
# 移除地址中的 "0x" 前缀(如果存在)和任何下划线
set address [string map {"0x" "" "_" ""} $address]
# 创建读事务
create_hw_axi_txn -quiet -force rd_tx [get_hw_axis hw_axi_1] -address $address -len 1 -type read
run_hw_axi -quiet rd_tx
# 在返回的数据上加上前缀 '0x'
return 0x[get_property DATA [get_hw_axi_txn rd_tx]]
}
proc write {address value} {
# 移除地址中的 "0x" 前缀(如果存在)和任何下划线
set address [string map {"0x" "" "_" ""} $address]
# 创建写事务
create_hw_axi_txn -quiet -force wr_tx [get_hw_axis hw_axi_1] -address $address -data $value -len 1 -type write
run_hw_axi -quiet wr_tx
}
# 定义一个过程 string2hex,输入参数为 s,作用是将字符串转换为十六进制格式
proc string2hex s {
# 将字符串 s 转换为 UTF-8 编码,然后使用 binary scan 命令将其转换成十六进制字符串
binary scan [encoding convertto utf-8 $s] H* hex
# 使用 regsub 命令将连续的两个十六进制数字之间添加一个空格,以便于后续处理
regsub -all (..) $hex {\1 }
}
# 定义一个过程 print,输入参数为 UART 地址和 string,用于将字符串通过 UART 接口按字符发送
proc print {address string} {
# 移除地址中的 "0x" 前缀(如果存在)和任何下划线
set address [string map {"0x" "" "_" ""} $address]
# 调用 string2hex 过程将字符串转换为十六进制,并去除前后空格,然后按空格分割成列表
set hex_string [split [string trim [string2hex $string]] " "]
# 遍历每个十六进制字符
foreach char $hex_string {
# 向 UART 接口写入数据,这里的写入命令为假设的 write,具体实现需根据实际情况调整
write $address 000000$char
# 每发送一个字符后暂停10毫秒
after 10
}
}
2)写入单个数据
0x48 对应的 ASCII 码为 'H':
write 0x4060_0004 0x0000_0048
3)读取单个数据
通过串口调试小助手,发送 'I',0x49。
分别在发送前后读取状态寄存器:
# 发送前
read 0x4060_0008
---
0x00000004
~~~~~~~~~~~~~~~~~~~~~
# 发送后
read 0x4060_0008
---
0x00000005
可以看到 Rx FIFO Valid Data 有效,即有数据到达。
读取数据:
read 0x4060_0000
---
0x00000049
4)发送字符串
print 0x4060_0004 "Hello"
3.4 AXI IIC IP Core
3.4.1 Block Design
1)构建 Block Design 原理图
2)配置 AXI 总线地址
3.4.2 AXI IIC 寄存器描述
| Address Space Offset | Register Name | Description |
|----------------------|-----------------|----------------------------------------------------------|
| 01Ch | GIE | Global Interrupt Enable Register |
| 020h | ISR | Interrupt Status Register |
| 028h | IER | Interrupt Enable Register |
| 040h | SOFTR | Soft Reset Register |
| 100h | CR | Control Register |
| 104h | SR | Status Register |
| 108h | TX_FIFO | Transmit FIFO Register |
| 10Ch | RX_FIFO | Receive FIFO Register |
| 110h | ADR | Slave Address Register |
| 114h | TX_FIFO_OCY | Transmit FIFO Occupancy Register |
| 118h | RX_FIFO_OCY | Receive FIFO Occupancy Register |
| 11Ch | TEN_ADR | Slave Ten Bit Address Register |
| 120h | RX_FIFO_PIRQ | Receive FIFO Programmable Depth Interrupt Register |
| 124h | GPO | General Purpose Output Register |
| 128h | TSUSTA | Timing Parameter Register |
| 12Ch | TSUSTO | Timing Parameter Register |
| 130h | THDSTA | Timing Parameter Register |
| 134h | TSUDAT | Timing Parameter Register |
| 138h | TBUF | Timing Parameter Register |
| 13Ch | THIGH | Timing Parameter Register |
| 140h | TLOW | Timing Parameter Register |
| 144h | THDDAT | Timing Parameter Register |
3.4.3 TCL 命令
4. 总结
- JTAG to AXI Master 功能简介
- 在 Vivado 中添加该 IP
- 基本 TCL 操作命令
- 三个示例
- 通过 JTAG to AXI 控制 AXI GPIO
- 通过 JTAG to AXI 控制 AXI IIC
- 通过 JTAG to AXI 控制 HLS IP Core
参考列表:
1)UG908
Programming and Debugging (UG908)https://docs.amd.com/r/en-US/ug908-vivado-programming-debugging/Hardware-System-Communication-Using-the-JTAG-to-AXI-Master-Debug-Core2)Xilinx Wiki - JTAG to AXI
Xilinx Wiki - JTAG to AXIhttps://xilinx-wiki.atlassian.net/wiki/spaces/A/pages/64488613/Using+the+JTAG+to+AXI+to+test+Peripherals+in+Zynq+Ultrascale