表1 VJ核输入端口
Port Name |
Required |
Description |
Comments |
tdo |
Yes |
Writes to the TDO pin on the device. |
|
ir_out[] |
No |
Virtual JTAG instruction register output. The value is captured whenever virtual_state_cir is high. |
Specify the width of this bus with the SLD_IR_WIDTH parameter.
|
表2 VJ核输出端口:
Port Name |
Required |
Description |
Comments |
tck
|
Yes |
JTAG test clock. |
Connected directly to the TCK device pin. Shared among all virtual JTAG instances. |
tdi
|
Yes |
TDI input data on the device. Used when the virtual JTAG megafunction instance is in when virtual_state_sdr is high.
|
Shared among all virtual JTAG instances. |
ir_in[]
|
No |
Virtual JTAG instruction register data. The value is available and latched when virtual_state_uir is high. |
Specify the width of this bus with the SLD_IR_WIDTH parameter. |
表3 High-level Virtual JTAG State Signals
Port Name |
Required |
Description |
Comments |
virtual_state_cdr |
No |
Indicates that virtual JTAG is in Capture_DR state. |
|
virtual_state_sdr |
Yes |
Indicates that virtual JTAG is in Shift_DR state. |
In this state, this instance is required to establish the JTAG chain for this device. |
virtual_state_e1dr |
No |
Indicates that virtual JTAG is in Exit1_DR state. |
|
virtual_state pdr |
No |
Indicates that virtual JTAG is in Pause_DR state. |
The Quartus II software does not cycle through this state using the TCL command. |
virtual_state_e2dr |
No |
Indicates that virtual JTAG is in Exit2_DR state. |
The Quartus II software does not cycle through this state using the TCL command. |
virtual_state_udr |
No |
Indicates that virtual JTAG is in Update_DR state. |
|
virtual_state_cir |
No |
Indicates that virtual JTAG is in Capture_IR state. |
|
virtual_state_uir |
No |
Indicates that virtual JTAG is in Update_IR state. |
|
上面三个表是VJ核的基本端口描述,在VJ核的user guide或者Quartus II软件的帮助里可以找得到。
关于Virtual JTAG测试平台的建设,主要分两个部分,一个部分是基于FPGA的底层设计,主要就是例化VJ核,以及相关的逻辑接口设计;另外一个部分是应用层的用户接口(GUI)的设计,主要是采用TCL语言设计友好的用户界面。
FPGA的底层逻辑设计,在前面的“如何有效利用Virtual JTAG进行电路调试”一文中有过简略介绍。在那个文章里介绍了如何在FPGA里例化一个FIFO和VJ和进行交互,再通过TCL建立的用户接口经由VJ访问FIFO.
在实际的实践中可以将一些非实时的数据暂存在FIFO里,当需要分析的时候再从FIFO里读出来进行分析。这里我们希望介绍一些相对比较复杂的应用,在本人实际应用中,我在之前基于FIFO的基础上再加入了对FPGA内部寄存器的读写(或者说对一些参数可以进行实时地配置),另外加入了VJ对于FPGA外挂的SDRAM的访问。
前面文章已经介绍了如何例化VJ,这里不赘述,只是需要提醒的是对user来说,逻辑里只有ir_in和tck这两个端口会经常用到,另外作为状态的控制,cdr,cir,sdr,udr,以及uir这几个状态指示引脚在相关的数据或者命令锁存的时候要用到。这里给出一个简单的例子:
------------------------------------------------------
--Tcl只负责发送写命令,写fifo的数据由FPGA自己产生
-------------------------------------------------------
process(clkin,reset)
begin
if reset = '0' then
write_en <= '0';
elsif clkin'event and clkin= '1' then
if ir_in = fifowr_cmd and uir = '1' then
write_en <= '1';
else
write_en <= '0';
end if;
end if;
end process;
ir_in端口当前只是处于FIFO写命令状态(需要注意的是VJ根据ir_in端口宽度可以编码出一定量的命令,比如ir_in为4bit的时候最多支持16个命令,所以在搭建调试平台的时候一定要事先确定好最终你需要的命令数,当然你也可以在不够的时候进行例化修改),那么uir指示了何时可以稳定锁存此命令,这时候就相当于FPGA收到了平台发过来的写FIFO的命令了,那么到底写什么数据呢?这个可以事先约定,或者也可以通过TCL平台传递需要写入的数据,这里是根据此命令,将相关逻辑已经处理好的数据写入FIFO以待后续分析。其他状态以及命令类似处理。对于VJ逻辑模块的设计,主要是VJ核的例化,还有就是VJ各个命令的编码,接着就是对于各个编码好的命令进行相应的解码以及后续处理。比如上述代码中“ir_in = fifowr_cmd”的fifowr_cmd是个常量,是VJ命令的一个编码值,上面给出的代码就是对此命令的部分逻辑处理。
处理VJ逻辑,另外一个部分就是用户逻辑处理,比如上述FIFO的例化以及FIFO的读写控制。这里需要加入的是FPGA内部寄存器的读写控制,以及SDRAM的控制器逻辑代码。当然增加了用户逻辑,相应地也要在VJ逻辑处理里增加相应的命令编码以及解码处理逻辑。
这里增加了VJ与SDRAM的通信,只是为了调试SDRAM控制器,调试结束后,为了节约资源完全可以注释掉VJ相关部分或者全部模块。至于如何在FPGA设计SDRAM的控制器有很多人有过相关的文章,而且Xilinx和ALTERA都有参考设计可以参考,本人也有专门的博文介绍自己的体验,这里也不再赘述。本文最后的问题描述部分给出我在实际项目中使用SDRAM的时候碰到的问题以及解决过程。
FPGA底层逻辑设计好以后,就是搭建应用层的用户界面,其实这两个部分可以同时交互进行,因为随着设计的丰富,你也许要逐步的增加调试项目,也即是要增加VJ的命令端口数目。在前面的两篇“Virtual JATG初探”中对于VJ TCL命令进行了相关的介绍,这里不再赘述。这里给出上述FIFO写的时候对应的VJ TCL代码
;###FIFO Write command.通过tcl发命令给FPGA,让FPGA将FIFO写满。
proc FIFO_Push_CMD {} {
.top.t insert end "\n Command: Single Write FIFO\n"
device_lock -timeout 10000
device_virtual_ir_shift -instance_index 0 -ir_value 1 -no_captured_ir_value
set usedw [device_virtual_dr_shift -instance_index 0 -length 32 -value_in_hex]
device_unlock
set tmp 0x
append tmp $usedw
set usedw [format "%i" $tmp]
set DataWidth 32
set value [.top.slider get]
if {$usedw!=255} {
if {$value > 2097152} {
.top.t insert end "\nvalue entered exceeds 21 bits\n" }
set push_value [int2bits $value]
set diff [expr {21 - [string length $push_value]%21}];#这里的“%”似乎没什么作用(求余数),如果去掉“%21”运行结果无变化,反正就是获取字符长度
if {$diff != 21} {
set push_value [format %0${diff}d$push_value 0]
}
.top.t insert end "$push_value\n"
device_lock -timeout 10000
device_virtual_ir_shift -instance_index 0 -ir_value 4 -no_captured_ir_value
device_virtual_dr_shift -instance_index 0 -dr_value $push_value -length 21 -no_captured_dr_value
device_unlock
} else {
.top.t insert end "\nCan't write the FIFO, for it is full now!\n"
}
}
上述代码中“device_virtual_ir_shift -instance_index 0 -ir_value 4 -no_captured_ir_value”定义了ir_value为4,那么也就是在FPGA中逻辑设计中对于此命令的编码值就是4,也即常量fifowr_cmd等于4.这点一定要注意,TCL和FPGA逻辑对于命令的编码值一定要一一对应,否则就无法正确的进行命令解析以致无法正常的进行调试。
1. 基于FIFO的测试平台
此阶段性测试平台具备以下功能:
1)、具备给FPGA发生一个系统复位功能;
2)、读取FIFO的usedw、full以及empty标志信息;
3)、给FPGA发一个命令,让其将FIFO填满数据;
4)、通过tcl将FIFO里的数据一次读出来;读出来的数据可以显示在当前text框里,同时可以存储在一个文件里供离线分析;
5)、从一个文件里往FPGA的存储器或者外挂的存储器里写入大量的初始数据;
6)、读取系统内部状态标志,一次可以读取32个标志“位”;
7)、向系统写入参数,写入的参数可以通过输入窗口进行设定。
2. 加入SDRAM访问的测试平台
此阶段性测试平台具备以下功能:
1). 加入SDRAM单个写控制按钮,写入的地址和数据通过参数设置窗口设定;目前支持设置的地址和写入的数据是一样的。
2). 加入SDRAM大批量写按钮;写入的数据是通过逐一读取当前目录下的文件里的数据写入,写入的地址根据逐次写入操作加1,起始地址默认是0.
3). 加入SDRAM读按钮,此按钮可以支持单个读,以及批量读1024个地址数据;当滑动条设置为0时为批量读,非0时为单个读;批量读默认从0开始读1024个数据,单个读的地址由参数设置窗口设定。
问题描述
1. VJ测试平台访问SDRAM的问题
上述SDRAM在批次写的时候,第一个数据不是文件里的第一个数据,而是上一次留在SDRAM数据线上的数据;文件里的第一个数据被写入在第二个位置,如图2中的0地址上的数据3不是文件里的第一个数据;而文件里的第一个数据“0000”被写在了地址1位置。经过查时序,这个问题算是找到了,把第一个数据改成x“5555”,为了好看。用signaltap抓了一下发现是在大批次写的时候第一个地址是从1开始而不是0开始,而大批次读的第一个地址是0.如图3所示:
大家看最后一行的“sdr_wr_adr"正好是地址1,而此时的写入数据”data_from_sys“是我定义的第一个数据0x5555,也就是在SDRAM写的时候第一个数据0x5555没有被写入地址0.修改SDRAM的控制器解决此问题,SDRAM的读写均无问题,如图4所示。
图4 解决SDRAM访问问提
2. SDRAM single operation mode下节约访问时间的探讨
SDRAM的Single Write写如图5图所示,从c_state的状态可以看出一次完整的Single Write花费了11个时钟周期,根据SDRAM的时序关系,可以缩短状态C和E(状态E可以省略),至于为何可以缩短可以查相关的SDRAM芯片的数据手册可以得到各个命令的具体时间参数。
修改SDRAM控制器,这里暂时保留状态E,这时候single Write控制时序如图6所示:
同样对于single read模式下,如图7所示,观察状态c_state,发现整个single read需要11个时钟周期,对照SDRAM时序图,可以修改逻辑使单个读减少到6个时钟,即去除图7中的状态A .
图8是修改后的SDRAM单个读时序图,此时没有状态A了 :
coyoo 2015-7-30 09:05
用户1738735 2015-7-29 22:35
用户1738735 2015-7-24 11:28
coyoo 2015-7-24 09:05
用户1738735 2015-7-23 17:06
coyoo 2015-7-23 08:52
用户1738735 2015-7-22 10:52
coyoo 2015-7-22 09:01
用户1738735 2015-7-21 22:28