EDN首页   博客首页 用户登陆  |  注册
aaa
发表于 2010/3/8 18:32:31

1

关于投票

回顾Virtual JTAG在一个项目中的成功应用


        几天前看到特权同学在学习使用Virtual JTAG,心中很是高兴:这么好的一个工具,终于有同行认真对待它,并且开始探索着使用它了。不知道特权同学使用的情况如何。 riple
        这些天在回顾两年前做的一个产品。得益于当时每天都写下的几行工作记录,这个产品的开发过程我还能回忆起来。在这个产品开发的各个阶段,Virtual JTAG和Tcl都发挥了重要作用。投入几天的时间开发一个小工具,在完成后就能持续地产生效益。Virtual JTAG在加快开发速度,提高调试效率方面发挥了重要的作用。 riple
       
        1. 应用场合之一:在开发初期,实现对FPGA外部接口芯片的灵活控制——KSZ8842接口控制台工具。我们的产品需要连接网络,并通过一个带本地接口的三端口交换机芯片KSZ8842实现和宿主机网络的共享。在最初拿到这款芯片的时候,我们很是为它复杂的地址扩展方式和功能配置选项头疼。虽然网站上提供了参考设计和驱动程序,但是我们做的是FPGA直接连接和控制KSZ8842,用C语言写的嵌入式代码帮助不大。 riple
        当时我们最需要的,是通过FPGA灵活地读写KSZ8842的寄存器,尝试交换芯片的各种功能配置,并通过交换芯片的本地接口实现网络报文的收发。我们应用Virtual JTAG,编写了一个简单的Tcl控制台。通过JTAG下载电缆,我们可以从运行在调试PC机上的Tcl控制台读写FPGA的内部逻辑,在FPGA和KSZ8842的接口上产生读写波形,向KSZ8842发送任意地址的读写操作。这一工具除了可以执行简单的单步读写操作,还可以读入一个脚本文件,实现批量的配置输入。利用这个工具,我们打通了从FPGA到网络的数据通路,积累了一系列的配置脚本。这些工作,为后期采用HDL代码编写状态机自动控制KSZ8842打下了坚实的基础。 riple

        2. 应用场合之二:贯穿于开发过程的始终,实现对FPGA外部接口总线读写事务的监听——PATA接口命令捕获和解析工具。在先前开发和调试其它PATA接口的产品时,我们经常需要捕获宿主机给PATA接口发送的命令,并通过对这些命令的内容和先后顺序的分析,推测宿主机BIOS的行为。以前的产品中有一颗嵌入式CPU芯片,通过CPU芯片的串口,这些信息可以很容易地传送到调试PC机上。当前这款产品的全部功能是用FPGA来实现的,没有串口,只能利用FPGA芯片的JTAG口。 riple
        首先在FPGA中捕获并存储宿主机发送给PATA接口的命令,然后应用Virtual JTAG读取FPGA中存储的命令序列,通过JTAG下载电缆传送到调试PC机上察看。借助于运行在调试PC机上的Tcl程序,这些原始的命令序列,可以得到进一步的解析,并且以一种易读易懂的方式呈现给调试者。应用这个工具,我们还捕获了宿主机与真正的硬盘之间传输的数据,其中最有用的是硬盘对宿主机Identify命令返回的硬盘参数信息。这些信息,给我们制定自己的硬盘参数提供了参考。 riple
        与此类似,在采用CPU和FPGA协同工作的嵌入式系统中,使用这一工具也可以从FPGA一侧捕获和解析CPU对FPGA接口上的读写操作。获得的信息可以辅助验证CPU与FPGA协同工作的正确性。 riple
       
        3. 应用场合之三:在开发过程的中后期,实现对尚未开发完成部分的功能模拟,验证已经完成部分的功能,隔离可能的故障点——PATA接口虚拟硬盘工具。在先前的产品中,PATA接口在FPGA上的程序已经开发好了,移植到新的产品上并不困难。PATA接口移植工作的正确性需要尽早验证。仿真验证的速度和覆盖率都有限,最好的验证是上板进行宿主机与PATA接口的硬件实测。但是由于网络接口一侧的开发还在进行中,并且出于隔离故障点的考虑,这时还不能进行集成实测。 riple
        当时我们需要的是抛开网络接口,尽快上板验证PATA接口移植工作的正确性。在上面提到的PATA接口命令捕获和解析工具的基础上,我们开发了基于Virtual JTAG的虚拟硬盘。通过JTAG下载电缆,我们把捕获到的宿主机发送给PATA接口的命令传送到调试PC机上,运行在调试PC机上的Tcl程序把收到的命令解析后分类为读写两类命令。针对读命令,可以读取调试PC机上存储的一个文件,把读取的数据通过JTAG下载电缆返回给PATA接口;针对写命令,可以把宿主机从PATA接口写入给FPGA的的数据,通过JTAG下载电缆传递给调试PC机,这些数据就可以写入到调试PC机上的文件中。这样,就通过Virtual JTAG,在调试PC机上虚拟出了一个可读可写的微型硬盘。 riple
        这个虚拟的微型硬盘虽然速度慢(通过JTAG下载电缆传输大量的数据),但是填补了后端设备尚未开发完成的功能,构成了一个可以实际上板运行的系统。有了这个系统,我们就可以实际调试一个部分完成的产品,尽早发现已经完成部分在实现上的错误。这样做比在仿真环境中调试快得多和实际得多。 riple
        同理,如果网络接口部分先开发完成,也可以不等待PATA接口的开发,采用Virtual JTAG虚拟前端设备的读写请求,进行网络接口部分及上层协议的硬件实测。 riple

        4. Tcl的应用:对上述虚拟硬盘的扩展——模拟服务器网络响应的工具。在网络部分初步开发出来之后,跟服务器之间通过网络的交互测试就是必需的了。由于交互的复杂性,通过仿真来验证是不够的。服务器程序在原有的产品中早就开发成熟并已经长期使用了,但是在服务器上调试新产品的网络部分并不容易,交互的具体内容是看不到,也不容易控制的。 riple
        我们需要的是模拟服务器对被测设备的响应,并获得交互过程中的各种命令参数。针对这一问题,在调试PC机上,我们用Tcl程序实现了对UDP报文的监听解析和返回报文的发送,模拟了服务器对被测设备发送的读写请求的响应。这里虽然没有用到Virtual JTAG,但是这一工具是在上述PATA接口虚拟硬盘工具成功使用的启发下开发的,也通过在调试PC机上读写文件实现了虚拟硬盘,并能在调试PC机上提供详尽的网络报文接收和发送参数。所不同的是,这一次虚拟硬盘的底层传输介质不再是JTAG下载电缆,而是真正的网络;上层的协议也不再是简单的ATA读写命令,而是运行在UDP/IP之上的RPC协议。 riple
        通过这一工具,我们把原本复杂甚至神秘的服务器端操作,详细清晰地呈现在调试者眼前。这个在调试PC机上虚拟的网络硬盘虽然在性能上比不上在服务器上运行的网络硬盘,但是其容量和速度已经可以支持Windows操作系统的安装和启动了。在这一工具的帮助下,我们在开发中及早地实现了集成实测和调试,甚至在服务器宕机数日的情况下都能继续调试和开发。这一工具,进一步演化为演示系统中的服务器端程序,在一台运行Windows操作系统的笔记本上就可以实现Linux服务器的基本功能,简化了演示系统的搭建过程。 riple


       上面这些工具是应用Virtual JTAG和Tcl辅助硬件调试的一个尝试,在我们的开发过程中得到了成功的验证。整理出来,供大家参考。 riple

相关链接:非常有用的Virtual JTAG——比串口还好用学习Tcl(四)——UDP收发包


系统分类: CPLD/FPGA  |  用户分类: Virtual JTAG  |  标签: JTAG Tcl  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(454) | 回复(7)

发表于 2009/1/17 23:28:00

2

关于投票

Quartus II中添加Tk程序的几个关键语句

Quartus II支持Tcl程序并且提供了很多专用的Tcl扩展命令。Virtual JTAG的用户接口就需要通过Tcl和Virtual JTAG的Tcl API来编写。
通过Tcl编写的Virtual JTAG用户接口是通过命令行来实现的,Tcl程序提示并且捕获用户的输入来完成与用户的对话。当需要输入较多的参数时,命令行的串行输入方式效率很低。
Tk(Tool Kit)是基于Tcl的图形程序开发工具箱。通过Tk可以编写简易的用户界面,提高与用户交互的速度,方便用户的使用。
在最近的工作中,我开发了一个Virtual JTAG工具,用于捕获CPU对FPGA寄存器的写入操作。最初只是简单地采用了命令行的提示方式,不方便使用。最近我把这个Tcl程序改写成了Tk程序,给这个工具添加了图形化用户界面。


在改写过程中,我发现通过Quartus II的命令行可执行命令(比如quartus_stp -t)启动包含Tk语句的Tcl脚本时,需要注意两点:
1. 在Tcl脚本中调用Tk语句之前,需要添加一条init_tk命令。不添加这条命令,Quartus II是不能识别Tk语句的。这一问题,在Altera的网站上给出了解释。
2. 在退出Tcl脚本之前,需要添加一条vwait variable命令。如果不添加这条命令的话,Quartus II会认为脚本已经执行完毕,并立即退出。采用vwait命令后,只有当variable取值变为1时,脚本才会正常退出。所以需要初始化该变量为0,在需要退出时置该变量为1。这一问题,在Altera的网站上查不到,我是在Quartus II的安装目录下逐个查找Tcl程序才找到答案的。

以上两点,在编写Modelsim中执行的包含Tk命令的脚本时都是不需要添加的。这与Modelsim的用户界面是采用Tk编写实现的是有关的。

相关链接:
Error: "invalid command name" when running a Tcl script that uses Tk widgets
Debug a microcontroller-to-FPGA interface from the FPGA side GUI界面的源程序可以在这篇文章中找到。

系统分类: CPLD/FPGA  |  用户分类: Virtual JTAG  |  标签: Tk Quartus  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(1187) | 回复(10)

发表于 2008/7/16 22:56:40

2

关于投票

Virtual JTAG仿真要点

半年前应jack0321朋友的要求 riple 就想着要写这个题目,四个月前终于有机会做了仿真,还写了个自动生成测试向量的脚本,后来忙着其他事情,就拖到了现在。 riple

 

VJI的部分功能是通过自定义逻辑来实现的。对VJI仿真的目的就是验证这部分逻辑以及这部分逻辑与用户设计之间配合的正确性。 riple

仿真是上板实测前最重要的一步,仿真都通不过,电路板上能跑通那才叫怪呢。VJI的仿真也不例外,如果不通过仿真验证VJI接口的正确性,而通过实测,甚至是SignalTap II调试的话,麻烦可就大了。在 riple 最初使用VJI时,就是通过实测和SignalTap II来调试VJI的,好在那时用的比较简单,没费太大力气。 riple

Virtual JTAG是支持仿真的。不过,就像Altera所有硬核模块一样,对VJI的仿真是通过行为级模型实现的。与其他硬核模块不同的是,VJI除了和用户逻辑有接口之外,还有一个隐藏起来的“虚拟”接口——JTAG接口。对这个接口的模拟可不太容易做:在真实电路中,这个接口是连接到调试宿主机(PC机)上的,而且它的行为是通过Tcl程序,受到用户的“动态控制”的。 riple

“动态控制”在Modelsim这种编译执行的仿真器中是无法实现的,我目前也不知道哪款仿真工具能够支持这样的用户交互。为了绕开这个难点,VJI的仿真模型采用了“静态控制”的方法。所谓“静态控制”,就是把对VJI的操作,通过参数配置的方式传递给VJI的行为模型,由于参数配置是在编译前指定好的,在仿真过程中不会也不能发生变化,所以是静态的。如果需要更改对VJI的控制,就要重新配置参数,重新编译后才能生效。这样做虽然与真实操作有些差异,但是也足够验证VJI与用户逻辑配合动作的正确性了。 riple

 

费了上面这么些话,才说到重点上。 riple

VJI的行为模型提供了三个参数接口: riple

sld_virtual_jtag_component.sld_sim_action
sld_virtual_jtag_component.sld_sim_n_scan
sld_virtual_jtag_component.sld_sim_total_length

这三个参数分别代表“扫描链操作序列”、“扫描链操作次数”和“扫描链操作总长度”。 riple

其中sld_sim_action比较复杂,由一系列的扫描链操作组成,每一次扫描链操作由4个操作参数组成:time type value length。这四个参数设定了具体一次扫描链操作的相对时间、操作类型(IR/DR)、串行移入数值、串行移入数值的位数(长度)。两个参数之间用逗号分隔,每组参数用括号保持在一起,两组参数之间用逗号隔开。就像下面这个样子: riple

((time,type,value,length),(time,type,value,length),(time,type,value,length))

其余两个参数sld_sim_n_scan和sld_sim_total_length是这一系列扫描链操作的统计信息,可以由第一个参数推算得到。“扫描链操作次数”无需解释,“扫描链操作总长度”是第一个参数中所有length值之和。这两个参数都不区分IR或DR。 riple

 

这些参数就是一组参数化的测试激励。在仿真开始后,这一系列测试激励绕过了VJI的“虚拟”JTAG接口,直接施加到VJI行为模型内部,在VJI的用户逻辑接口产生相应的波形,实现了对VJI的仿真。这一仿真过程与真实的硬件操作有两个不同点:一是激励是静态施加到仿真环境中的,无法实现用户交互,所以需要设计一组最有效的操作参数,保证测试的功能覆盖率;二是仿真过程绕开了真实的JTAG操作,无法验证Tcl脚本与JTAG API的配合。对VJI仿真的主要目的是验证用户自定义扫描链逻辑与VJI的配合正确性,实践证明这一部分逻辑也是最容易出错和难以直接调试的。 riple

 

需要说明的是,实际的JTAG电路运行速度不快,TCK只有不到10MHz的频率。所以仿真中的电路跑起来也不快,需要耐心等待。 riple

 

手工输入上述三个参数非常繁琐,而且容易出错。试试手工生成下面这组参数,嘿嘿,不是很容易吧。

sld_sim_action : (1,1,1,4),(1,2,6,6),(1,1,2,4),(1,2,0,6),(1,1,8,4),(1,2,3,2),(1,1,4,4),(1,2,55aa,10),(1,1,4,4),(1,2,f0f0,10),(1,1,4,4),(1,2,0123,10),(1,1,4,4),(1,2,4567,10),(1,1,4,4),(1,2,89ab,10),(1,1,4,4),(1,2,cdef,10),(1,1,1,4),(1,2,4,6),(1,1,2,4),(1,2,0,6),(1,1,8,4),(1,2,2,2),(1,1,4,4),(1,2,55aa,10),(1,1,4,4),(1,2,55aa,10),(1,1,4,4),(1,2,55aa,10),(1,1,4,4),(1,2,55aa,10),(1,1,1,4),(1,2,4,6),(1,1,2,4),(1,2,0,6),(1,1,8,4),(1,2,2,2),(1,1,4,4),(1,2,55aa,10),(1,1,4,4),(1,2,55aa,10),(1,1,4,4),(1,2,55aa,10),(1,1,4,4),(1,2,55aa,10)
sld_sim_n_scan : 46
sld_sim_total_length : 358

由于有规律可循,可以用Tcl自动生成上面的参数。实际硬件调试时总是需要写一组Tcl脚本来完成对JTAG API的操作和用户交互,可以在这组脚本中生成上述仿真参数。在Tcl脚本中设置一个变量,用于区分是实际调试还是仅生成仿真参数,再编写一组用户操作就可以在实际调试之前得到仿真参数。 riple

系统分类: CPLD/FPGA  |  用户分类: Virtual JTAG  |  标签: JTAG VJI 仿真  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(862) | 回复(0)

发表于 2008/3/5 21:53:47

2

关于投票

从PFL megafunction中学到的Virtual JTAG使用技巧

现在开发的产品需要借用CPLD烧写Nor Flash,可选的方案有两个:采用Altera的Parallel Flash Loader,或者自己用VJTAG做一个。 riple

采用PFL虽然速度够快,但是曾经有过文件不匹配的失败经历,所以采用了后一个方案。CPLD代码和Tcl底层操作很快开发出来了,做软件的同事开发的Tcl用户接口也很容易操作,但是发现烧写速度慢得惊人,只有几kB/s。 riple

同样是采用JTAG电路,甚至原理都一样,为什么效率差这么多?是不是Altera给用户开放的API是慢速的?PFL到底需要怎样的文件格式。为了弄清这些问题,我硬着头皮又把PFL做了一遍。先前采用PFL时没弄清文件格式和烧写起始地址,所以失败了。这次在文件格式上下了些功夫,把原理搞清楚了,下载也就成功了。 riple

烧写虽然成功了,但是我仍然没弄明白占用的逻辑资源差不多,PFL的速度为什么这么快。于是利用周末的时间把PFL生成的代码仔细分析了一遍,还真发现不少提高Virtual JTAG操作效率的窍门: riple

1. IR采用one-hot方式编码,减少了译码逻辑的复杂度。 riple

2. 采用一条专用的IR命令,通过JTAG获得参数化硬件电路的参数值。通过读取硬件电路的参数值,自动保证Tcl脚本与HDL代码中数据宽度等信息的一致性。 riple

3. 对于连续地址写入操作,采用一个计数器产生地址值,而不采用专用IR命令传入地址值。 riple

4. 在数据写入命令的数据移入寄存器中多添加一位,用于产生上述计数器的计数脉冲。 riple

5. 采用TCK同步操作,既可以保证电路在低频率下稳定工作,还省去了外部输入时钟和相应的跨时钟域边沿同步脉冲提取电路。 riple

6. 在PFL的Magawizard界面中,有一个area/speed选项,选中speed模式,还能进一步提高速度。代价是需要采用RAM(CPLD中没有)或LE实现一个FIFO,实现数据的缓冲;围绕着这个FIFO,还要设计两个状态机,一个实现从VJTAG接口向FIFO写入数据的操作,一个实现读取FIFO向Flash接口写入数据的操作。这只是初步分析,我还没能弄清speed模式下的操作细节。 riple

 

PS:PFL需要的文件格式和生成方法我还要另写一篇日志。 riple

参考文件:rar

系统分类: CPLD/FPGA  |  用户分类: Virtual JTAG  |  标签: 无标签  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(733) | 回复(2)

发表于 2008/3/5 21:51:55

2

关于投票

Virtual JTAG仿真要点(附图)

    Virtual JTAG仿真要点图形说明。从下图可以看出Virtual JTAG与Real JTAG的对应关系。下面两幅Modelsim仿真截屏的上半部分是VJI命令发出后Real JTAG的状态变化,下半部分是Virtual JTAG状态机的变化。 riple

一、device_virtual_ir_shift  riple 

点击看大图

    Virtual IR操作对应一次Real IR操作和两次Real DR操作。从图中可以看出Virtual JTAG的ir_in由0000变为0001,这是执行device_virtual_ir_shift命令的结果。从图中还可以看出,device_virtual_ir_shift命令在virtual jtag部分没有对应的操作。也就是说,除了传递Virtual IR值之外,device_virtual_ir_shift命令是无法对用户逻辑产生影响的,我们无法利用device_virtual_ir_shift命令进行用户自定义的操作。 riple

二、device_virtual_dr_shift riple

点击看大图

    Virtual DR操作对应一次Real IR操作和一次Real DR操作。与device_virtual_ir_shift命令不同,device_virtual_dr_shift命令在virtual jtag部分对应一次DR移位操作,这一操作是我们可以用来控制自定义扫描链逻辑的。 riple

 

    需要注意的是,从仿真看来,VJI电路有以下几个特点: riple

    1. TCK信号不是一个标准时钟。除了速度只有10MHz之外,它也不是连续恒定翻转的。 riple

    2. 在一次Virtual DR操作结束后,VJI的状态跳转到udr(update dr),该状态一直持续到下一次VJI操作。所以,采用该信号实现寄存器加载操作不合适,应该代之以e1dr信号。 riple

    3. 从VJI的virtual jtag接口看来,只有device_virtual_dr_shift命令可用于操作自定义扫描链。但是由于VJI还提供了一组real jtag接口(low level 接口),可以利用real jtag接口信号操作自定义扫描链,这样一来,device_virtual_ir_shift命令也可以用于自定义扫描链操作了。然而,这样做并没有资料可以参考,需要三思而后行。 riple

    4. 在virtual jtag接口看到的JTAG接口信号是经过屏蔽的。如第二幅图所示,上半部分Real JTAG接口信号中的tdi信号在下半部分并没有完整出现。其实,Virtual JTAG原本就是Real JTAG的简化和抽象,抽象的结果就是VJI仅仅保留了自定义扫描链操作最本质和必要的接口,而忽略了在空间上和时间上不必要的信息。 riple

 

    Virtual JTAG仿真要点文字说明

系统分类: CPLD/FPGA  |  用户分类: Virtual JTAG  |  标签: 无标签  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(733) | 回复(0)

发表于 2007/5/7 23:20:30

4

关于投票

非常有用的Virtual JTAG——比串口还好用

    今天加了一会儿班,把节前调通的网络接口芯片操作程序整理了一下。 riple

    这个Tcl程序用于控制一个Virtual JTAG接口,通过Virtual JTAG给FPGA输入控制信号,通过FPGA内部的逻辑产生网络接口芯片的控制波形,实现对网络接口芯片的读写操作。 riple

    通过一段时间的调试,当前这个Tcl程序已经比较完善了。在调试过程中,我愈发认识到了Virtual JTAG在FPGA调试中的作用:在没有Virtual JTAG之前,我只能借助于电路板上的按键和串口,或者是一个有串口控制平台的CPU芯片给FPGA施加控制信号;反馈信息只能借助于7段数码管或者串口才能显示。有了Virtual JTAG,复杂的控制输入、详细的反馈信息显示和处理都可以在Tcl中实现,在PC机的命令行中显示。如果核心程序稳定下来,还可以借助Tk制作一个图形化的人机交互界面。Tcl + Virtual JTAG真的是FPGA调试中的绝配。 riple

    采用Virtual JTAG进行调试,适用于渐进式的开发流程。FPGA往往是一个被动系统,没有激励就不会自己动作。当部分代码开发完成后,往往不能独立上板调试:缺乏控制输入和输出显示。即使采用外部辅助电路,也只能实现比较简单的控制和显示功能。采用Tcl + Virtual JTAG,可以对这个尚未完成的系统施加复杂的控制激励,对于反馈的输出也能够进行细致的分析和处理。随着代码逐步完善,可以调整Virtual JTAG的接口,逐步用已经实现的电路代替Tcl的功能,实现渐进式的板级调试和验证。 riple

    从施加激励和检查响应的角度看,Tcl + Virtual JTAG是一种板级的验证平台,就像使用testbench在Modelsim中验证一样。 riple

    需要说明的一点是,上面这句话仅仅强调了VJI调试与Modelsim仿真二者在功能上的近似性。除了上面这一点近似性外,调试与仿真的差异还很多,比如运行速度、控制和观察信号的难易程度、开发成本等等。总体来说,仿真比调试的性价比高得多。采用VJI进行调试仅仅适用于仿真不能胜任的情况,比如仿真模型不存在或功能不完善或者开发仿真模型的成本和难度太大的情况下。再有一种情况是由FPGA对外部的芯片进行主动控制时,由于编写和调试复杂状态机的难度很大,可以考虑用Tcl+VJI模拟需要进行的控制操作,用一种类似于嵌入式软件编程的方法调试外部芯片,待调试成功后再总结操作程序,据此编制控制状态机。

系统分类: CPLD/FPGA  |  用户分类: Virtual JTAG  |  标签: jtag tcl  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(2146) | 回复(0)

发表于 2006/11/13 14:50:57

8

关于投票

第一个有那么点用处的virtualjtag代码

    今天终于把我学到的那么一点点virtual jtag的用法用到了工作中。 riple

    上午,我用virtual jtag做了一个察看计数器的工具,把我们系统中对nand flash擦除操作的计数值传回来显示。以前,这样的工作要么求助于软件人员,要么就得上signal tap。 riple

    一直以来,都很羡慕软件人员可以在串口察看调试信息,并且可以通过宏定义设置调试级别。而我能做的只是signal tap,由于stp文件的可重用性比较差,每次都要重新设置,被我自己都认为是一种比较dirty的做法。 riple

    现在,我可以名正言顺地在开发目录中添加一个debug目录了。下面可以汇集我所做过的各种virtual jtag调试代码,并且可以通过宏定义决定是否加入调试逻辑了。 riple

    传上来一份rar,大家看看。 riple

    第二个有点用的代码rar,以FIFO的方式捕获数据,捕到后可以写到文件中,供进一步分析。大家喜欢的话,一定要学学Tcl。学会了Tcl,就可以DIY EDA了。 riple

 

系统分类: CPLD/FPGA  |  用户分类: Virtual JTAG  |  标签: FPGA jtag  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(1933) | 回复(9)

发表于 2006/11/3 17:29:55

6

关于投票

虚拟JTAG工具在FPGA调试中的应用(续二)

四、 verilog代码分析 riple

    先把关键的verilog代码写在下面。完整的代码在最后,按照我的理解和习惯,对原示例代码的写法作了修改。 riple
wire [3:0] counter1;
reg   [3:0] feed_reg;     // 四位的DR寄存器,用于加载输入值

wire tdi, tck, cdr, cir, e1dr, e2dr, pdr, sdr, udr, uir;
reg   tdo, bypass_reg;
wire [1:0] ir_in;             // 两位的IR寄存器输出,来自my_vji_a
wire sample = ir_in[0];  // IR译码,2'b01表示SAMPLE命令 
wire feed   = ir_in[1];    // IR译码,2'b10表示FEED命令

reg [3:0] offload_reg;    // 四位的DR寄存器,用于输出

/* instantiation of the vji mega functionc */
my_vji_a VJI_INST(
 .ir_out (2'b0), // input to megafunction
 .tdo (tdo),      // input to mega function

 .ir_in (ir_in),   // output from mega function
 .tck (tck),      // output from mega function
 .tdi (tdi),        // output from mgafunction
 
 .virtual_state_cdr (cdr), // output from mega function
 .virtual_state_e1dr(e1dr), // "
 .virtual_state_e2dr(e2dr), //  "
 .virtual_state_pdr (pdr), //  "
 .virtual_state_sdr (sdr), // "
 .virtual_state_udr (udr), //  "

 .virtual_state_uir (uir), //  "
 .virtual_state_cir (cir)); // "

/* 1. Sample Instruction Handler */  
always @ (posedge tck)  // 针对SAMPLE指令的处理
  if ( sample && cdr )
    offload_reg <= counter1;
  else if ( sample && sdr )
    offload_reg <= {tdi, offload_reg[3:1]}; // 典型的移位寄存器操作(MSB to LSB),移位输出counter1的当前值

/* 2. Feed Instruction Handler */
always @ (posedge tck)  // 针对FEED指令的处理
  if ( feed && sdr )
    feed_reg <= {tdi, feed_reg[3:1]}; // 典型的移位寄存器操作(MSB to LSB),移位输入要赋给counter1的初始值
  
/* 3. Bypass register */  // 旁路寄存器,没有针对这个virtual_jtag的操作就旁路
always @ (posedge tck)
  bypass_reg = tdi;

/* 4. Node TDO Output */  // TDO输出选择器,根据IR的不同,选择不同的信号输出
always @ ( sample, feed, feed_reg[0], offload_reg[0], bypass_reg )
begin
  if (sample)
    tdo <= offload_reg[0];
  else if (feed)
    tdo <= feed_reg[0];   // Used to maintain the continuity of the scan chain. // 在移位输入时,也要保证jtag链路有输出
  else
    tdo <= bypass_reg; 
end

    上面代码中,/* Sample Instruction Handler */之后的代码是需要用户自己编写的代码,是使用virtual_jtag的精髓所在,一定要读懂。 riple

    sld_virtual_jtag 的说明中把TAP控制器的状态信号分为High level和Low level。示例代码中使用的是High level部分的信号。High level部分的信号又可以分为DR寄存器操作对应的一组状态信号(6个)和IR寄存器操作对应的一组状态信号(2个)。 riple

    1. DR寄存器操作对应的一组状态是:Capture_DR -> Shift_DR -> Exit1_DR -> Pause_DR -> Exit2_DR -> Update_DR。每一个状态对应一个*dr信号。 riple

    对于数据输出操作(此例中是SAMPLE命令,并行加载,串行输出),需要在Capture_DR状态把被采样的信号并行加载到DR寄存器中,在Shift_DR状态把DR寄存器串行输出到virtual jtag链路的tdo引脚上(同时串行载入tdi引脚的数据),然后遍历余下的状态并不做任何操作。这一过程就是代码中对offload_reg寄存器的操作。 riple

    对于数据输出操作(此例中是FEED命令,串行输入,并行加载),在Capture_DR状态不进行任何操作直接跳转到下一个状态,Shift_DR状态串行载入virtual jtag输入的数据,在Exit1_DR状态把获得的数据并行加载到目标寄存器上,然后遍历余下的状态并不做任何操作。这一过程就是代码中对feed_reg寄存器的操作。 riple

    2. IR寄存器操作对应的一组状态是:Capture_IR -> Shift_IR -> Exit1_IR -> Pause_IR -> Exit2_IR -> Update_IR。由于virtual jtag模块提供了并行的ir_in端口,简化了操作,所以只有首尾两个状态对应*ir信号。 riple

    在这个例子中,只用到了ir_in端口,没有用到IR操作对应的状态及输出信号。这也可以看作是virtual jtag的方便之处。 riple

    3. bypass_reg寄存器提供了jtag链路的第三条通路,在没有针对当前virtual jtag操作的情况下,tdi数据经过一个tck周期的延时输出到tdo引脚。 riple

    4. tdo引脚输出时,需要根据ir_in的取值选择三条通路中的一条,所以这部分代码也是需要用户设计的。  riple

    看懂了这个例子,对virtual jtag的基本输出和输入功能就掌握了。 riple

    下图是用lpm宏单元替换各个功能块后编译得到的RTL视图。相应的代码可以在此rar下载。点击看大图点击看大图。 riple

 

系统分类: CPLD/FPGA  |  用户分类: Virtual JTAG  |  标签: JTAG FPGA  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(1861) | 回复(9)

发表于 2006/11/1 19:22:29

6

关于投票

虚拟JTAG工具在FPGA调试中的应用(续一)

三、 Tcl命令的使用。 riple

    ::quartus::jtag Tcl命令包中的各条命令都有英文注释,这里就不挨个翻译了。 riple

    下面,把用户指南里给出的第一个例子逐句分析一下,后面还会给出一个模板。 riple

    示例如下。其中只给::quartus::jtag Tcl命令包中的命令加上了绿色,其余简单的Tcl命令可以按照E文的意义理解,稍微复杂一些的Tcl命令可以参考相关书籍。为了区别原注释,我的注释一概用红色标出。 riple

 

#### Script begins ######################################################

set loop 3

## 检测下载电缆,从命令行输出检测到的下载电缆名称。原示例只检测USB下载线,我给改了。 ##

# get hardware names : get download cable name
foreach hardware_name [get_hardware_names] {
    puts "\n$hardware_name"
    if { [string match "ByteBlasterMV*" $hardware_name] } {
        set byteblaster_name $hardware_name
    }
}
puts "\nSelect JTAG chain connected to $byteblaster_name.\n";

 

## 检测下载电缆对应的jtag链路,从命令行输出检测到的器件名称。并选中第一个作为操作对象。##


# List all devices on the chain, and select the first device on the chain.
puts "\nDevices on the JTAG chain:"
foreach device_name [get_device_names -hardware_name $byteblaster_name] {
    puts $device_name
    if { [string match "@1*" $device_name] } {
        set test_device $device_name
    }
}
puts "\nSelect device: $test_device.\n";

 

## 打开器件 ##


# Open device
open_device -hardware_name $byteblaster_name -device_name $test_device

 

## 获得器件的jtag编号。需要先发送jtag命令--获取ID,命令值是“6”。然后读取jtag数据,得到32位的ID值。##

## 由于该步骤需要两个操作,这两个操作之间不能插入其他操作,所以需要lock一下。##


# Retrieve device id code.
# IDCODE instruction value is 6; The ID code is 32 bits long.

# IR and DR shift should be locked together to ensure that other applications
# will not change the instruction register before the id code value is shifted
# out while the instruction register is still holding the IDCODE instruction.
device_lock -timeout 10000
device_ir_shift -ir_value 6 -no_captured_ir_value               ## 发送jtag命令 6。注意:这里的jtag是真实的jtag ##
puts "IDCODE: 0x[device_dr_shift -length 32 -value_in_hex]"     ## 获取jtag数据 ##
device_unlock

## real jtag operation completed ##

## 以下是virtual jtag的操作 ##


# SAMPLE instruction samples a 8-bit bus; the captured value shows the number of sample performed.
# FEED instruction supplies a 8-bit value to the logic connected to this instance.
# Both data registers corresponding to the IR are 8 bit wide.

## 循环采样数据部分 ##

# Send SAMPLE instruction to IR, read captured IR for the sampling number.
# Capture the DR register for the current sampled value.

## 设置循环参数 ##
set run_script 0
while {$run_script != $loop} {
    set run_script [expr $run_script +1]
    set counter1 0
    set counter2 1

    ## 获取采样数据 ##

    device_lock -timeout 10000
    while {$counter1!=$counter2} {

        device_virtual_ir_shift -instance_index 0 -ir_value 1                               ## 发送virtual jtag命令 1 ##
        set counter1 [device_virtual_dr_shift -instance_index 0 -length 4 -value_in_hex]    ## 获取virtual jtag数据 ##

        device_virtual_ir_shift -instance_index 1 -ir_value 1                               ## 发送virtual jtag命令 1 ##
        set counter2 [device_virtual_dr_shift -instance_index 1 -length 4 -value_in_hex]    ## 获取virtual jtag数据 ##

        puts "Value of {counter2,counter1} is <$counter2,$counter1>"

        ## 设置延时参数 ##

        set delay 0
        while {$delay != 120000} {
            set delay [expr $delay+1]
        }
        puts ""
    }

    device_unlock

##  交互输入,设定FPGA计数器初值部分 ##


## instead of stopping at the equal value, force a value of supplied by the user in both  counters and then end.
# Send FEED instruction to IR, read a two-digit hex string from the console,
# then send the new value to the DR register.
    puts "\nType in a digit in hexadecimal to update the contents of the counters:"
    gets stdin update_value
    set update_value2 [expr $update_value+1]


    device_lock -timeout 10000
    device_virtual_ir_shift -instance_index 0 -ir_value 2 -no_captured_ir_value ## 发送virtual jtag命令 2 ##
    device_virtual_dr_shift -instance_index 0  -length 4 -dr_value $update_value -value_in_hex -no_captured_dr_value ## 获取virtual jtag数据 ##
    device_virtual_ir_shift -instance_index 1 -ir_value 2 -no_captured_ir_value ## 发送virtual jtag命令 2 ##
    device_virtual_dr_shift -instance_index 1  -length 4 -dr_value $update_value2 -value_in_hex -no_captured_dr_value ## 获取virtual jtag数据 ##
    device_unlock


}
# Close device
close_device

    如果要读懂上述代码,建议按照用户指南中的步骤设置好工程,记得一定要把引脚按照自己电路板的情况分配上(可以不用LED)。先把## real jtag operation completed ##之前的代码运行一下,看看有什么反应。如果反应很好的话,那么祝贺你,你已经克服了对jtag和Tcl的恐惧心理。 riple

    上述代码的组织结构如下: riple

1. 真实jtag操作。 riple

1.1 检测电缆。(如果你用的是并口下载线,并且没有修改原代码的话,在这一步你就会遇到拦路虎) riple

1.2 查找器件。(如果你的电路板上串接了不只一个jtag器件的话,你要修改你的代码,否则这一步也是过不去的) riple

1.3 打开器件。(前两关过去了,这一步应该不成问题) riple

1.4 获得器件的jtag编号。(IDCODE命令)(个人觉得没有什么大用处,也许可以起到初始化IR的作用) riple

 

2. 虚拟jtag操作。 riple  riple

2.1 循环采样计数器值。(SAMPLE命令)(通过jtag链路从FPGA读数据) riple

2.2 设置计数器初值。(FEED命令)(通过jtag链路向FPGA发数据) riple

    需要说明的是,2中的SAMPLE命令(2'b01)和FEED命令(2'b10)是用户自定义的virtual jtag命令(随便定,只要你的verilog代码中是对应译码的就可以),1中的IDCODE命令(在Cyclone器件中是10'b0000000110)是由Altera定义的,返回值是一组32位的二进制数。 riple

    把上面的代码结合着::quartus::jtag Tcl命令包的帮助文件(我已经给了)逐条分析一下,对于::quartus::jtag Tcl命令包的使用就没有问题了。 riple

    我做的一个Tcl模板rar,根据上面代码改的,可以检查jtag链路,并由用户选择使用哪个器件,可以读取一次jtag数据,然后由用户输入一次jtag数据。如果需要循环功能,还要根据上面代码加入Tcl命令。以后有更好的再传上来。 riple

系统分类: CPLD/FPGA  |  用户分类: Virtual JTAG  |  标签: JTAG FPGA  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(2427) | 回复(10)

发表于 2006/10/19 18:30:31

7

关于投票

虚拟JTAG工具在FPGA调试中的应用(待续)

    最近学习了Altera的Virtual JTAG工具的使用。下面是我的使用心得。 riple

 

    Altera在Quartus II 6.0中加入了一个sld_virtual_jtag 参数化宏单元模块,并提供了相应的Tcl程序包。有了这套工具,使用sld_virtual_jtag 和相应的Tcl命令,我们就可以构建自己的虚拟JTAG链路,并进行自定义的JTAG调试了。 riple

一、 相关文件 riple

    后面的链接是Quartus帮助文件中的内容,前两个是我从Help里拷出来用Word保存的html文件,由于里面的一些链接指向本地文件,会被当作危险代码,不理就是了,不是病毒。 riple

  1.     sld_virtual_jtag 的说明:rar。只给出了VHDL的例化方式,对于各个选项的配置给了说明。  riple
  2.     ::quartus::jtag Tcl命令包的说明:rar。每个命令都给了使用的例子,拷到一个空Tcl文件中,保存后用Quartus的Tcl scripts工具运行即可。
  3.   Altera提供的用户指南:太大了传不上来,给个链接,自己下吧。里面有JTAG协议的讲解和两个示例。 riple

二、 Virtual JTAG要点解析 riple

    澄清一个概念:所谓虚拟JTAG,是Altera用PLD上的硬件JTAG电路和可编程逻辑资源搭建的一个IP core。这个IP core实现了JTAG接口电路的功能,但本身不是硬件JTAG电路的一部分,是用可编程逻辑“虚拟”出来的。 riple

    这个IP core有两个接口:一个接口在布局布线时连接到硬件JTAG电路上,用户不可见;一个接口由用户通过电路图或者HDL例化到代码中,并通过这个接口自定义JTAG操作。 riple

    这个IP core的功能 = JTAG信号hub + JTAG TAP控制器 + IR/DR IO。 riple

    用户看到的是虚拟JTAG电路对内的接口,看不到硬件JTAG电路接口;并且这个接口是从JTAG TAP控制器引出的,信号方向和大家通常从外部对JTAG电路的理解不一样,所以容易引起混淆,理解上会有一定的困难。 riple

    用户看到(可以利用)的接口有四组: riple

  1. JTAG协议中的接口(TDI、TDO、TCK)。TDI是IP core的输出;TDO是IP core的输入;没有TMS,这个引脚的功能被另一组接口解析并代替了;TCK是唯一没有变化的引脚。  riple
  2. 命令寄存器接口(IR_IN[]、IR_OUT[])。这组接口是Tcl命令和用户逻辑交互的接口,很有用。也可用来简单地传递数据。  riple
  3. 虚拟JTAG TAP控制器状态接口(virtual_state_...)。这组接口是虚拟JTAG的状态机输出,一个状态对应一个输出,可以看作状态信号灯。这组信号就是TMS的解析。如果需要实现复杂地数据传递功能,一定要理解这组信号的功能。  riple
  4. 硬件JTAG TAP控制器状态接口(jtag_state_...)。这组接口是硬件JTAG的状态机输出。这些功能暂时不会用,可能是用来实现更高级控制和数据传递功能的。 riple

 

    理解虚拟JTAG概念的关键有以下两点: riple

  1. 在IP core的背后有四根看不见的JTAG信号,这四根信号才是我们通常从外部理解的JTAG。  riple
  2. 看得见的TDI和TDO是两根等待连接的信号(就像墙上插座里的两根线),我们通过在这两根线之间或串接或并接或简单或复杂的逻辑,实现我们的JTAG链路。 riple

    理解了这些概念,看懂用户指南应该不成问题了。然后再看示例程序的verilog代码。 riple

    我的一个空想:如果Altera能够把用户不可见的硬件JTAG电路接口开放出来(用户可见),那么用户就可以把这个接口上的标准JTAG接口连接到PLD的引脚上,再把这组引脚连接到外部JTAG电路上,那么这个IP core就不再是“虚拟”的了。 riple

 

相关链接:Actel Application Note:How to Use UJTAG riple

系统分类: CPLD/FPGA  |  用户分类: Virtual JTAG  |  标签: JTAG FPGA  |  来源: 原创  | 

点击查看原文

发表评论 阅读全文(3613) | 回复(9)

Total , Page /