← SVIP demo · 文档与示例快照 · 运行库、历史验收记录及仿真日志未打包 · 阅读范围说明
SVIP · JTAG 0.2.0

syan · master / passive / device · chain helper · VCS / UVM1.2

SVIP JTAG 使用指导

Author: syan

1. 支持范围

当前提供 master、passive 与可选 TAP device 响应组件,目标 VCS/UVM1.2,采用 IEEE1149.1 的16态、IR/DR移位与Update语义。master自行生成TCK;passive可观察外部master。多 TAP 链使用可选 sequence helper 拼接,底层仍是一个串行 bit stream。

支持动态scan数组;默认 max_scan_bits=65536 是资源策略。高层scan默认从RTI开始、至少1bit,经Update返回RTI;可显式分段停在对应 Shift/Pause,再 resume。raw可表达Capture-only等路径。未知状态需先TMS5或TRST恢复;不会通过隐式导航提交用户未完成的scan。

当前不含BSDL/SVF/STAPL、IJTAG或DMI/JTAG2AXI业务层。自测夹具的IR长度、寄存器、IDCODE/opcode只属于fixture,不是产品限制;device 的默认配置只启用BYPASS,用户显式配置自己的指令和寄存器。

2. 编译与引脚接入

从仓库根编译,先加载模拟器的UVM1.2:

vcs -full64 -sverilog -ntb_opts uvm-1.2 -timescale=1ps/1ps \
  -f jtag/files.f -f jtag/sequence_lib/files.f \
  -f jtag/checker/files.f YOUR_DUT_AND_TEST_FILES -top YOUR_TOP

files.f包含common coverage service、interface和core package;sequence package与SVA是显式的后续输入。现有工程已编译common包时,按同样顺序只编译一次。

使用VCS三步流程时,先单独执行 vlogan -full64 -sverilog -ntb_opts uvm-1.2 分析UVM,再分别用vlogan加载上述filelist,最后vcs链接top。仅在含用户文件的vlogan命令上写 -ntb_opts,不能假设uvm_pkg已经分析;本版已原生验证分开分析的接入流程。

顶层创建 svip_jtag_if bus(tap_external_reset_n),连接DUT的TCK/TMS/TDI到对应interface变量,DUT的TDO回接 bus.tdo。有TRST引脚时DUT连接 bus.tap_reset_n,它是外部有效TAP reset与VIP生成TRST的组合。无TRST引脚时设置 cfg.has_trst=0,用TMS5恢复。

reset_n表示确实让目标TAP复位的外部源,不要连接一个不影响TAP的SoC reset。若没有这种源,tie high。trst_n由active VIP拥有,外部复位源通过 reset_n 接入,不与VIP争驱 trst_n。master拥有TCK,禁止再接另一个时钟发生器。

3. 创建agent

在已有UVM env/test的build_phase中:

svip_jtag_agent jtag;
svip_jtag_cfg cfg;
virtual svip_jtag_if vif;

// vif由顶层通过config_db发布,检查get()返回值。
cfg=svip_jtag_cfg::type_id::create("cfg");
cfg.vif=vif;
cfg.t_low=5ns;
cfg.t_high=5ns;
cfg.coverage_en=1;
cfg.tracker_filename="jtag.tracker.log";
jtag=svip_jtag_agent::type_id::create("jtag",this);
jtag.cfg=cfg;

顶层发布vif须在 run_test() 前完成;UVM run phase必须从仿真时间0启动。完整可执行示例在 testbench/tb.sv、svip_jtag_test_pkg.sv 和 testsuite/examples/,正式runner会编译并运行它们。

配置 默认 使用规则
is_active UVM_ACTIVE passive只创建观察链,无driver/sqr;build期设置
t_low/t_high 各50ns package/interface均1ps单位与精度,必须可表示且>=1ps;build期设置
t_low_max/t_high_max 0 0使用固定时长;非零为每bit均匀随机区间的上界,须>=对应最小值且<=4294967295ps
drive_delay 0 低相开始到TMS/TDI驱动的偏移,须<t_low;零保持原有NBA驱动方式
sample_delay 0 0在上升沿前采TDO;正值在上升沿后该偏移采样,须<t_high;TDO须在整个高相保持当前位
trst_low 150ns TRST命令的低脉冲时长,必须>=1ps;不依赖TCK运行
has_trst 1 无引脚时置0,TRST命令被拒绝
max_scan_bits 65536 配置范围1..2147483647(SV数组size容器),active长度上限、passive保留前缀上限;超限被拒绝/报告截断;首版实测上限65536
checks_en 1 使用 agent.set_checks(bit) 同时切换monitor与interface上的SVA enable
tracker_en 1 build期设置;空文件名使用agent实例全名
coverage_en 0 build期设置,创建native covergroup与公共FC采样;JSON另需plusarg
clock_hold 0 使用 agent.set_clock_hold(bit);当前高相完成后停低,释放后继续同一命令

时序在每个命令开始时冻结,命令中途修改不会改变该命令;下一命令重新验证。结构配置在build期设置。运行时即时控制只有 set_checks 与 set_clock_hold;用户扩展通过sequence、callback或device寄存器hook表达。

4. 发送scan与获得结果

便利sequence继承 svip_jtag_seq 并在 body() 中使用:

svip_jtag_txn r;
bit payload[];
reset_tms(r);                 // 五个TMS=1,结束于TLR
goto_state(SVIP_JTAG_RTI,r);
scan_word(1,64'hf,4,r);        // 示例设备4bit IR的BYPASS指令
payload=new[132];
foreach(payload[i])payload[i]=i%2;
dr_scan(payload,r);
if(r.status!=SVIP_JTAG_DONE)
  `uvm_error("MY_JTAG",r.convert2string())
foreach(r.rx_bits[i])begin
  // 示例BYPASS期望:第0位是Capture的0,后续位是前一个TDI。
  if(r.rx_bits[i] !== (i==0?1'b0:payload[i-1]))
    `uvm_error("MY_JTAG","BYPASS mismatch")
end

在test中 seq.start(jtag.sqr)。不要调用 svip_jtag_seq.body()直接驱动;标准start_item/finish_item负责仲裁和完成。

ir_scan/dr_scan以数组为权威长度,数组下标0最先移入。scan_word(is_ir,value,n,r)是最多64bit的便利转换,长数据使用数组。raw(tms[],tdi[],r)要求数组长度相等;空raw允许作为无操作,空高层scan拒绝。

finish_item()返回时命令已经完成或明确中止/拒绝,响应已回写原transaction。tx_bits可randomize,例如约束 op==SVIP_JTAG_DR_SCAN 和payload长度;无条件随机op可能产生不满足状态前置条件的控制命令,不能将其等同于合法场景生成器。

status 含义
SVIP_JTAG_DONE 命令完成,声明的结束状态已达到
SVIP_JTAG_RESET_ABORTED 外部reset中止或提交时仍在reset;不自动重试
SVIP_JTAG_BAD_REQUEST 状态/长度/资源/opcode不支持,报告 SVIP_JTAG_REQUEST,驱动前拒绝
SVIP_JTAG_X_RESPONSE 有效Shift样本含X/Z,原值保留在四态rx数组
SVIP_JTAG_COMPARE_ERROR 已完成采样,但显式TDO比较失败;n_mismatches给出不匹配位数

中止时rx数组可以包含未采样的尾部,只有前 n_sampled 位有效。中途取消时已经采到的位仍保留。start_state/end_state是执行器的协议预测状态,不是DUT内部状态的直接证明。

IR→DR之类组合在多个sequence间需要原子性时,使用标准sequencer lock/grab;单命令串行不阻止其他sequence在两笔命令之间插入。transaction支持深拷贝和严格字段比较;派生transaction应扩展自己的do_copy/do_compare。

5. 复位、时序与raw控制

TMS5复位、可选TRST、外部有效TAP reset是不同入口。异步effective reset使旧epoch失效,外部reset让在飞命令完成一次RESET_ABORTED;已发生的Update副作用不会回滚。外部reset后driver在下一笔命令前同步到TLR,用户通常再goto RTI。

TMS5是实际TMS路径,不强制更换引脚reset epoch;从Pause/Shift出发可能先经过Update再到TLR,因此不能用它保证半笔操作从未提交。TLR选择目标的默认指令;用户寄存器是否复位由设备语义决定。tms_reset_default专门检查这一区别。

master在低相设置TMS/TDI,等待t_low后读取前一个下降沿准备的TDO,再拉高TCK,等待t_high后拉低。该采样契约避免读取DUT同一上升沿移位后的下一位。低/高时间必须满足具体DUT的setup/hold和TDO clock-to-output,VIP不提供模拟电气时序认证。

没有READY式反压。命令结束后TCK保持低电平;停TCK不改变TAP状态,进入Pause需要真实TMS路径。RTI clocks可能触发设备行为,不能当作无副作用延迟。

5.1 分段scan、Pause和运行时停钟

dr_scan(first_bits,r,SVIP_JTAG_PAUSE_DR);  // 采样完成,尚未Update
dwell(8,r);                              // Pause内产生8个TCK,保持移位内容
dr_scan(rest_bits,r,SVIP_JTAG_RTI,1);      // resume=1;继续移位,最终Update

finish_state只允许RTI、与操作匹配的Shift或Pause;resume=1只允许从同种Shift/Pause继续。默认fresh scan从RTI开始。每段结果只含本段位;monitor在最终Update发布一条累计scan。Pause不加位直接提交用 goto_state(SVIP_JTAG_RTI,r);从Shift退出会再移一位,不能用goto声称无额外位提交。dwell(cycles,r)只接受TLR/RTI/Pause与1..max_scan_bits时钟数,拒绝在Shift填充隐式数据。

多个sequence并行时,在完整的分段scan或IR/DR组合外使用标准sequencer lock()/unlock();driver串行执行单条命令,组合的原子性由调用sequence持有。

agent.set_clock_hold(1)完成当前高相,并在下一上升沿前等待;命令可能仍在 finish_item() 中。需由另一并行控制线程释放,或由外部reset中止。TRST命令不依赖TCK;TMS5仍需要时钟。hold不是进入Pause,也不会中止或重发事务。每个bit的随机时长独立取样;默认固定时序不增加RNG调用,指定seed可以重放。

5.2 TDO比较与mask

svip_jtag_txn t=new("read_check");
t.op=SVIP_JTAG_DR_SCAN;
t.tx_bits=payload;
t.check_tdo=1;
t.expected_bits=expected;  // logic[],长度与payload相同
t.compare_mask=mask;       // bit[],1比较、0忽略;空数组表示全比较
send(t);

长度不匹配在驱动前拒绝。比较使用四态精确比较,失败每命令报告一条 SVIP_JTAG_COMPARE。reset中止不比较未采样尾部。有效Shift的X检查独立于业务mask;mask全零也不会掩盖X_RESPONSE。X_RESPONSE优先于COMPARE_ERROR,仍保留mismatch计数。复杂比较通过transaction表达,不给scan helper增加一组重复参数。

5.3 多TAP chain

TDI -> TAP[0] -> TAP[1] -> TAP[2] -> TDO
发送顺序:TAP[2]的LSB-first字 -> TAP[1] -> TAP[0]

在sequence中导入 svip_jtag_seq_pkg,创建 svip_jtag_chain chain。设置 ir_lengths 与当前指令所选的 dr_lengths,两者均按TDI到TDO的物理节点顺序。svip_jtag_words_t 是动态bit数组的数组;每个节点的字长必须精确匹配。调用 ir_scan(chain.pack_ir(ir_words),r)、dr_scan(chain.pack_dr(dr_words),r),用 svip_jtag_logic_words_t received=chain.unpack_dr(r.rx_bits) 得到相同物理节点顺序的四态结果。

其他TAP选BYPASS时,其IR全1、DR长度1。helper不猜测设备指令或实际DR长度,不把高位静默截断。IR至少2bit,DR至少1bit,合计受 chain.max_bits 限制。IR与DR组合需要原子性时仍用标准sequencer lock。example_chain 使用3/5/7-bit IR和不同寄存器值;chain_target 演示只选中中间TAP。

5.4 可选TAP device与外挂寄存器

在env的build_phase创建一个独立响应组件:

svip_jtag_device device;
svip_jtag_register reg0=new("control");
device=svip_jtag_device::type_id::create("device",this);
device.cfg=new("device_cfg");
device.cfg.vif=vif;
device.cfg.ir_length=4;
reg0.opcode='{0,1,0,0};       // LSB-first opcode 2
reg0.reset_bits=new[65];     // 任意动态寄存器长度
foreach(reg0.reset_bits[i])reg0.reset_bits[i]=0;
device.cfg.registers.push_back(reg0);

device只驱动TDO;同一interface不能再有DUT或另一个device争驱TDO。需要日志、coverage或checker时,在同一interface接passive agent与显式SVA;不要创建第二个active master。

配置/扩展 规则
ir_length/max_bits 默认4/65536;IR>=2,寄存器非空,大小受max_bits限制
BYPASS IR全1,DR固定1bit,Capture为0;已知未映射指令也进入BYPASS
has_idcode/idcode/idcode_opcode 默认不启用;启用时显式给出等长opcode与32bit、bit0=1的IDCODE;不能占用BYPASS
registers 每个opcode等于IR长度、唯一、不与IDCODE/BYPASS冲突;reset_bits声明宽度和物理reset值
read_only 基础register忽略Update;派生类覆盖update时自行负责业务权限
capture()/update(logic bits[])/reset() 可派生register外挂存储,不要求调用super;均为零时间function,不能阻塞TCK
tco 默认0;相对下降沿的TDO延迟,必须满足实际master的采样窗口,延迟输出带reset代际检查

结构与opcode在build时冻结,register对象是有意保留的业务扩展句柄;不要运行中更改宽度、opcode或reset_bits定义。Capture必须返回声明的宽度。Shift用环形存储,每bit常数开销,Update时再物化位序。TLR/TMS5只选择默认指令,不清除用户存储;effective pin reset同时复位TAP和register。未知IR保留不确定性,不能二态转换为已知指令。

device在posedge先保存TMS/TDI与epoch,经同槽reset/NBA检查后调用Capture/执行Shift;Update hook在有效下降沿调用。外挂存储的capture函数读取该调用时刻的业务模型值。

example_device 是产品自环示例;device_manual、device_wide_ir、device_long 使用独立手工master检查,device_hooks 展示外部存储及软件/物理reset的区别。device不是DMI或CPU调试模型,业务协议应独立实现。

6. 观察、callback和tracker

analysis对象按只读使用,producer不会重用其动态payload。callback的pre_command接收staging,可改pattern;driver随后深拷贝为运行快照。post_command用于通知,修改通知不会改变用户结果。不要在callback里驱引脚或添加阻塞时序。

注册方式:uvm_callbacks#(svip_jtag_driver,svip_jtag_callback)::add(jtag.drv,callback_handle)。参考 copy_callback 的快照隔离测试和 example_callback。

tracker默认输出CMD、SCAN、RESET,时间为ps;包含epoch、状态、请求/实采位数、提交/中止和四态数据摘要。数据摘要明确标注低64bit与truncated,长数据的完整内容由transaction/AP消费;没有默认逐bit打印开销。

7. 检查与coverage

monitor提供采样窗口X、状态未知传播和资源限制检查;SVA需在顶层显式实例化,见checker/README。SVA和monitor独立报告,各有rule ID,负例预算分别核对。set_checks(0)只关闭可选协议诊断,不解除资源限制或参数验证。

coverage采样实际命令终结、真实scan和TAP事件。包括op/status/长度、resume/请求结束态/比较开关、IR/DR/提交、实际TDI pattern分类(empty/zero/one/alternating/mixed/unknown/truncated)、32条状态出边、未知和reset。默认分母包括未命中能力,不以非零覆盖率声称完整认证。

开启 cfg.coverage_en=1 并传 +svip_fc_json=path.json,agent在final_phase导出。runner使用common的FC格式检查器验证产物、实际样本数和身份,regress只合并通过运行。覆盖文件和native covergroup是不同证据,本版发布以经过审计的FC JSON bin计数为覆盖结论,不宣称原生VDB合并闭环。

8. 自测与排查

先执行examples,再full suite。--waves默认直接生成FSDB(VCS/Verdi环境,使用 -debug_access+all -kdb 和dump宏),--waves vcd可回退;未请求波形时不dump。建议观察TCK/TMS/TDI/TDO、tap_reset_n、reset_epoch、DUT state和Update计数。唯一run目录内有run.log、result.json、tracker.log、fc.json及请求的waves.fsdb/vcd,格式与哈希写入result.json。

python3 jtag/scripts/run.py --case example_chain --case example_segmented --waves
python3 jtag/scripts/run.py --case example_device --waves vcd

源文件、catalog、运行器或公共FC消费者变化会使缓存身份变化;编译后检测输入变化则拒绝沿用结果。不要手动编辑已冻结结果或将失败run的coverage并入发布。当前实测点与未验收范围见verification.md。