集成电路流片随笔17:jtag子模块1
JTAG 驱动模块(jtag_driver),它用于实现 JTAG 接口协议,控制 JTAG 状态机的操作,并处理与调试模块(DM)的交互。通过该模块,JTAG 接口可以完成数据传输、调试和控制等任务。
模块输入输出
输入信号:
- rst_n:复位信号,低电平有效。用于将模块恢复到初始状态。
- jtag_TCK:JTAG 时钟信号。用于同步 JTAG 数据传输。
- jtag_TDI:JTAG 数据输入信号,数据从外部传入设备。
- jtag_TMS:JTAG 模式选择信号,控制 JTAG 状态机的状态转移。
- dm_resp_i:来自调试模块(DM)的响应信号。表示调试模块已经发送了数据。
- dm_resp_data_i:来自 DM 的响应数据。
- dm_ack_i:来自 DM 的确认信号,表示 DM 已经准备好响应数据。
输出信号:
- jtag_TDO:JTAG 数据输出信号,设备将数据发送到外部调试设备。
- dtm_ack_o:调试传输模块(DTM)的确认信号。表示从设备接收到数据请求并已准备好响应。
- dtm_req_valid_o:DTM 请求信号,表示是否有有效的请求需要处理。
- dtm_req_data_o:DTM 请求的数据。包含目标寄存器、数据或操作等信息。
- reg_we_o:寄存器写使能信号,表示是否进行寄存器写操作。
- reg_addr_o:寄存器地址,指示要访问的寄存器。
- reg_wdata_o:写入寄存器的数据。
- mem_we_o:内存写使能信号,表示是否进行内存写操作。
- mem_addr_o:内存地址,指示要访问的内存位置。
- mem_wdata_o:写入内存的数据。
- op_req_o:操作请求信号,表示设备要求执行操作。
JTAG 状态机(JTAG State Machine)
JTAG 使用状态机(State Machine)来控制数据的传输和命令的执行。状态机的状态由 TMS(Test Mode Select) 信号控制。
主要状态:
parameter TEST_LOGIC_RESET = 4'h0;
parameter RUN_TEST_IDLE = 4'h1;
parameter SELECT_DR = 4'h2;
parameter CAPTURE_DR = 4'h3;
parameter SHIFT_DR = 4'h4;
parameter EXIT1_DR = 4'h5;
parameter PAUSE_DR = 4'h6;
parameter EXIT2_DR = 4'h7;
parameter UPDATE_DR = 4'h8;
parameter SELECT_IR = 4'h9;
parameter CAPTURE_IR = 4'hA;
parameter SHIFT_IR = 4'hB;
parameter EXIT1_IR = 4'hC;
parameter PAUSE_IR = 4'hD;
parameter EXIT2_IR = 4'hE;
parameter UPDATE_IR = 4'hF;
这段代码定义了 JTAG 状态机的所有状态。TMS 信号用于在不同的状态之间进行切换。常见的状态有:
- TEST_LOGIC_RESET:设备复位状态。
- RUN_TEST_IDLE:空闲状态。
- SELECT_DR:选择数据寄存器进行数据传输。
- CAPTURE_DR:捕获数据寄存器的内容。
- SHIFT_DR:移位操作,将数据移入数据寄存器或输出。
- UPDATE_DR:更新数据寄存器的状态。
这些状态通过 TMS 信号的变化来控制,确保 JTAG 操作按照协议顺序进行。
数据传输和寄存器操作
在 CAPTURE_DR 和 SHIFT_DR 状态下,JTAG 会根据 TDI(Test Data Input) 和 TDO(Test Data Output) 信号来完成数据的传输。
这段代码实现了 JTAG 接口中的 IR(Instruction Register) 和 DR(Data Register) 的移位操作。JTAG 设备通过 TDI(Test Data Input) 和 TDO(Test Data Output) 进行数据传输,其中,IR 用于传输指令,而 DR 用于传输数据。
代码解析
代码基于 JTAG 状态机 的状态变化,通过移位寄存器(shift_reg
)来执行 IR 和 DR 的数据移位。移位过程发生在 JTAG 时钟信号 TCK 的上升沿。
1. IR 移位 (CAPTURE_IR
和 SHIFT_IR
状态)
// IR
CAPTURE_IR: shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}}, 1'b1}; // JTAG spec says it must be b01
SHIFT_IR : shift_reg <= {{(SHIFT_REG_BITS - IR_BITS){1'b0}}, jtag_TDI, shift_reg[IR_BITS - 1:1]}; // right shift 1 bit
-
CAPTURE_IR
:
在 CAPTURE_IR 状态下,JTAG 会捕获指令寄存器(IR)的数据,并将其存入移位寄存器shift_reg
中。根据 JTAG 协议,IR 的初始值应为1'b1
,并且其它位应填充为0
,所以使用{ {(SHIFT_REG_BITS - 1){1'b0}}, 1'b1 }
。 -
SHIFT_IR
:
在 SHIFT_IR 状态下,JTAG 从 TDI 信号中读取数据并将其右移一个位置,保留原有的shift_reg
内容。shift_reg
中的数据会从最低位(TDI
)开始移位,直到完成传输。这时 TDI 输入的数据会填充shift_reg
的最低位,剩下的数据将向右移动。
2. DR 移位 (CAPTURE_DR
和 SHIFT_DR
状态)
// DR
CAPTURE_DR: case (ir_reg) REG_BYPASS : shift_reg <= {(SHIFT_REG_BITS){1'b0}}; // No dataREG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, idcode}; // ID codeREG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, dtmcs}; // DTM control and statusREG_DMI : shift_reg <= is_busy ? busy_response : none_busy_response; // DMI datadefault:shift_reg <= {(SHIFT_REG_BITS){1'b0}}; // Default caseendcase
SHIFT_DR : case (ir_reg) REG_BYPASS : shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}}, jtag_TDI}; // Bypass, just pass dataREG_IDCODE : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, jtag_TDI, shift_reg[31:1]}; // right shift 1 bitREG_DTMCS : shift_reg <= {{(SHIFT_REG_BITS - DMI_DATA_BITS){1'b0}}, jtag_TDI, shift_reg[31:1]}; // right shift 1 bitREG_DMI : shift_reg <= {jtag_TDI, shift_reg[SHIFT_REG_BITS - 1:1]}; // right shift 1 bitdefault:shift_reg <= {{(SHIFT_REG_BITS - 1){1'b0}} , jtag_TDI}; // Default caseendcase
-
CAPTURE_DR
:
在 CAPTURE_DR 状态下,根据指令寄存器(ir_reg
)的值选择不同的操作:REG_BYPASS
:不进行任何数据传输,移位寄存器shift_reg
直接置零。REG_IDCODE
:将 ID 代码加载到移位寄存器shift_reg
中。ID 代码是设备的唯一标识。REG_DTMCS
:加载调试传输模块(DTM)控制和状态信息。REG_DMI
:加载 DMI 数据,具体取决于是否忙碌(is_busy
)。如果忙碌,则加载忙碌响应busy_response
,否则加载正常响应none_busy_response
。
-
SHIFT_DR
:
在 SHIFT_DR 状态下,移位寄存器中的数据向右移动,并根据指令寄存器(ir_reg
)的值执行相应的操作:REG_BYPASS
:直接将 TDI 数据传递到shift_reg
中,不改变其它数据。REG_IDCODE
、REG_DTMCS
、REG_DMI
:将 TDI 数据移入寄存器并右移一位,保留其余部分的值。
通过这种方式,JTAG 可以通过 TDI 和 TDO 在目标设备与调试主机之间传递数据。移位操作通过 TCK(JTAG 时钟)同步进行,以确保数据按顺序传输。
DTM 请求和响应
DTM Debug Transport Module 是 JTAG 调试协议中的一个模块,负责数据传输和调试操作。它通常包含在 JTAG 控制器中,允许通过 JTAG 接口进行调试和设备控制。
-
功能:DTM 的主要作用是向调试目标设备(如 CPU)发送命令,并接收目标设备的响应。它负责处理与设备间的数据传输和调试命令的交互。
-
如何工作:
- 请求:调试主机通过 JTAG 向 DTM 发送请求,要求执行某个操作或读取某个寄存器的数据。
- 响应:DTM 处理请求并返回响应数据。如果操作失败或 DTM 无法处理请求,它会返回一个错误响应。
代码解释
涉及到的几个主要部分有 DTM 请求,DTM 重置,接收 DM 响应数据 和 TX 忙碌状态。
1. 开始访问 DM 模块 (start access DM module)
always @(posedge jtag_TCK or negedge rst_n) beginif (!rst_n) begindtm_req_valid <= `DTM_REQ_INVALID;dtm_req_data <= {DTM_REQ_BITS{1'b0}};end else beginif (jtag_state == UPDATE_DR) beginif (ir_reg == REG_DMI) begin// if DM can be accessedif (!is_busy & tx_idle) begindtm_req_valid <= `DTM_REQ_VALID;dtm_req_data <= shift_reg;endendend else begindtm_req_valid <= `DTM_REQ_INVALID;endend
end
DTM 请求有效信号 (dtm_req_valid)
:该信号表明 DTM 请求是否有效。如果为1
,表示可以发送请求。DTM 请求数据 (dtm_req_data)
:该信号保存发送给 DM 模块的数据。
工作原理:
- 这个过程在每个时钟周期检查是否可以发送 DTM 请求。在
UPDATE_DR
状态下,如果当前指令寄存器(ir_reg
)为REG_DMI
(表示数据模块接口),且当前 DTM 模块未忙碌 (!is_busy
),并且传输空闲 (tx_idle
),则会将请求设置为有效,并将移位寄存器中的数据(shift_reg
)作为请求数据。 - 如果当前不符合条件,则将
dtm_req_valid
设置为无效 (DTM_REQ_INVALID
)。
2. DTM 重置 (DTM reset)
always @(posedge jtag_TCK or negedge rst_n) beginif (!rst_n) beginsticky_busy <= 1'b0;end else beginif (jtag_state == UPDATE_DR) beginif (ir_reg == REG_DTMCS & dtm_reset) beginsticky_busy <= 1'b0;endend else if (jtag_state == CAPTURE_DR) beginif (ir_reg == REG_DMI) beginsticky_busy <= is_busy;endendend
end
sticky_busy
:这个寄存器用于存储 DTM 的忙碌状态。
工作原理:
- 在
UPDATE_DR
状态下,如果当前指令寄存器是REG_DTMCS
(表示 DTM 控制和状态寄存器)并且要求重置(dtm_reset
)时,将sticky_busy
设置为0
,表示重置 DTM 的忙碌状态。 - 在
CAPTURE_DR
状态下,如果当前指令寄存器是REG_DMI
(数据模块接口寄存器),则将sticky_busy
设置为当前 DTM 的忙碌状态(is_busy
)。is_busy
表示 DTM 是否正在忙碌。
3. 接收 DM 响应数据 (receive DM response data)
always @(posedge jtag_TCK or negedge rst_n) beginif (!rst_n) begindm_resp_data <= {DM_RESP_BITS{1'b0}};end else beginif (rx_valid) begindm_resp_data <= rx_data;endend
end
dm_resp_data
:该寄存器用于存储从 DM 模块接收到的数据。
工作原理:
- 每次接收到有效的
rx_valid
信号时,就会将接收到的数据rx_data
存入dm_resp_data
。
4. TX 忙碌状态 (TX busy)
always @(posedge jtag_TCK or negedge rst_n) beginif (!rst_n) begindm_is_busy <= 1'b0;end else beginif (dtm_req_valid) begindm_is_busy <= 1'b1;end else if (rx_valid) begindm_is_busy <= 1'b0;endend
end
dm_is_busy
:该寄存器用于指示 DTM 是否处于忙碌状态。
工作原理:
- 当
dtm_req_valid
为有效时,表示正在向 DTM 模块发送请求,所以将dm_is_busy
设置为1
,表示 DTM 正在忙碌。 - 如果
rx_valid
为有效(接收到响应数据),则表示 DTM 的请求已处理完毕,设置dm_is_busy
为0
,表示 DTM 不再忙碌。
TAP(Test Access Port)复位、TDO 输出、以及数据的全双工传输(通过 full_handshake_tx
和 full_handshake_rx
模块)
1. TAP reset
always @(negedge jtag_TCK) beginif (jtag_state == TEST_LOGIC_RESET) beginir_reg <= REG_IDCODE;end else if (jtag_state == UPDATE_IR) beginir_reg <= shift_reg[IR_BITS - 1:0];end
end
jtag_TCK
:JTAG 时钟信号。ir_reg
:指令寄存器(Instruction Register),它用于保存当前指令的状态。
工作原理:
- 在 JTAG 时钟的负边沿(
negedge jtag_TCK
)时,这段代码会根据当前状态 (jtag_state
) 来更新指令寄存器ir_reg
。- 如果当前状态是
TEST_LOGIC_RESET
,表示 JTAG 正在复位,此时将ir_reg
设置为REG_IDCODE
,表示指令寄存器指向 IDCODE 寄存器。 - 如果当前状态是
UPDATE_IR
,表示要更新指令寄存器的内容,此时将ir_reg
设置为移位寄存器shift_reg
的低位(shift_reg[IR_BITS - 1:0]
)。这将移位寄存器的当前值加载到指令寄存器中。
- 如果当前状态是
2. TDO output
always @(negedge jtag_TCK) beginif (jtag_state == SHIFT_IR) beginjtag_TDO <= shift_reg[0];end else if (jtag_state == SHIFT_DR) beginjtag_TDO <= shift_reg[0];end else beginjtag_TDO <= 1'b0;end
end
jtag_TDO
:JTAG 数据输出信号(Test Data Out)。
工作原理:
- 在 JTAG 时钟的负边沿(
negedge jtag_TCK
)时,这段代码根据当前的 JTAG 状态来设置输出信号jtag_TDO
。- 如果当前状态是
SHIFT_IR
,表示正在移位指令寄存器(IR),此时将jtag_TDO
设置为移位寄存器shift_reg
的最低位shift_reg[0]
。 - 如果当前状态是
SHIFT_DR
,表示正在移位数据寄存器(DR),同样将jtag_TDO
设置为移位寄存器shift_reg
的最低位。 - 否则,即不在移位状态下,
jtag_TDO
设置为0
。
- 如果当前状态是
3. 全双工传输模块 (full_handshake_tx
)
full_handshake_tx #(.DW(DTM_REQ_BITS)
) tx(.clk(jtag_TCK),.rst_n(rst_n),.ack_i(dm_ack_i),.req_i(tx_valid),.req_data_i(tx_data),.idle_o(tx_idle),.req_o(dtm_req_valid_o),.req_data_o(dtm_req_data_o)
);
full_handshake_tx
:这是一个全双工传输模块,用于发送数据(请求)到 DM(调试模块)。tx_valid
:发送请求有效信号,表示数据请求是否有效。tx_data
:发送的数据。dtm_req_valid_o
:DTM 请求有效信号,表示是否可以发送请求。dtm_req_data_o
:DTM 请求数据,将tx_data
转发给 DTM 模块。
工作原理:
full_handshake_tx
模块通过握手信号完成数据的发送。- 通过
ack_i
(DM 模块的应答信号)来判断是否可以发送新的数据。 - 当
tx_valid
为1
时,表示可以发送数据,tx_data
存储需要发送的数据。 - 在
full_handshake_tx
模块中,dtm_req_valid_o
和dtm_req_data_o
表示将数据发送到 DTM 模块。
- 通过
4. 全双工接收模块 (full_handshake_rx
)
full_handshake_rx #(.DW(DM_RESP_BITS)
) rx(.clk(jtag_TCK),.rst_n(rst_n),.req_i(dm_resp_i),.req_data_i(dm_resp_data_i),.ack_o(dtm_ack_o),.recv_data_o(rx_data),.recv_rdy_o(rx_valid)
);
full_handshake_rx
:这是一个全双工接收模块,用于从 DM 模块接收响应数据。dm_resp_i
:DM 响应请求输入信号,表示 DM 是否发送了响应。dm_resp_data_i
:从 DM 模块接收的数据。dtm_ack_o
:DTM 应答信号,表示是否接受数据。rx_data
:接收到的数据。rx_valid
:接收数据有效信号,表示接收到有效数据。
工作原理:
full_handshake_rx
模块通过握手信号来接收数据。- 通过
dm_resp_i
(DM 模块的响应信号)来判断是否可以接收数据。 dm_resp_data_i
保存接收到的 DM 响应数据,并通过rx_valid
告知数据是否有效。
- 通过