JTAG篇(4)——OpenOCD与JTAG TAP通信

OpenOCD是一个开源的片上调试器,用于嵌入式设备的调试和编程。本文介绍了如何配置和运行OpenOCD,通过FTDI适配器进行JTAG通信,并展示了JTAGTAP控制器的工作原理,包括状态机和指令处理逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

OpenOCD 简介

OpenOCD (Open On-Chip_Debugger)是一个开源的片上调试器,它主要是为嵌入式设备(如ARM,STM32,ATMEL,FPGA/CPLD等)提供调试、系统编程以及边界扫描等功能。

当然OpenOCD实现这些功能需要借助于**硬件调试器/适配器(Debug Adapter)**来辅助完成.
The debug adapter is a small hardware module which help provide the right kind of electrical signaling to the target being debugged.

硬件调试器/适配器来说即是可以支持系统在线编程(下载程序)的转换器, 多为USB —> JATG或SW.
dongle: a small device that plugs into a computer and servers as an adapter.
在这里插入图片描述

运行OpenOCD

配置 OpenOCD 有两种基本方法,当然你也可以通过多种方式混合使用它们
• 在命令行中多个 -f file-c command
• 不带任何选项,但是在当前文件夹中有一个名为 openocd.cfg的用户配置文件


用户配置文件

interface ftdi
ftdi_vid_pid 0x0403 0x6010

# ftdi_channel 0 is port ADBUS, ftdi_channel 1 is port BDBUS.
ftdi_channel 1

#adapter_name
transport select jtag
adapter_khz 10

# ftdi_layout_init data direction
ftdi_layout_init 0x0038 0x00FB
ftdi_layout_signal nSRST -oe 0x0040
ftdi_layout_signal TRST -oe 0x0010 -data 0x0010

ftdi_layout_signal led2 -data 0x0080 -oe 0x0080
ftdi_layout_signal led3 -data 0x0040 -oe 0x0040

set _CHINPNAME custom
jtag newtap custom tap -irlen 4 -expected-id 0x149511c5 

init
#jtag_init
ftdi_set_signal led2 1
ftdi_set_signal led3 0


#verify_ircapture enable
#verify_jtag enable

#pathmove RESET  DRSELECT
foreach tapname [jtag names] {
    puts [format "TAP: %s\n" $tapname]
}

irscan custom.tap 0x8  -endstate RUN/IDLE

JATG TAP Controller



// Define IDCODE Value
`define IDCODE_VALUE  32'h149511c5
// 0001             version
// 0100 1001 0101 0001 part number (IQ)
// 000 1110 0001      manufacturer id (flextronics)
// 1                required by standard

// Length of the Instruction register
`define	IR_LENGTH	4

// Supported Instructions
`define EXTEST          4'b0000
`define SAMPLE          4'b0001
`define PRELOAD         4'b0011   
`define IDCODE          4'b0010
`define DEBUG           4'b1000
`define MBIST           4'b1001
`define BYPASS          4'b1111


module jtag_tap(
    // JTAG pins
    input  wire  tms_pad_i,      // JTAG test mode select pad
    input  wire  tck_pad_i,      // JTAG test clock pad
    input  wire  tdi_pad_i,      // JTAG test data input pad
    output wire  tdo_pad_o,      // JTAG test data output pad
    input  wire  trstn_pad_i,    // JTAG test reset pad

    // TAP states
    output wire  test_rst,
    output wire  test_idle,
    output wire  shift_dr,
    output wire  pause_dr,
    output wire  update_dr,
    output wire  capture_dr,

    // Select signals for boundary scan or mbist
    output wire  ir_extest,
    output wire  ir_sample,
    output wire  ir_preload,
    output wire  ir_mbist,
    output wire  ir_debug,

    // TDI signals from sub-modules
    input wire  debug_tdo_i,    // from debug module
    input wire  bs_chain_tdo_i, // from Boundary Scan Chain
    input wire  mbist_tdo_i    // from Mbist Chain
);

    wire     sel_dr_scan;
    wire     exit1_dr;
    wire     exit2_dr;
    wire     sel_ir_scan;
    wire     capture_ir;
    wire     shift_ir;
    wire     exit1_ir;
    wire     pause_ir;
    wire     exit2_ir;
    wire     update_ir;

    // Wires which depend on the current value in the IR
    wire     ir_idcode;
    wire     ir_bypass;

    /**********************************************************************************
    *   TAP State Machine: Fully JTAG compliant                                       *
    **********************************************************************************/
    parameter ST_TEST_RST    = 4'hF;
    parameter ST_TEST_IDLE   = 4'hC;
    parameter ST_DR_Scan     = 4'h7;
    parameter ST_Capture_DR  = 4'h6;
    parameter ST_Shift_DR    = 4'h2;
    parameter ST_Exit1_DR    = 4'h1;
    parameter ST_Pause_DR    = 4'h3;
    parameter ST_Exit2_DR    = 4'h0;
    parameter ST_Update_DR   = 4'h5;
    parameter ST_IR_Scan     = 4'h4;
    parameter ST_Capture_IR  = 4'hE;
    parameter ST_Shift_IR    = 4'hA;
    parameter ST_Exit1_IR    = 4'h9;
    parameter ST_Pause_IR    = 4'hB;
    parameter ST_Exit2_IR    = 4'h8;
    parameter ST_Update_IR   = 4'hD;

    reg [3:0] cur_state /* synthesis preserve */ ; 
    reg [3:0] nxt_state; 

    // sequential part of the FSM
    always @ (posedge tck_pad_i or negedge trstn_pad_i) begin
        if(~trstn_pad_i) cur_state <= ST_TEST_RST;
        else             cur_state <= nxt_state;
    end
    
    always@(cur_state, tms_pad_i) begin
        case(cur_state)
            ST_TEST_RST  : nxt_state <= tms_pad_i ? ST_TEST_RST : ST_TEST_IDLE ; 
            ST_TEST_IDLE : nxt_state <= tms_pad_i ? ST_DR_Scan : ST_TEST_IDLE ;  
            ST_DR_Scan   : nxt_state <= tms_pad_i ? ST_IR_Scan : ST_Capture_DR ; 
            ST_Capture_DR: nxt_state <= tms_pad_i ? ST_Exit1_DR : ST_Shift_DR ; 
            ST_Shift_DR  : nxt_state <= tms_pad_i ? ST_Exit1_DR : ST_Shift_DR ; 
            ST_Exit1_DR  : nxt_state <= tms_pad_i ? ST_Update_DR : ST_Pause_DR ; 
            ST_Pause_DR  : nxt_state <= tms_pad_i ? ST_Exit2_DR : ST_Pause_DR ; 
            ST_Exit2_DR  : nxt_state <= tms_pad_i ? ST_Update_DR : ST_Shift_DR ; 
            ST_Update_DR : nxt_state <= tms_pad_i ? ST_DR_Scan : ST_TEST_IDLE ; 

            ST_IR_Scan   : nxt_state <= tms_pad_i ? ST_TEST_RST : ST_Capture_IR ; 
            ST_Capture_IR: nxt_state <= tms_pad_i ? ST_Exit1_IR : ST_Shift_IR ; 
            ST_Shift_IR  : nxt_state <= tms_pad_i ? ST_Exit1_IR : ST_Shift_IR ; 
            ST_Exit1_IR  : nxt_state <= tms_pad_i ? ST_Update_IR : ST_Pause_IR ; 
            ST_Pause_IR  : nxt_state <= tms_pad_i ? ST_Exit2_IR : ST_Pause_IR ; 
            ST_Exit2_IR  : nxt_state <= tms_pad_i ? ST_Update_IR : ST_Shift_IR ; 
            ST_Update_IR : nxt_state <= tms_pad_i ? ST_DR_Scan : ST_TEST_IDLE ; 
            default      : nxt_state <= ST_TEST_RST; 
        endcase
    end

    reg [15:0] tap_out;
    always@(posedge tck_pad_i or negedge trstn_pad_i) begin
        if(~trstn_pad_i) begin
            tap_out <= 16'h1;
        end else begin
            case(nxt_state) 
                ST_TEST_RST    : tap_out <= 16'h1 ; 
                ST_TEST_IDLE   : tap_out <= 16'h2 ; 
                ST_DR_Scan     : tap_out <= 16'h4 ; 
                ST_Capture_DR  : tap_out <= 16'h8 ; 
                ST_Shift_DR    : tap_out <= 16'h10; 
                ST_Exit1_DR    : tap_out <= 16'h20; 
                ST_Pause_DR    : tap_out <= 16'h40; 
                ST_Exit2_DR    : tap_out <= 16'h80; 
                ST_Update_DR   : tap_out <= 16'h100 ; 
                ST_IR_Scan     : tap_out <= 16'h200 ; 
                ST_Capture_IR  : tap_out <= 16'h400 ; 
                ST_Shift_IR    : tap_out <= 16'h800 ; 
                ST_Exit1_IR    : tap_out <= 16'h1000; 
                ST_Pause_IR    : tap_out <= 16'h2000; 
                ST_Exit2_IR    : tap_out <= 16'h4000; 
                ST_Update_IR   : tap_out <= 16'h8000; 
            endcase
        end
    end

    assign test_rst    = tap_out[0];       
    assign test_idle   = tap_out[1];     
    assign sel_dr_scan = tap_out[2];      
    assign capture_dr  = tap_out[3];     
    assign shift_dr    = tap_out[4];   
    assign exit1_dr    = tap_out[5];   
    assign pause_dr    = tap_out[6];   
    assign exit2_dr    = tap_out[7];   
    assign update_dr   = tap_out[8];    
    assign sel_ir_scan = tap_out[9];      
    assign capture_ir  = tap_out[10];     
    assign shift_ir    = tap_out[11];   
    assign exit1_ir    = tap_out[12];   
    assign pause_ir    = tap_out[13];   
    assign exit2_ir    = tap_out[14];    
    assign update_ir   = tap_out[15];   

	 reg  select_shift_ir /* synthesis preserve */;
	 always @(posedge tck_pad_i, negedge trstn_pad_i) begin
		if(~trstn_pad_i) begin
			select_shift_ir <= 1'b0;
		end else begin
			if(sel_ir_scan)    select_shift_ir <= 1'b1;
			else if(update_ir) select_shift_ir <= 1'b0;
		end
	 end
    
    /**********************************************************************************
    *                                                                                 *
    *   InstructionShiftReg:  JTAG Instruction Register                                           *
    *                                                                                 *
    **********************************************************************************/
    reg [`IR_LENGTH-1:0]  InstructionShiftReg;     // Instruction Shift register
    reg [`IR_LENGTH-1:0]  jtag_instr;    // Instruction register

    always @ (posedge tck_pad_i or negedge trstn_pad_i) begin
      if(!trstn_pad_i)     InstructionShiftReg <= 0; 
      else if(test_rst)    InstructionShiftReg <= 0;
      else if(capture_ir)  InstructionShiftReg <= 4'b0101;          
      else if(shift_ir)    InstructionShiftReg <= {tdi_pad_i, InstructionShiftReg[`IR_LENGTH-1:1]};
    end
    
    // Updating InstructionShiftReg (Instruction Register)
    // InstructionShiftReg should be latched on FALLING EDGE of TCK when capture_ir == 1
    always @ (negedge tck_pad_i or negedge trstn_pad_i) begin
        if(~trstn_pad_i)    jtag_instr <= `IDCODE;   // IDCODE selected after reset
        else if(test_rst)   jtag_instr <= `IDCODE;
        else if(update_ir)  jtag_instr <= InstructionShiftReg;
    end

    assign ir_extest = (jtag_instr == `EXTEST ) ? 1'b1 : 1'b0; 
    assign ir_sample = (jtag_instr == `SAMPLE ) ? 1'b1 : 1'b0; 
    assign ir_preload= (jtag_instr == `PRELOAD) ? 1'b1 : 1'b0;  
    assign ir_idcode = (jtag_instr == `IDCODE ) ? 1'b1 : 1'b0;
    assign ir_debug  = (jtag_instr == `DEBUG  ) ? 1'b1 : 1'b0;
    assign ir_mbist  = (jtag_instr == `MBIST  ) ? 1'b1 : 1'b0;
    assign ir_bypass = (jtag_instr == `BYPASS ) ? 1'b1 : 1'b0;

    /**********************************************************************************
    *                                                                                 *
    *   idcode logic                                                                  *
    *                                                                                 *
    **********************************************************************************/
    reg [31:0]  idcode_reg;
    always @ (posedge tck_pad_i or negedge trstn_pad_i) begin
      if(~trstn_pad_i)                 idcode_reg <= `IDCODE_VALUE;   // IDCODE selected after reset
      else if(test_rst)                idcode_reg <= `IDCODE_VALUE;
      else if(ir_idcode & capture_dr)  idcode_reg <= `IDCODE_VALUE;
      else if(ir_idcode & shift_dr)    idcode_reg <= {tdi_pad_i, idcode_reg[31:1]};
    end

    /**********************************************************************************
    *                                                                                 *
    *   Bypass logic                                                                  *
    *                                                                                 *
    **********************************************************************************/
    reg   bypass_reg;  // This is a 1-bit register

    always @ (posedge tck_pad_i or negedge trstn_pad_i) begin
      if(~trstn_pad_i)                 bypass_reg <=  1'b0;
      else if(test_rst)                bypass_reg <= 1'b0;
      else if(ir_bypass & capture_dr)  bypass_reg<= 1'b0;
      else if(ir_bypass & shift_dr)    bypass_reg<= tdi_pad_i;
    end
	
    /**********************************************************************************
    *                                                                                 *
    *   Multiplexing TDO data                                                         *
    *                                                                                 *
    **********************************************************************************/
    reg  tdo_mux_out;
    always @ (negedge tck_pad_i) begin
		if(select_shift_ir) begin
			tdo_mux_out <= InstructionShiftReg[0];
		end else begin
			case(jtag_instr)    // synthesis parallel_case
            `IDCODE:        tdo_mux_out <= idcode_reg[0];    // Reading ID code
            `DEBUG:         tdo_mux_out <= debug_tdo_i;      // Debug
            `SAMPLE:        tdo_mux_out <= bs_chain_tdo_i;   //
            `PRELOAD:       tdo_mux_out <= bs_chain_tdo_i;   // Sampling/Preloading
            `EXTEST:        tdo_mux_out <= bs_chain_tdo_i;   // External test
            `MBIST:         tdo_mux_out <= mbist_tdo_i;      // Mbist test
            default:        tdo_mux_out <= bypass_reg ;      // BYPASS instruction
        endcase
		end
 
    end

    assign tdo_pad_o = (shift_dr | shift_ir) ? tdo_mux_out : 1'bz;
endmodule

Result

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值