jtag 序列测试说明

JTAG 扫描时序文档 — jtag_ir_scanjtag_dr_scan


目录

  1. 时序约定
  2. TAP 状态路径
  3. jtag_ir_scan 典型波形
  4. jtag_dr_scan 典型波形
  5. IDCODE 读回 TDO 波形
  6. TDO 输出语义
  7. 关键时序点总结

1. 时序约定

1.1 时钟参数(testbench 定义)

参数说明
TCK_HALF_PERIOD50nsTCK 半周期 → TCK = 10 MHz
SYS_CLK_PERIOD20ns系统时钟 → sys_clk = 50 MHz

1.2 信号边沿规则

{
  "head": {"tick": 0},
  "signal": [
    {"name": "TCK", "wave": "p.p.p.p.p.p", "period": 2},
    {"name": "TMS", "wave": "0.1.0.1.0.1", "node": "....n.."},
    {"name": "TDI", "wave": "1.0.1.0.1.0"},
    {"name": "TDO", "wave": "x.0.1.0.1.0", "node": "..p...."}
  ]
}

在这里插入图片描述

关键规则(JTAG 标准)

  • TMS / TDITCK 下降沿 由测试端驱动(testbench 的 @(negedge TCK)
  • TAPTCK 上升沿 采样 TMS/TDI,并更新状态(@(posedge TCK)
  • TDOTCK 下降沿 由 TAP 驱动,测试端在 上升沿 采样

本文档 Wavedrom 波形中:TAP 行标注每个 TCK 周期期间所处的 TAP 状态;p=时钟脉冲,n=下降沿标记,.=保持。


1.3 设备模型架构图

设备模型即 DUT(jtag_debug_bridge):一个多 SoC JTAG 调试桥。主机(testbench,含 §2.3 的 jtag_ir_scan / jtag_dr_scan task)通过 5 根 JTAG 线(TCK/TMS/TDI/TDO/TRST_n)访问设备内部,设备内部划分为 TCK 域CDC 跨时钟域sys_clk 域 三部分。

设备模型 = jtag_debug_bridge(DUT)

主机 / 测试端(jtag_debug_tb.v)

SoC 目标路由器

sys_clk 域

CDC 跨时钟域

TCK 域

JTAG 物理接口

TCK

TMS

TDI

TDO 采样

capture/update/shift 脉冲

capture/update/shift 脉冲

ir_latched

ir_opcode

dr_capture_data

ir_scan_out

dr_scan_out

TDO

pulse_update_dr

dr_addr / dr_wdata

cmd_opcode / addr / wdata

读数据 / 状态

rd_data 回读

sram_* / reg_* 接口

jtag_ir_scan / jtag_dr_scan
jtag_shift 基础移位(见 §2.3)

TCK

TMS

TDI

TDO

TRST_n

jtag_tap
TAP 状态机
(IEEE 1149.1)

IR 扫描链 8bit
ir_reg(移位)
ir_latched(Update-IR 影子)

DR 扫描链 64bit
dr_reg + bypass_reg

IR 译码
soc_id / is_reg
opcode / bypass

dr_capture_data
按 ir_opcode 选择

TDO 输出选择
ir_scan_out / dr_scan_out

update_dr 同步器
+ 命令锁存 cmd_*

调试命令状态机
IDLE / READ / WRITE / DONE

rd_data_reg
debug_status

SoC0 SRAM + REG

SoC1 SRAM + REG

SoC2 SRAM + REG

SoC3 SRAM + REG

数据流主线(一次 JTAG 写/读命令)

  1. IR 扫描:主机 jtag_ir_scan 沿 TDI 移入 8bit 指令 → ir_reg → Update-IR 锁存到 ir_latched(影子寄存器,见 §3.5)→ IR 译码 得到 opcode/soc_id/is_reg
  2. DR 扫描:主机 jtag_dr_scan 沿 TDI 移入 {addr, data}dr_regdr_capture_datair_opcode 决定回读内容(IDCODE/STATUS/读数据/写回显)。
  3. TDO:移位期间 TDO 输出选择ir_scan_outdr_scan_out 的 LSB 送出,主机上升沿采样。
  4. 执行:Update-DR 脉冲经 CDC 同步,cmd_* 锁存命令,sys_clk 域状态机执行写/读,读数据经 rd_data_reg 回馈到下一次 DR 捕获。

JTAG 可见面:只有 TCK/TMS/TDI/TDO/TRST_n 五根线跨出设备边界;内部 TCK 域 ↔ sys_clk 域的全部交互都通过 CDC 同步器完成。


2. TAP 状态路径

2.1 jtag_ir_scan 状态路径

{
  "head": {"tick": 1, "hscale": 2},
  "signal": [
    {"name": "TAP", "wave": "4444444", "data": ["①","②","③","④","⑤","⑥","⑦"]}
  ],
  "foot": {"text": "IR 扫描状态路径(共14个TCK周期)"}
}

在这里插入图片描述
图例(TAP 状态标签)

标签状态说明
RTI空闲(起点/终点)
Select-DR选择 DR 扫描
Select-IR选择 IR 扫描
Capture-IR捕获 IR(装入 {6'b0,2'b01}:高6位填0 + 低2位固定捕获码01)
Shift-IR移位 8bit(重复 8 个 TCK 周期)
Exit1-IR退出移位
Update-IR更新 IR:ir_latched <= ir_reg,指令生效

状态数: 8 个 TAP 状态跳变(不含移位内部重复的 Shift-IR)

2.2 jtag_dr_scan 状态路径

{
  "head": {"tick": 1, "hscale": 2},
  "signal": [
    {"name": "TAP", "wave": "444444", "data": ["①","②","③","④","⑤","⑥"]}
  ],
  "foot": {"text": "DR 扫描状态路径(共69个TCK周期)"}
}

在这里插入图片描述
图例(TAP 状态标签)

标签状态说明
RTI空闲(起点/终点)
Select-DR选择 DR 扫描
Capture-DR捕获 DR(装入 dr_capture_data
Shift-DR移位 N bit(64bit 时重复 64 个 TCK 周期)
Exit1-DR退出移位
Update-DR更新 DR(触发 sys_clk 域命令)

状态数: 6 个 TAP 状态跳变(不含移位内部重复的 Shift-DR)


2.3 协议 Task 代码封装(jtag_debug_tb.v

两个扫描 task 都建立在基础移位 task jtag_shift 之上:jtag_shiftLSB-first 在每个 TCK 下降沿驱动 TMS/TDI、上升沿采样 TDO

jtag_shift — 基础移位(N bit)
// 发送一个 TMS 序列 + 对应数量的 TDI bit,返回 TDO bit 序列
// JTAG 是 LSB-first 协议:TDI[0] 先移入,TDO[0] 先移出
// 内部自动处理位序反转(tdi_vec/tdo_vec 仍按自然顺序存放)
task jtag_shift;
    input  integer       num_bits;   // 移位 bit 数
    input  [127:0]       tms_vec;    // TMS 序列, tms_vec[0]=最后一个bit的TMS
    input  [127:0]       tdi_vec;    // TDI 序列, tdi_vec[0]=最后移入的bit
    output [127:0]       tdo_vec;    // TDO 序列, tdo_vec[0]=最后移出的bit
    integer i;
    begin
        tdo_vec = 0;
        for (i = 0; i < num_bits; i = i + 1) begin
            @(negedge TCK);          // TMS/TDI 在 TCK 下降沿变化
            TMS = tms_vec[i];
            TDI = tdi_vec[i];
            @(posedge TCK);          // TDO 在 TCK 上升沿采样
            tdo_vec[i] = TDO;
        end
    end
endtask
jtag_ir_scan — IR 扫描(8 bit,对应 §3.2 波形 C1~C14)
// 扫描 IR (进入 Shift-IR → 移位 → 退出到 RTI)
task jtag_ir_scan;
    input  [7:0] ir_data;
    output [7:0] ir_tdo;
    reg    [127:0] tms_ir;
    begin
        // 导航: RTI → Select-DR → Select-IR → Capture-IR → Shift-IR (C1~C4)
        @(negedge TCK); TMS = 1'b1; TDI = 1'b0; @(posedge TCK); // C1 RTI→Sel-DR
        @(negedge TCK); TMS = 1'b1; TDI = 1'b0; @(posedge TCK); // C2 Sel-DR→Sel-IR
        @(negedge TCK); TMS = 1'b0; TDI = 1'b0; @(posedge TCK); // C3 Sel-IR→Cap-IR (Capture: ir_reg<={6'b0,2'b01})
        @(negedge TCK); TMS = 1'b0; TDI = 1'b0; @(posedge TCK); // C4 Cap-IR→Shift-IR

        // 移位 8 bit (C5~C12), 最后一位(MSB) TMS=1 → Exit1-IR
        tms_ir = 0;
        tms_ir[7] = 1'b1;            // bit7=MSB 时 TMS=1 (C12)
        jtag_shift(8, tms_ir, {120'h0, ir_data}, ir_tdo);

        // 退出: Exit1→Update (C13) → Update→RTI (C14, 锁存 ir_latched<=ir_reg)
        @(negedge TCK); TMS = 1'b1; TDI = 1'b0; @(posedge TCK); // C13 Exit1→Update
        @(negedge TCK); TMS = 1'b0; TDI = 1'b0; @(posedge TCK); // C14 Update→RTI (指令生效, 见 §3.5)
    end
endtask
jtag_dr_scan — DR 扫描(N bit,对应 §4.2 波形 C1~C69)
// 扫描 DR (进入 Shift-DR → 移位 → 退出到 RTI)
//   num_bits : DR 扫描链长度 = 本次移位的 bit 数 (IDCODE=32, 读写=64, BYPASS=32 ...)
//   dr_data  : 要移入的 TDI 数据(低 num_bits 位有效)
//              - 写: {addr[31:0], data[31:0]};  读: 只给地址数据位填0;  纯读: 全0
//   dr_tdo   : 移位期间从 TDO 采样的回读(低 num_bits 位有效)
task jtag_dr_scan;
    input  integer       num_bits;   // DR 扫描链长度(bit 数)
    input  [127:0]       dr_data;    // 移入的 TDI 数据(低 num_bits 位有效)
    output [127:0]       dr_tdo;     // 移出的 TDO 回读数据(低 num_bits 位有效)
    reg    [127:0]       tms_dr;
    begin
        // 导航: RTI → Select-DR → Capture-DR → Shift-DR (C1~C3)
        @(negedge TCK); TMS = 1'b1; TDI = 1'b0; @(posedge TCK); // C1 RTI→Sel-DR
        @(negedge TCK); TMS = 1'b0; TDI = 1'b0; @(posedge TCK); // C2 Sel-DR→Cap-DR (Capture: dr_reg<=dr_capture_data)
        @(negedge TCK); TMS = 1'b0; TDI = 1'b0; @(posedge TCK); // C3 Cap-DR→Shift-DR

        // 移位 N bit (C4~C(3+N)), 最后一位 TMS=1 → Exit1-DR
        tms_dr = 0;
        tms_dr[num_bits-1] = 1'b1;   // 最后移入的 bit (MSB) 设 TMS=1
        jtag_shift(num_bits, tms_dr, dr_data, dr_tdo);

        // 退出: Exit1→Update → Update→RTI (C(4+N)~C(5+N))
        @(negedge TCK); TMS = 1'b1; TDI = 1'b0; @(posedge TCK); // C(4+N) Exit1→Update (Update-DR: 触发 sys_clk 域命令)
        @(negedge TCK); TMS = 1'b0; TDI = 1'b0; @(posedge TCK); // C(5+N) Update→RTI
    end
endtask

封装要点:两个 task 结构对称 —— 3~4 拍导航进入 Shift 状态 → jtag_shift 移位 N bit(最后一位 TMS=1 退出)→ 2 拍退出回 RTI。TMS/TDI 一律在下降沿驱动、由 TAP 上升沿采样,TDO 在上升沿采样(见 §1.2)。


3. jtag_ir_scan 典型波形

3.1 调用示例与指令位域详解

IR 编码(8-bit,每一位的作用)

build_ir(soc_id, is_reg, opcode) 拼出的 8-bit IR 结构:

代码中使用宏(`JTAG_OP_* `、`JTAG_DEVICE_ID 等)前需 include "jtag_defines.vh"; 本文代码示例与 jtag_tap.v/jtag_debug_bridge.v/jtag_debug_tb.v` 保持一致。

  IR 8-bit:  [7:5] soc_id    [4] is_reg    [3:0] opcode
             ┌───────────┬──────────┬────────────────┐
             │  SoC 选择   │ 空间选择  │    操作类型      │
             └───────────┴──────────┴────────────────┘
IR 位位宽字段说明
[7:5]3 bitsoc_id目标 SoC 编号`JTAG_SOC0 ~ `JTAG_SOC7(0~7)
[4]1 bitis_reg空间选择`JTAG_SPACE_SRAM = 0,`JTAG_SPACE_REG = 1
[3:0]4 bitopcode操作类型`JTAG_OP_*(见下表)

操作码表(宏定义见 jtag_defines.vh):

opcode宏定义助记符含义是否访问存储
0000`JTAG_OP_IDCODEIDCODE读设备 ID
0001`JTAG_OP_BYPASSBYPASS旁路
0010`JTAG_OP_READREAD读 SRAM/寄存器
0011`JTAG_OP_WRITEWRITE写 SRAM/寄存器
0100`JTAG_OP_STATUSSTATUS读调试状态
0111`JTAG_OP_RESET_DBGRESET_DBG复位调试逻辑

代码中一律用宏(`JTAG_OP_*),数值统一由 jtag_defines.vh 维护,避免魔法数字。

关键点:IR 只决定「对哪个 SoC / 哪个空间 / 什么操作」;
具体的地址和写入的数据由紧随其后的 DR 扫描 提供(DR[63:32]=地址DR[31:0]=数据)。


例 1:`JTAG_OP_IDCODE(IDCODE,读设备 ID)→ 拼出 8'h00
build_ir(`JTAG_SOC0, `JTAG_SPACE_SRAM, `JTAG_OP_IDCODE) = {3'b000, 1'b0, 4'h0} = 8'h00
         └────┬────┘  └────┬────┘    └────┬────┘
            SoC0         SRAM          IDCODE
含义
[7:5]`JTAG_SOC0SoC0(IDCODE 不访问存储,此字段无实际作用)
[4]`JTAG_SPACE_SRAMSRAM 空间(同样无实际作用)
[3:0]`JTAG_OP_IDCODEIDCODE:读设备 ID

完整调用(IDCODE 不需要地址,DR 捕获即返回设备 ID):

jtag_ir_scan(build_ir(`JTAG_SOC0, `JTAG_SPACE_SRAM, `JTAG_OP_IDCODE), ir_tdo);  // 装入 IDCODE 指令
jtag_dr_scan(64, 64'h0, dr_tdo);  // 64=DR长度64bit; 64'h0=移入全0(读取无需输入); DR捕获→设备ID回读到dr_tdo
// 结果:dr_tdo[31:0] = `JTAG_DEVICE_ID("JTAG",bit0=1)

例 2:`JTAG_OP_WRITE(写 SoC1 寄存器 0x10)→ 拼出 8'h33
build_ir(`JTAG_SOC1, `JTAG_SPACE_REG, `JTAG_OP_WRITE) = {3'b001, 1'b1, 4'h3} = 8'h33
         └────┬────┘  └────┬────┘   └────┬────┘
            SoC1         寄存器        WRITE
含义
[7:5]`JTAG_SOC1SoC1(第 2 个 SoC)
[4]`JTAG_SPACE_REG寄存器空间(不是 SRAM)
[3:0]`JTAG_OP_WRITEWRITE 写操作

⚠️ IR 里没有地址和数据!「写哪个寄存器、写什么值」由紧随其后的 DR 扫描给出。

完整调用(testbench T5 中的实际用法):

// Step 1: 装入 WRITE 指令(SoC1 + 寄存器 + 写)
jtag_ir_scan(build_ir(`JTAG_SOC1, `JTAG_SPACE_REG, `JTAG_OP_WRITE), ir_tdo);   // 8'h33
// Step 2: 提供 目标寄存器地址(0x10) + 写入数据(0xABCD0001)
jtag_dr_scan(64, build_dr_rw(32'h0000_0010, 32'hABCD_0001), dr_tdo);  // 64=DR长度64bit({addr,data}); 0x0010=SoC1寄存器地址; 0xABCD0001=写入数据
//           └───── DR[63:32] = 0x10 寄存器地址 ──────┘
//                    DR[31:0]  = 0xABCD0001 写入数据
// 结果:SoC1.寄存器[0x10] 被写入 0xABCD0001

读操作对比(两步读协议)

若要 SoC1 寄存器 0x10,用 `JTAG_OP_READ(拼出 8'h32)+ 两次 DR 扫描:

// Step 1: 装入 READ 指令,DR 提供读地址(0x10) → 触发读取
jtag_ir_scan(build_ir(`JTAG_SOC1, `JTAG_SPACE_REG, `JTAG_OP_READ), ir_tdo);    // 8'h32 (READ)
jtag_dr_scan(64, build_dr_rw(32'h0000_0010, 32'h0), dr_tdo);  // 64=DR长度64bit; 0x0010=读地址; 数据位填0(读无需输入数据)
// Step 2: 再次 READ,DR 捕获返回读到的数据
jtag_ir_scan(build_ir(`JTAG_SOC1, `JTAG_SPACE_REG, `JTAG_OP_READ), ir_tdo);
jtag_dr_scan(64, 64'h0, dr_tdo);  // 64=DR长度64bit; 64'h0=移入全0(仅回读); 读数据在dr_tdo
// 结果:dr_tdo[31:0] = SoC1.寄存器[0x10] 的当前值

注:地址/数据为测试场景魔法数字,含义已在注释中说明。

本波形以 ir_data = 8'h33 (SoC1/REG/WRITE) 为例。
说明:tms_ir[7]=1,即最后一个移入 bit(bit7=MSB)时 TMS=1。

3.2 完整波形(以 ir_data = 8'h33 为例)

tms_ir[7]=1最后一个移入 bit(bit7=MSB)时 TMS=1,引导 TAP 从 Shift-IR 进入 Exit1-IR。

{
  "head": {"tick": 1},
  "signal": [
    {"name": "TCK", "wave": "p............."},
    {"name": "TAP", "wave": "44444444444444", "data": ["①","②","③","④","⑤","⑤","⑤","⑤","⑤","⑤","⑤","⑤","⑥","⑦"]},
    {"name": "TMS", "wave": "11000000000110"},
    {"name": "TDI", "wave": "00001100110000", "data": ["","","","","0","1","2","3","4","5","6","7","",""]},
    {"name": "TDO", "wave": "00001000000000", "data": ["","","","","0","1","2","3","4","5","6","7","",""]}
  ]
}

在这里插入图片描述

图例

  • TAP 标签: ①=RTI ②=Sel-DR ③=Sel-IR ④=Cap-IR ⑤=Shift-IR(×8) ⑥=Exit1-IR ⑦=Update-IR
  • TDI/TDO 数字: 移位 bit 序号(0 = LSB,最先移入/移出)

分步说明

TCK 周期TMSTDI动作TAP 状态跳转事件
C110RTI→SelDRRTI → Select-DR
C210SelDR→SelIRSelect-DR → Select-IR
C300SelIR→CapIRSelect-IR → Capture-IRCapture-IR: ir_reg <= {6'b0, 2'b01}(8位IR: 高6位填0 + 低2位捕获码01)
C400CapIR→ShiftIRCapture-IR → Shift-IR进入移位
C50ir_data[0]=1Shift bit0Shift-IRir_reg 右移,TDI 从高位插入
C60ir_data[1]=1Shift bit1Shift-IR同上
C70ir_data[2]=0Shift bit2Shift-IR同上
C80ir_data[3]=0Shift bit3Shift-IR同上
C90ir_data[4]=1Shift bit4Shift-IR同上
C100ir_data[5]=1Shift bit5Shift-IR同上
C110ir_data[6]=0Shift bit6Shift-IR同上
C121ir_data[7]=0Shift bit7Shift-IR → Exit1-IR最后 bit,TMS=1 退出移位
C1310Exit1→UpdateExit1-IR → Update-IRUpdate-IR: 指令生效
C1400Update→RTIUpdate-IR → RTI回到空闲

3.3 TDI/TDO 位序图(移位阶段 C5~C12)

  TDI 输入 (从右到左依次移入):
        ir_data[7]  ir_data[6]  ...  ir_data[1]  ir_data[0]
  C12   ▲           ▲                       ▲          ▲
  (MSB 最后)                              (LSB 最先) C5

  移位链内部:  TDI ──► ir_reg[7] → ir_reg[6] → ... → ir_reg[0] ──► TDO
                     (高位插入,右移,最低位移出)

  移完 8 bit 后: ir_reg = ir_data   (LSB-first 协议,自然位序)
  ir_tdo = 移位期间 TDO 依次采样的值(即 Capture-IR 装入的 8'b0000_0001 逐位移出)

3.4 ir_tdo 回读值说明

ir_tdo 拿到的是 IR 扫描链在 Capture-IR 时装入的值、移位期间从 TDO 逐位移出的结果——它是 scan-out(回读值),不是指令本身。

固定值 8'h01(与装入什么指令无关)。原因:jtag_debug_bridge.v 的 IR 扫描链在 Capture-IR 阶段装入固定值:

else if (ir_capture_en) begin
    ir_reg <= {{IR_WIDTH-2{1'b0}}, 2'b01};   // 装入 8'b0000_0001
end

移位时 TDO 输出 ir_reg[0](最低位先出),8 个移位周期(C5~C12)依次移出:

Capture 装入:  0000_0001
TDO 移出(LSB-first): 1 → 0 → 0 → 0 → 0 → 0 → 0 → 0
                     └── C5   C6   C7   C8   C9   C10  C11  C12
ir_tdo = 8'h01

对应 §3.2 波形 TDO 行 00001000000000(C5=1,其余 0)。

含义

  • 8'h01 = bit[1:0]=01,正是 JTAG 规范要求的 Capture-IR 固定捕获码,向主机表明"本设备存在 IR 扫描链 / 支持 IDCODE"
  • 完整 JTAG 设计中,Capture-IR 通常捕获当前已装入的指令寄存器值供主机读回确认;本例简化为固定 {6'b0,2'b01}

一句话总结

jtag_ir_scan(build_ir(`JTAG_SOC1, `JTAG_SPACE_REG, `JTAG_OP_WRITE), ir_tdo);
// ir_tdo = 8'h01  ← 只是回读的捕获码,与 WRITE 指令无关
// 真正生效的指令是 ir_data 移入的那 8 位

ir_tdo = 扫描链"吐出来"的旧值/捕获值(固定 8'h01);ir_data 才是"塞进去"的新指令。


3.5 Update-IR 影子指令寄存器(ir_latched

规范要求(IEEE 1149.1):IR 的并行输出(生效指令)只能在 Update-IR 状态改变,防止 Shift-IR 移位中途「半截指令」被组合逻辑误用。本设计用 TCK 域影子寄存器 ir_latched 实现。

// jtag_debug_bridge.v — IR 扫描链 + Update-IR 影子锁存
reg [IR_WIDTH-1:0] ir_reg;      // 移位寄存器(Capture/Shift 用,可被中途改写)
reg [IR_WIDTH-1:0] ir_latched;  // 影子指令寄存器(只在 Update-IR 更新)

// ir_reg: 仅 capture/shift 两分支(无 update 分支)
always @(posedge TCK or negedge TRST_n) begin
    if (!TRST_n) begin
        ir_reg <= {IR_WIDTH{1'b0}};
    end else if (ir_capture_en) begin
        ir_reg <= {{IR_WIDTH-2{1'b0}}, 2'b01};        // Capture-IR 捕获码
    end else if (ir_shift_en) begin
        ir_reg <= {ir_scan_in, ir_reg[IR_WIDTH-1:1]}; // Shift-IR 移位
    end
end

// ir_latched: 仅在 Update-IR(ir_update_en 脉冲)锁存移好的新指令
always @(posedge TCK or negedge TRST_n) begin
    if (!TRST_n)
        ir_latched <= {IR_WIDTH{1'b0}};               // 复位 = IDCODE
    else if (ir_update_en)                            // Update-IR 脉冲
        ir_latched <= ir_reg;                          // 锁存新指令
end

// 译码一律取自 ir_latched(稳定指令),不再直接读 ir_reg
assign ir_soc_id = ir_latched[IR_WIDTH-1 -: SOC_IDX_WIDTH];
assign ir_opcode = ir_latched[3:0];
assign ir_bypass = (ir_opcode == OP_BYPASS);

行为(注:锁存发生在离开 Update-IR 的 posedge,即 Update→RTI 边沿):

时刻ir_regir_latched(生效指令)
Shift-IR 移位中途逐位变化(半截新指令)保持上一指令不变
移位完成(Exit1-IR)= 新指令仍为上一指令
进入 Update-IR 瞬间= 新指令仍为上一指令(离开时才锁存)
离开 Update-IR(→RTI)= 新指令更新为新指令

验证:testbench 新增 T10: Shadow IR Latch (Update-IR),用分层引用 u_dut.ir_latched 直接观察:

[init]       ir_reg=0x00 ir_latched=0x00   ← 装入 IDCODE 后锁存生效
[mid-shift]  ir_reg=0x30 ir_latched=0x00   ← 移位中途: ir_reg 已是半截新指令, ir_latched 仍为旧指令
[pre-update] ir_reg=0x33 ir_latched=0x00   ← 移完 8bit, 未到 Update-IR, 锁存仍未更新
[in-update]  ir_reg=0x33 ir_latched=0x00   ← 进入 Update-IR 瞬间仍未更新(离开时锁存)
[after]      ir_reg=0x33 ir_latched=0x33   ← 离开 Update-IR 后锁存为新指令
Read-back:   0xdeadcafe                    ← 用新指令 WRITE 写 SoC1 REG[0x10] 读回生效

这样即使主机在 Shift-IR 中途暂停/退出,ir_reg 留下半截值,生效指令 ir_latched 也不受影响,符合 IEEE 1149.1 对指令并行输出稳定性的要求。


4. jtag_dr_scan 典型波形

4.1 调用示例

// 例:64-bit 数据扫描(IDCODE 读取,全 0 输入)
jtag_dr_scan(64, 64'h0, dr_tdo);  // 64=DR长度64bit; 64'h0=移入全0(IDCODE回读无需输入)

// 例:64-bit 读写扫描 {addr=0x40, data=0x1234_5678}
jtag_dr_scan(64, build_dr_rw(32'h0000_0040, 32'h1234_5678), dr_tdo);  // 64=DR长度64bit({addr,data}); 0x0040=写地址; 0x12345678=写入数据

4.2 完整波形(64-bit,TDI/TDO 用 x 表示数据移位)

{
  "head": {"tick": 1},
  "signal": [
    {"name": "TCK", "wave": "p...................................................................."},
    {"name": "TAP", "wave": "444444444444444444444444444444444444444444444444444444444444444444444", "data": ["①","②","③","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","④","⑤","⑥"]},
    {"name": "TMS", "wave": "100000000000000000000000000000000000000000000000000000000000000000110"},
    {"name": "TDI", "wave": "000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx00"},
    {"name": "TDO", "wave": "000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx00"}
  ]
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

图例TAP 标签 ①=RTI ②=Sel-DR ③=Cap-DR ④=Shift-DR(×64) ⑤=Exit1-DR ⑥=Update-DR

分步说明

TCK 周期TMS动作TAP 状态跳转事件
C11RTI→SelDRRTI → Select-DR
C20SelDR→CapDRSelect-DR → Capture-DRCapture-DR: dr_reg <= dr_capture_data
C30CapDR→ShiftDRCapture-DR → Shift-DR进入移位
C40Shift bit0Shift-DRdr_reg 右移
C50Shift bit1Shift-DR同上
C660Shift bit62Shift-DR同上
C671Shift bit63Shift-DR → Exit1-DR最后 bit,TMS=1
C681Exit1→UpdateExit1-DR → Update-DRUpdate-DR: 触发 sys_clk 域命令执行
C690Update→RTIUpdate-DR → RTI回到空闲

注意num_bits 可配置。例如 BYPASS 时 jtag_dr_scan(32, ...),则移位阶段为 C4~C35,尾部 C36~C37。

4.3 64-bit DR 数据布局

DR 位域长度内容移入顺序
DR[63:32]32 bitAddress(读写目标地址)后移入(C36~C67)
DR[31:0]32 bitData(写入数据 / 读时忽略)先移入(C4~C35)

移入顺序为 LSB-first:先移入低 32 位(Data),再移入高 32 位(Address)。


5. IDCODE 读回 TDO 波形

5.1 场景

// 装入 IDCODE 指令(等价于 8'h00)
jtag_ir_scan(build_ir(`JTAG_SOC0, `JTAG_SPACE_SRAM, `JTAG_OP_IDCODE), ir_tdo);
jtag_dr_scan(64, 64'h0, dr_tdo);   // 64=DR长度64bit; 64'h0=移入全0(仅回读); Capture 装入 {32'h0=高32位, `JTAG_DEVICE_ID=低32位}

5.2 TDO 波形(前 36 周期:3 导航 + 32 位 IDCODE)

`JTAG_DEVICE_ID = 0x4A544147 = “JTAG”,bit0=1 符合 JTAG 规范;移位期间按 LSB-first 逐位移出。

{
  "head": {"tick": 1},
  "signal": [
    {"name": "TCK", "wave": "p..................................."},
    {"name": "TDO", "wave": "000111000101000001000101010010100100", "data": ["","","","0","1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32"]}
  ]
}

在这里插入图片描述
在这里插入图片描述

图例TDO 数字 = 移出的 bit 序号(0 最先移出,即 LSB);波形电平 1/0 即该 bit 的值

说明:C4~C35 输出 `JTAG_DEVICE_ID0x4A544147)的 32bit(LSB-first,bit0=1 符合 JTAG 规范);C36 起为高 32 位(0x00000000)的 bit0=0。


6. TDO 输出语义

6.1 TDO 何时有意义

TDO 只有在 Shift-DR / Shift-IR 状态 时才输出有效数据,其余状态输出 0

// jtag_tap.v 中的 TDO 逻辑
always @(negedge TCK) begin
    if (tap_state == ST_SHIFT_IR)
        tdo_reg <= ir_scan_out[0];      // IR 链最低位
    else if (tap_state == ST_SHIFT_DR)
        tdo_reg <= dr_scan_out;         // DR 链最低位
    else
        tdo_reg <= 1'b0;
end

6.2 移位期间 TDO 采样的内容

  Capture 时刻装入扫描链的值(进入 Shift 前的那个 posedge):
    - IR:  Capture-IR 装入 {6'b0, 2'b01}  → 移位期间逐个移出
    - DR:  Capture-DR 装入 dr_capture_data(IDCODE/状态/读回数据)

  所以测试端在移位阶段采样到的 TDO 序列 = Capture 装入值按 LSB-first 移出

6.3 波形示例:IDCODE 读取

{
  "signal": [
    {"name": "TCK", "wave": "p.........."},
    {"name": "TDO", "wave": "1.1.1.0.0.0"}
  ]
}

在这里插入图片描述

说明:IR 扫描装入 `JTAG_OP_IDCODE(IDCODE),DR 扫描 Capture 装入 `JTAG_DEVICE_ID;最低位 bit0=1 符合 JTAG 规范。


7. 关键时序点总结

#关键点说明
1TMS/TDI 下降沿驱动testbench 在 @(negedge TCK) 改变信号,保证上升沿采样时稳定
2TDO 上升沿采样testbench 在 @(posedge TCK) 采样 TDO,与 TAP 的下降沿驱动错开半周期
3最后一位 TMS=1tms_ir[7]=1 / tms_dr[num_bits-1]=1 引导 TAP 从 Shift 进入 Exit1
4LSB-first 位序jtag_shift 从 i=0 循环到 num_bits-1,TDI[0] 先移入,TDO[0] 先移出
5Capture 先于 ShiftCapture-DR/IR 在进入 Shift 前的那个上升沿装入数据
6Update 触发执行Update-IR 把 ir_reg 锁存进影子寄存器 ir_latched(指令生效,规范要求);Update-DR 触发 sys_clk 域命令执行(经 CDC)
7两步读协议读取需两次 DR 扫描:第一次 Update-DR 执行读取,第二次 Capture-DR 返回数据
8IR 8bit / DR 可变IR 固定 8 bit;DR 长度由 num_bits 指定(IDCODE=32, R/W=64, BYPASS=32 等)
9影子指令寄存器译码取自 ir_latched(仅 Update-IR 更新),Shift-IR 中途保持稳定,符合 IEEE 1149.1

附录: 时序参数速查

事件起始周期结束周期周期数
IR 扫描: 导航C1C44
IR 扫描: 移位C5C128
IR 扫描: 退出C13C142
IR 扫描总计C1C1414 TCK
DR 扫描: 导航C1C33
DR 扫描: 移位C4C(3+N)N
DR 扫描: 退出C(4+N)C(5+N)2
DR 扫描总计 (N=64)C1C6969 TCK
DR 扫描总计 (N=32)C1C3737 TCK
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值