Verilog——JTAG标准的状态机实现

JTAG标准的状态机实现

JTAG作为一项国际标准测试协议(IEEE1149.1兼容),主要用于芯片内部测试和调试。目前的主流芯片均支持JTAG协议,如DSP、FPGA、ARM、部分单片机等。标准的JTAG接口是20Pin,但JTAG实际使用的只有4根信号线,再配合电源、地。目前常见的各种接口形式(20pin、14pin、10pin):

image-20210407200521928

JTAG标准介绍

JTAG的基本原理是在器件内部定义一个TAP(Test Access Port)(测试访问口)通过专用的JTAG测试工具对内部节点进行测试。JTAG测试允许多个器件通过JTAG接口串联在一起,形成一个JTAG链,能实现对各个器件分别测试。JTAG引脚的定义如下列表所示:

  1. TCK:TCK在IEEE1149.1标准里是强制要求的。TCK为TAP的操作提供了一个独立的、基本的时钟信号,TAP的所有操作都是通过这个时钟信号来驱动的;

  2. TMS:TMS在IEEE1149.1标准里是强制要求的。TMS信号在TCK的上升沿有效,用来控制TAP状态机的转换。通过TMS信号,可以控制TAP在不同的状态间相互转换;

  3. TDI:TDI在IEEE1149.1标准里是强制要求的。TDI是数据输入的接口,所有要输入到特定寄存器的数据都是通过TDI接口一位一位串行输入的(由TCK驱动);

  4. TDO:TDO在IEEE1149.1标准里是强制要求的。TDO是数据输出的接口,所有要从特定的寄存器中输出的数据都是通过TDO接口一位一位串行输出的(由TCK驱动);

  5. TRST:可选项,TRST可以用来对TAP控制器进行复位(初始化)。因为通过TMS也可以对TAP控制器进行复位(初始化),所以有四线JTAG与五线JTAG之分;

  6. RTCK:可选项,由目标端反馈给仿真器的时钟信号,用来同步TCK信号的产生,不使用时直接接地;

  7. nSRST:可选性与目标板上的系统复位信号相连,可以直接对目标系统复位。同时可以检测目标系统的复位情况,为了防止误触发,应在目标端是哪个加上适当的上拉电阻;

JTAG标准的信号时序如下图所示:

image-20210407200732304

通过JTAG连接,可以完成如下的功能:

  1. 对所有串接在一起的IC进行引脚连接性测试,确认PCB是否焊接正常;
  2. 对CPU、DSP、FPGA等进行调试;
  3. 通过JTAG对FPGA进行编程。

进行引脚连接测试的JTAG用法如下图所示,各个芯片引脚的连通状态可以一次串接通信到PC的TDO引脚中。

image-20210407200857495

按照菊花链方式串接调试的JTAG用法如下图所示,多个串接在一起的CPU和FPGA都能够一起进行调试和测试。

image-20210407201003247

上图可以看出JTAG的调试原理:

  1. 所有调试芯片的IR寄存器串接在一起,然后进行串行移位,最后,所有数据都进入到JTAG口的TDO中;PC通过对TDO数据的串并转换,获得每个CPU、DPS或FPGA的内部寄存器状态。
  2. PC将需要写入CPU、DSP或FAPG的数据通过并串转换放置到TDI总线上,最后通过状态移位到规定的CPU寄存器上,最后通过TMS制定生效时刻。
  3. TCK就是TDI和TDO的移位时钟,而TMS则是控制指令。

因此,JTAG通过一个标准状态机就能够将CPU/DSP/FPGA的内部状态查明,也能改变内部寄存器内容,这也是一种状态控制原理。在1990年之前,JTAG的状态机基本是由各个厂商自行定义的,但后来出现的IEEE1149.1标准对状态转移过程进行了标准化。在某种意义上讲,JTAG的状态机实现过程是最佳的FSM学习对象。

JTAG状态机设计

JTAG内部的状态转换图如下图所示,其中的状态值可以由读者自行定义,但推荐采用独热编码或者格雷码进行编码。其中连续的5个TMS为1时,就会回到Test-Logic-Reset状态。

image-20210407201448928

下面的代码是实现JTAG功能的FSM部分,该代码已经应用到多款ASIC芯片中,具有较高的研究价值。

//TAP FSM implementation
module tap_FSM #(parameter sync_mode = 1)(
input   tck,
input   trst_n,
input   tms,
input   tdi,
output  byp_out,
output updateIR,reset_n,

output reg  clockDR, updateDR, clockIR, tdo_en, shiftDR,shiftIR,
output  selectIR, sync_capture_en, sync_update_dr, flag,
output [15:0] tap_state
);
//Inter signal declaration
reg [15:0] state;
reg [15:0] next_s;
reg scan_out_a, scan_out_s, updateIR_a;

localparam TEST_LOGIC_RESET = 16'h0001, RUN_TEST_IDLE = 16'h0002, SELECT_DR_SCAN = 16'H0004,
  CAPTURE_DR= 16'h0008, SHIFT_DR = 16'h0010, EXIT1_DR = 16'h0020,PAUSE_DR = 16'h0040,
  EXIT2_DR  = 16'h0080, UPDATE_DR= 16'h0100, SELECT_IR_SCAN = 16'h0200,
  CAPTURE_IR= 16'h0400, SHIFT_IR = 16'h0800, EXIT1_IR = 16'h1000,
  PAUSE_IR  = 16'h2000, EXIT2_IR = 16'h4000, UPDATE_IR= 16'h8000;

assign flag = state[10] || state[11];
wire updateIR_s = state == UPDATE_IR;
assign updateIR   = sync_mode ? updateIR_s : updateIR_a;
assign tap_state= state;

always @(posedge tck or negedge trst_n)
  if ( !trst_n )
    state<=TEST_LOGIC_RESET;
  else
    state<=next_s;

always @(*)
  case(state)
    TEST_LOGIC_RESET: if(tms)
                        next_s=TEST_LOGIC_RESET;
                      else
                        next_s=RUN_TEST_IDLE;
    RUN_TEST_IDLE: if( tms )
                     next_s=SELECT_DR_SCAN;
                   else
                     next_s=RUN_TEST_IDLE;
    SELECT_DR_SCAN: if(tms)
                      next_s=SELECT_IR_SCAN;
                    else
                      next_s=CAPTURE_DR;
    CAPTURE_DR: if(tms)
                  next_s=EXIT1_DR;
                else
                  next_s=SHIFT_DR;
    SHIFT_DR: if(tms)
                next_s=EXIT1_DR;
              else
                next_s=SHIFT_DR;
    EXIT1_DR: if(tms)
                next_s=UPDATE_DR;
              else
                next_s=PAUSE_DR;
    PAUSE_DR: if(tms)
                next_s=EXIT2_DR;
              else
                next_s=PAUSE_DR;
    EXIT2_DR: if(tms)
                next_s=UPDATE_DR;
              else
                next_s=SHIFT_DR;
    UPDATE_DR: if(tms)
                next_s=SELECT_DR_SCAN;
              else
                next_s=RUN_TEST_IDLE;
    SELECT_IR_SCAN:if(tms)
                     next_s=TEST_LOGIC_RESET;
                   else
                     next_s=CAPTURE_IR;
    CAPTURE_IR: if(tms)
                  next_s=EXIT1_IR;
                else
                  next_s=SHIFT_IR;
    SHIFT_IR: if(tms)
                next_s=EXIT1_IR;
              else
                next_s=SHIFT_IR;
    EXIT1_IR: if(tms)
                next_s=UPDATE_IR;
              else
                next_s=PAUSE_IR;
    PAUSE_IR: if(tms)
                next_s=EXIT2_IR;
              else
                next_s=PAUSE_IR;
    EXIT2_IR: if(tms)
                next_s=UPDATE_IR;
              else
                next_s=SHIFT_IR;
    UPDATE_IR: if(tms)
                next_s=SELECT_DR_SCAN;
              else
                next_s=RUN_TEST_IDLE;
  endcase

//FSM outputs
reg rst_n;

//reg  clockDR, updateDR, clockIR, tdo_en, rst_n, shiftDR, shiftIR;
//ClockDR/ClockIR - posedge occurs at the posedge of tck
//updateDR/updateIR - posedge occurs at the negedge of tck
always @( tck or state )begin
    if ( !tck && ( state == CAPTURE_DR || state == SHIFT_DR ))
      clockDR = 0;
    else
      clockDR = 1;

    if ( !tck && ( state == UPDATE_DR ))
      updateDR = 1;
    else
      updateDR = 0;

    if ( !tck && ( state == CAPTURE_IR || state == SHIFT_IR ))
      clockIR = 0;
    else
      clockIR = 1;

    if ( !tck && ( state == UPDATE_IR ))
      updateIR_a = 1;
    else
      updateIR_a = 0;
  end

always  @( negedge tck )
  if ( state == SHIFT_IR || state == SHIFT_DR )
    tdo_en <= 1;
  else
    tdo_en <= 0;

always  @( negedge tck ) 
  if ( state == TEST_LOGIC_RESET )
    rst_n <= 0;
  else
    rst_n <= 1;

always @(negedge tck or negedge trst_n)
  if ( !trst_n )
    shiftDR <= 0;
  else if ( state == SHIFT_DR )
    shiftDR <= 1;
  else
    shiftDR <= 0;

always @(negedge tck or negedge trst_n)
  if ( !trst_n )
    shiftIR <= 0;
  else if ( state == SHIFT_IR )
    shiftIR <= 1;
  else
    shiftIR <= 0;

assign reset_n = rst_n & trst_n;
assign selectIR = state == SHIFT_IR;
assign sync_capture_en = ~(shiftDR | (state == CAPTURE_DR) | (state == SHIFT_DR));
assign sync_update_dr = state == UPDATE_DR;

always @( posedge clockDR )
  scan_out_a <= shiftDR & tdi & ~(state == CAPTURE_DR);

wire nxt_st_3 = (state == SELECT_DR_SCAN) & ~tms;
wire nxt_st_4 = ((state == CAPTURE_DR) & ~tms) || ( state == SHIFT_DR & ~tms);

reg sel;
always @(posedge tck or negedge trst_n)
  if(!trst_n )
    sel <= 0;
  else
    sel <= ~(nxt_st_3 | nxt_st_4);

wire scan_out = sel ? scan_out_s : shiftDR & tdi;
always @(posedge tck )
  scan_out_s <= scan_out & ~(state == CAPTURE_DR);

assign byp_out = sync_mode ? scan_out_s : scan_out_a;

endmodule

对于上述代码,还有一种非常简洁的描述,同样是三段式描述风格,但最重要的组合电路部分可通过手工推导,直接将always描述的组合电路化简为最小逻辑实现代码。

module vjtag (
input   clk,    // Internal clock
input   tdo_mux,// TDO before the negative edge flop
input   bypass, // JTAG instruction=BYPASS
input   tck,    // clock input
input   trst_n, // optional async reset active low
input   tms,    // Test Mode Select
input   tdi,    // Test Data In

output reg tdo, // Test Data Out
output reg tdo_enb,//Test Data Out tristate enable

output  tdi_r1,   // TDI flopped on TCK.
output  tck_rise, // tck rate clock enable
output  captureDR,// JTAG state=CAPTURE_DR
output  shiftDR,  // JTAG state=SHIFT_DR
output  updateDR, // JTAG state=UPDATE_DR
output  captureIR,// JTAG state=CAPTURE_IR
output  shiftIR,  // JTAG state=SHIFT_IR
output  updateIR
);
reg     tck_r1,tck_r2,tck_r3; 
reg     tdi_f_local; //  local version
wire    tdo_enb_nxt; //  D input to TDO_ENB flop
wire    tdo_nxt; //  D input to TDO flop
wire    itck_rise; 
wire    tck_fall; 

reg     [3:0] state; //  current state
wire    a,b,c,d,a_nxt,b_nxt,c_nxt,d_nxt;
assign a = state[0];
assign b = state[1];
assign c = state[2]; 
assign d = state[3];

assign a_nxt=(~tms & ~c & a) |(tms & 	~b)|(tms & ~a)|(tms & 	d & c);
assign b_nxt=(~tms & b & ~a) |(~tms & ~c)|(~tms & ~d & b)|(~tms & ~d & ~a)|(tms & c & ~b)|(tms & d & c & a);
assign c_nxt=(c & ~b)|(c & a)|(tms & ~b);
assign d_nxt=(d & ~c)|(d & b)|(~tms & c & ~b)|(~d & c & ~b & ~a);

assign tdo_enb_nxt = state == 4'b0010 | state == 4'b1010 ? 1'b1 : 	1'b0; 
assign captureIR = state == 4'b1110 ? 1'b1 : 	1'b0; 
assign shiftIR = state == 4'b1010 ? 1'b1 : 	1'b0; 
assign updateIR = state == 4'b1101 ? 1'b1 : 1'b0; 
assign captureDR = state == 4'b0110 ? 1'b1 : 	1'b0; 
assign shiftDR = state == 4'b0010 ? 1'b1 : 	1'b0; 
assign updateDR = state == 4'b0101 ? 1'b1 :	1'b0; 
assign tdo_nxt = bypass == 1'b1  &  state == 4'b0010 ? tdi_f_local : 	tdo_mux; 
assign tdi_r1 = tdi_f_local; 

always @(posedge clk) begin : rtck_proc
  tck_r3 <= tck_r2;	
  tck_r2 <= tck_r1;	//synchronizers for edge detection
  tck_r1 <= tck;	
end
assign tck_rise = itck_rise; 
assign itck_rise = tck_r2  &  ~tck_r3; 
assign tck_fall = ~tck_r2  &  tck_r3; 

always @(posedge clk)
  if (trst_n == 1'b0)
     state <= 4'b1111;	
  else if (itck_rise == 1'b1)begin
     state <= {d_nxt, c_nxt, b_nxt, a_nxt};	
  end

always @(posedge clk)  
   if (trst_n == 1'b0)
      tdi_f_local <= 1'b0;	
   else if (itck_rise == 1'b1 ) begin
      tdi_f_local <= tdi;	
   end

always @(posedge clk)
  if (trst_n == 1'b0)begin
      tdo <= 1'b0;	
      tdo_enb <= 1'b0;	
   end
   else if (tck_fall == 1'b1 ) begin
      tdo <= tdo_nxt;	
      tdo_enb <= tdo_enb_nxt;	
   end

endmodule // module vjtag

JTAG接口除了标准的4信号引脚外,TI还定义了一种叫做SBW-JTAG的接口,仅用两根引脚(SBWTCK、SBWTDIO)即可实现JTAG功能,通常用于引脚受限的芯片上。ARM的Cortex-M系列CPU均包含SW-JTAG定义标准。

有限状态机小结

学习有限状态机的关键是理解有限状态机的运行原理,知道通通过有限状态机能够将一个复杂的逻辑流程简化为有限的几个状态,所有的输出相应都是与状态对应的输出。有限状态机的编写风格当采用三段式编码,并尽量采用Moore型状态机

参考

本文主要内容来自《通信IC设计》,仅用于学习参考。

2021-04-07.

  • 14
    点赞
  • 99
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: Verilog自动售货机实现是通过使用Verilog语言来描述售货机的行为和逻辑,包括输入输出、控制信号、状态转换等。通过Verilog语言的描述,可以将自动售货机的功能实现在FPGA或ASIC中,从而实现一个完全由硬件来实现的自动售货机。这个自动售货机可以根据用户的选择,自动出售商品并扣除相应的费用,同时可以显示交易信息和状态。 ### 回答2: Verilog 是一种硬件描述语言,能够描述数字电路的行为和结构。自动售货机是状态机的经典示例,因此我们可以使用 Verilog 描述自动售货机的状态机。下面是详细的步骤: 1. 指定状态:自动售货机的状态图是由多个状态组成的,每个状态代表售货机不同的状态。例如,我们可以定义以下状态:待机、接收货币、选择商品、出货、退货等等。 2. 定义输入输出信号:这些信号将被用来控制状态机的行为。输入信号可能包括按钮、货币接口和显示屏等。输出信号可能包括灯、电机和音频信号等。我们需要定义每个输入和输出信号及其对应的作用。 3. 指定状态转移条件和动作:状态转移指定了状态机从一个状态转移到另一个状态所需的条件,例如,如果货币输入正确,自动售货机应转移到选择商品的状态。动作指定了状态机在转移时必须执行的操作,例如,在出货状态下,我们需要执行出货动作,将商品投放到出货口。 4. 编写 Verilog 代码实现状态机:根据上述步骤,我们可以编写 Verilog 代码实现状态机。我们将输入、输出信号、状态和状态转移和动作分别作为模块输入、输出、参数和逻辑实现的条件,然后设置逻辑实现,使状态机根据输入信号转移到不同的状态,并执行相应的操作输出信号。 综上所述,Verilog 自动售货机状态机实现的过程需要明确状态、输入输出信号以及状态转移条件和动作,并编写相应逻辑实现。根据这些步骤,我们可以通过 Verilog 描述状态机,控制自动售货机的行为。 ### 回答3: Verilog 是一种硬件描述语言,用于电子系统级别的设计和验证。它有丰富的库和模块,使得我们可以对各种电子元器件进行建模,并且能够在较高的抽象层次上进行设计、优化和验证。 自动售货机是一个常见的应用场景,我们可以用 Verilog实现状态机。首先,我们需要定义自动售货机的各个状态,该状态机有以下状态: 1. 初始状态 2. 等待投币状态 3. 投币状态 4. 等待选择状态 5. 选择状态 6. 支付状态 7. 出货状态 在初始状态下,我们需要初始化自动售货机中的各个计数器,并等待着用户投币,这时候状态机会进入等待投币状态。在等待投币状态下,自动售货机会等待着用户投入硬币,如果用户投硬币,它会进入投币状态。在投币状态下,自动售货机会将投币的钱数加起来,并等待用户选择商品,状态机会转移到等待选择状态。在等待选择状态下,自动售货机会等待用户输入商品编号,如果输入正确,状态机会进入选择状态。在选择状态下,自动售货机会进行支付,如果用户付款成功,状态机会进入支付状态。在支付状态下,自动售货机会进行出货,如果成功出货,状态机会进入出货状态。在出货状态下,自动售货机会等待用户将商品取走,完成交易。 以上是自动售货机状态机实现思路,我们需要根据实际情况进行具体的实现。通过使用 Verilog状态机,我们可以很方便地设计各种硬件系统,从而能够更加高效地进行电子系统的设计、仿真和验证。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShareWow丶

前人栽树,分享知识,传播快乐。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值