概述
本文档描述了基于JTAG协议的Zynq SoC重构加载控制逻辑。该控制器使用Verilog语言实现,可部署于CPLD或FPGA平台,负责加载Zynq器件的PL端和PS端程序。当前实现中,PL端支持全局配置比特流文件的加载;PS端支持加载并运行Zynq FSBL(First Stage Bootloader)和u-boot启动程序,并且在FSBL加载完成后,能够加载并执行任意的ELF格式可执行文件映像。
完整工程文件下载:Verilog实现JTAG加载重构PS PL源码 (点击蓝色字体获取)
取件码:6qhr
一、介绍
Zynq SoC的常规启动模式包括QSPI、SD卡等,其中JTAG启动模式通常用于与调试主机的连接,配合Vivado和SDK软件加载需要调试的程序。本文介绍的控制器能够实现JTAG启动模式下的无外部干预加载运行,适用于Zynq硬件设备的备份启动、量产测试等场景。
理解本文内容要求读者具备对JTAG协议时序及其状态机的基本了解,并熟悉Zynq SoC的功能架构及PL/PS之间的关系。此外,读者还应了解Zynq BootROM、FSBL和u-boot的功能及其启动流程。这些内容在我之前的文章也都进行过讲解,不懂的可以去翻阅一下之前的文章。
用户需自行准备适用于PL配置的bitstream文件,以及FSBL和u-boot的ELF文件。不同硬件电路的映像文件不可互换。
二、基本原理
Zynq器件中的调试接口为JTAG,按照协议,共串联了两个JTAG控制器,其一为Xilinx TAP控制器,用于对PL部分进行操作;其二为ARM DAP控制器,用于对PS部分进行操作。两者除底层JTAG协议外,工作方式完全独立,需要按照各自的控制协议进行访问。
Xilinx TAP是第一个设备,其IR长度为6bit,IDCODE为0x23727093(XC7Z045,其他设备会不同)。TAP的主要参考资料为:
- 《UG470 - 7 Series FPGAs Configuration User Guide》
ARM DAP是第二个设备,其IR长度为4bit。IDCODE为0x4ba00477。DAP的主要参考资料为:
- 《ARM Debug Interface Architecture Specification ADIv5.0 to ADIv5.2》
- 《ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition》
Zynq的JTAG内部连接关系如下,正常模式下使用的是PL JTAG接口,MIO PJTAG和EMIO PJTAG都是未选通的。由于JTAG的IR和DR是LSB First的移位寄存器,TDI上先输出的比特进入到TAP,后输出的进入到DAP。
2.1 JTAG接口
JTAG的基本时序逻辑如下:
Xilinx TAP和ARM DAP均符合上述时序。
在之前的文章也有所介绍,在这里就不在进行讲解,可以翻阅一下之前的文章
2.2 TAP控制器
Xilinx TAP的实现相对简单,严格按照UG470 Table-10-4的操作序列执行即可。
在之前的文章也有所讲解,大家可以去看一下,本文章主要讲解DAP控制器的原理和实现。
2.3 DAP控制器
ARM的DAP控制器相对复杂。首先DAP是一个通用规范,所有ARM结构处理器都采用这个接口作为调试用途。但每个ARM核心架构的调试寄存器接口均不同,需要参照各自的手册。就Zynq而言,应参照ARMv7-A。
2.3.1 DAP接口
DAP接口对应ARM Debug Interface中的JTAG-DP。DAP接口包括一个DP和若干个AP。Zynq的实现提供了两个AP,其中AP0可以访问AHB系统总线,AP1通过APB接口访问Cortex-A的Debug接口。理论上AP0可以对整个地址空间进行操作,但缺少官方说明,目前所有的编程器都是采用通用方式,通过AP1接口间接访问所有资源。
DAP上实现的指令清单:
表 1 DAP JTAG IR指令清单
IR指令 | 二进制值 | DR位宽 | 用途 |
ABORT | 1000 | 35 | 中止指令 |
DPACC | 1010 | 35 | 访问DP |
APACC | 1011 | 35 | 访问AP |
IDCODE | 1110 | 32 | 读取IDCODE |
BYPASS | 1111 | 1 | BYPASS模式 |
主要操作通过DPACC和APACC指令进行。DAP的主要访问数据位宽是35位,其中前3位是操作码,后32位是数据。所有读写都是以32bit为单位。
表 2 DPACC和APACC指令的DR数据格式
DATA[34:3] | DATA[2:1] | DATA[0] |
32位数据 | 访问地址,需要*4作为实际地址 | 0 - 读操作 1 - 写操作 |
MSB后传输 | LSB先传输 |
根据DPACC或者DPACC指令,DATA[2:1]*4表示的地址对应寄存器定义为:
表 3 DP和AP的寄存器清单
DPACC | 地址 | 寄存器 | 功能 |
0x4 | CTRL/STAT | 控制/状态 | |
0x8 | SELECT | 选择AP通道 | |
0xC | RDBUFF | 读取前一次读操作的结果 | |
APACC | 地址 | 寄存器 | 功能 |
0x0 | CSW | 访问控制 | |
0x4 | TAR | 目标地址 | |
0x8 | RSV | ||
0xC | DRW | 读写数据 |
DPACC指令对应的寄存器主要进行DAP接口的功能控制如使能和禁用等。SELECT寄存器选择访问哪个AP及AP的哪个bank。
APACC指令用于访问SELECT选定的AP,其中TAR用于设定APB总线地址,DRW则为读写的数据。CSW控制访问属性如地址自增等。
通过DPACC+APACC配合使用,可以间接访问APB上按地址映射的资源,也就是Cortex-A的Debug接口。
DP和AP的详细定义参见《ARM Debug Interface Architecture Specification ADIv5.0 to ADIv5.2》。关于AP的实现信息参见《UG585 - Zynq 7000 SoC Technical Reference Manual》Chapter 27 JTAG and DAP Subsystem。
2.3.2 ARM Debug接口
大部分ARM处理器都提供了Debug接口,其中包括一定数量的寄存器可以进行调试相关的操作。具体到Zynq,其实现了Cortex-A的Debug Interface Registers。Debug接口的具体定义参见《ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition》 Chapter C6 Debug Register Interfaces.
表 4 ARM Debug接口主要寄存器清单
地址偏移量 | 寄存器 | 功能 |
0x80 | DTRRX | 用于配合指令进行Host到CPU的数据传递 |
0x84 | ITR | 用于写入要执行的指令机器码 |
0x88 | DSCR | 调试状态和控制寄存器 |
0x8C | DTRTX | 用于配合指令进行CPU到Host的数据传递 |
0x90 | DRCR | 调试运行控制寄存器,控制Halt和Restart |
zynq包括两个Cortex-A核心,每个核心有一套独立的Debug寄存器接口,可以单独控制。Zynq的两个核心的Debug接口APB地址分配未在官方文档提及,但通过解析源码得到以下信息:
表 5 Zynq Debug接口APB地址映射
CPU | Debug接口基地址 | 功能 |
CPU.0 | 0x80090000 | CPU0 Debug接口 |
CPU.1 | 0x80092000 | CPU1 Debug接口 |
由于启动阶段仅使用CPU0运行fsbl和u-boot,所以基本上只使用位于0x80090000的CPU0 Debug接口。例如:APACC的TAR寄存器写入0x80090080是访问CPU0.DTRRX;写入0x80090090是访问CPU0.DRCR。
利用上述Debug接口寄存器可以对CPU的运行/挂起进行控制,并通过数据传递寄存器和指令寄存器执行任意CPU指令。
2.3.3 C14协处理器
利用ITR寄存器可以执行任意ARM指令。对于调试功能来说最常用的是CP14指令。CP14指ARM第14号协处理器,该协处理器用于Debug功能,主要是在Host和CPU之间传递数据。利用CP14指令,可以在DTRRX和CPU通用寄存器(R0~R15)之间传递数据。
CP14指令一共有5条:
表 6 CP14指令集概要
指令 | 功能 |
CDP | 协处理器寄存器到协处理器寄存器的数据操作 |
LDC | 将源寄存器内容所指的存储器数据读取到目标寄存器 |
STC | 将源寄存器内容写入到目标寄存器内容所指的存储器地址 |
MCR | 将ARM处理器源寄存器内容传送到协处理器目标寄存器 |
MRC | 将协处理器源寄存器内容传送到ARM处理器目标寄存器 |
加载功能主要实现的是将程序区段(segment)写入到其对应的内存地址。这个目标可以利用STC指令实现。ARM为了方便调试加载操作,在DSCR寄存器设置中,提供了FAST_MODE,在该模式下起始地址首先写入R0寄存器,然后STC指令写入ITR,之后的每次DTRRX写入都会自动执行STC指令并自增地址,从而顺序写入程序数据。
完成程序写入内存后,再将程序入口地址写入R0寄存器,并执行一条通用指令“B0”,表示跳转到R0寄存器指向的地址运行。然后设置DRCR为Restart,程序将从设定的入口地址开始执行。
三、总结
本篇文章详细介绍了基于JTAG接口的zynq重构加载的理论部分,重点讲解了DAP接口、ARM Debug接口及C14协处理器指令的工作原理,并阐述了如何通过JTAG进行Zynq的程序加载和调试控制。通过深入分析Zynq的调试寄存器及其操作方式,本文为开发者提供了理解Zynq调试架构和调试流程的理论框架。
下一篇将发布关于Verilog代码实现的文章,详细介绍如何基于本文所述的理论内容,使用Verilog语言实现相关的Zynq控制器。这一实现部分将深入探讨Verilog代码的具体设计和应用,帮助读者进一步掌握如何在硬件层面上实现JTAG启动和调试控制。
敬请期待下一篇文章,进一步了解Verilog代码实现的技术细节。
如有兴趣进一步深入了解FPGA和Zynq设计方面的应用,欢迎关注相关技术分享和实际项目案例,涵盖多种规模的设计实践。通过分享实际设计经验,帮助开发者更高效地实现各种定制化的硬件解决方案
Verilog代码实现文章已经更新!! 下面为快捷链接
基于Verilog实现通过JTAG接口对zynqPS和PL程序重构 ------代码实现部分-优快云博客
完整工程文件下载:Verilog实现JTAG加载重构PS PL源码 (点击蓝色字体获取)
取件码:6qhr
如果感觉文章对您有用,麻烦三连支持一下,方便下次用到的时候,就可以快速找到我,非常感谢您的支持!!!