OpenOCD与JTAG TAP通信
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