彻底掌握Quartus——虚拟JTAG篇

Altera的FPGA支持多种调试工具,其中最为大家所熟知的是Signaltap,虽然Signaltap支持条件触发、保存波形等强大的功能,但是,它也只能看个波形而已啊。

如果我要跟FPGA内部的逻辑交换数据,是否有个简便的方法?

有的,它就是虚拟JTAG。虚拟JTAG可以通过TCL脚本在线地把PC机的数据写入到FPGA内部或者从FPGA内部读出并传到PC机。这样,在调整算法参数(如PID的参数整定)的时候,无需多次综合。此外,只要你会用TCL的TK图形库,就能利用虚拟JTAG做上位机。

推荐《TCL/TK入门经典》、《虚拟JTAG教学视频》、《虚拟JTAG博客》,还有Altera的《虚拟JTAG用户手册》、《QuartusII脚本参考手册》。

上面这些视频、资料,已经把原理说得非常清楚了,这里不再重复,而是给出一个最简单的例子。

1、新建一个虚拟JTAG的IP核。

建议手动设定虚拟JTAG的索引号(index),这里设为0,记住索引号,后面有用。如下图所示。


下图这一步是设置仿真激励,目前我们不需要仿真,可以直接点finish,生成IP核。


2、建个verilog文件,代码如下。注意例化虚拟JTAG的名称。

module vjtag (
input clock,
output reg [7:0] my_counter='b0
);

always @ (posedge clock)
    if (load && e1dr)     // decode logic: used to load the counter my_counter
        my_counter <= tmp_reg;
    else
        my_counter <= my_counter;

// Signals and registers declared for VJI instance
wire tck, tdi;
reg tdo='b0;
wire cdr, eldr, e2dr, pdr, sdr, udr, uir, cir;
wire ir_in;

// Instantiation of VJI
vir_jtag my_vji(
.tdo (tdo),
.tck (tck),
.tdi (tdi),
.tms(),
.ir_in(ir_in),
.ir_out(),
.virtual_state_cdr (cdr),
.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)
);

// Declaration of data register
reg [7:0] tmp_reg='b0;

// Deocde Logic Block
// Making some decode logic from ir_in output port of VJI
wire load;
assign load = ir_in;

// Bypass used to maintain the scan chain continuity for
// tdi and tdo ports
reg bypass_reg='b0;
always @ (posedge clock)
    bypass_reg <= tdi;

// Data Register Block
always @ (posedge tck)
if ( load && sdr )
    tmp_reg <= {tdi, tmp_reg[7:1]};

// tdo Logic Block
always @ (*)
    if(load)
        tdo <= tmp_reg[0];
    else
        tdo <= bypass_reg;

endmodule

3、锁好时钟引脚,综合,再调用Signaltap,采集my_counter信号,再综合下载代码。如下图所示。


4、在上面的工程目录下,新建一个tcl脚本,这里是vji_ctl.tcl。代码如下。

# exec "D:\\altera\\13.0sp1\\quartus\\bin64\\quartus_stp.exe" "-t" "G:\\WorkDir\\ProAltera\\ProAVerilog\\vjtag\\vji_ctl.tcl"

set usb [lindex [get_hardware_names] 0]
set device_name [lindex [get_device_names -hardware_name $usb] 0]

proc push {value} {
    global device_name usb
    if {$value > 256} {
        return "value entered exceeds 8 bits"
    }

    open_device -device_name $device_name -hardware_name $usb
    set push_value [int2bits $value]
    set diff [expr {8 - [string length $push_value]%8}]
    
    if {$diff != 8} {
    set push_value [format %0${diff}d$push_value 0]
    }
    puts -nonewline "push value : "
    puts $push_value

    device_lock -timeout 10000

    device_virtual_ir_shift -instance_index 0 -ir_value 1
    device_virtual_dr_shift -instance_index 0 -dr_value $push_value -length 8

    device_unlock
    close_device
}

proc int2bits {i} {
     set res ""
     while {$i>0} {
         set res [expr {$i%2}]$res
         set i [expr {$i/2}]
     }
     if {$res==""} {set res 0}
     return $res
}

push 2

5、在Quartus里,调出TCL控制台。


因为Quartus 13.0的TCL控制台有bug,不能载入::quartus::project包,所以不能直接在TCL控制台使用该包的命令(如quartus_stp -t a.tcl,会出错),于是,这里使用exec命令,间接调用quartus_stp命令。(网上的例子多数用的是老版本的Quartus,可以载入::quartus::project包,也可以直接使用quartus_stp -t a.tcl命令

在TCL控制台中,使用 exec "D:\\altera\\13.0sp1\\quartus\\bin64\\quartus_stp.exe" "-t" "G:\\WorkDir\\ProAltera\\ProAVerilog\\vjtag\\vji_ctl.tcl"

D:\\altera\\13.0sp1\\quartus\\bin64\\ , 是我的quartus的安装目录,G:\\WorkDir\\ProAltera\\ProAVerilog\\vjtag\\ , 是上面的工程目录。

这两个目录都要按照自己的实际修改,注意:路径分隔符用\\。

然后,回车,正常的话,会输出以下信息。


其中push命令,可以把数据通过虚拟JTAG发到FPGA,load和e1dr信号有效的话,就把数据装载到my_counter。


最后,可以在Signaltap里,看到my_counter的值,有变化。


6、以上例子的使用流程。

只要修改TCL脚本中的push命令后面的参数,保存,再在Quartus的TCL控制台中调用exec命令(使用方向键↑,可以调用以前的命令),就可以把数据发到FPGA的tmp_reg,再利用load和e1dr装载到my_counter。



展开阅读全文
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读