资讯详情

资讯详情

Testbench不只看波形:用scoreboard抓住丢包、重复和乱序

Testbench不只看波形用scoreboard抓住丢包、重复和乱序最后一笔数据丢了前面的比较却全部通过两笔数据交换了位置输入输出总数仍然相等。检查流水线时这两种情况很容易被“波形看着正常”漏掉。本文用一个实际运行过的SystemVerilog实验说明怎样检查输入握手建立期望队列输出握手逐笔比较最后用有环境保证的排空窗口检查未交付事务。正常FIFO加上五种故障通道分别验证检查器能否抓住丢中间笔、重复、乱序、阻断和丢末笔。一 先确定scoreboard检查哪一段实验链路是源 → 同步FIFO → 仿真故障通道 → 接收端。FIFO的输入输出都是16位数据测试用唯一递增的ID作为数据功能约定是按序原样转发一进一出。这里没有多拍包边界也没有允许乱序的事务。期望值只来自输入端成功握手的历史不读取DUT的存储器、指针也不拿实际输出反过来生成答案。源端准备发送不等于FIFO已经接收只有上升沿的s_valid s_ready成立才将该笔数据记入expected。接收端也只在m_valid m_ready成立时消费一笔。如果真实数据没有可观察的ID两笔相同数值交换后单看数据无法区分。若规格允许乱序则应依据真实事务ID与顺序约束设计匹配规则不能直接套用这里的队首比较。这种期望队列方法也能在cocotb-bus的官方scoreboard实现中看到默认按队首比较并在收尾检查剩余期望事务。本实验直接用SystemVerilog实现不依赖cocotb。二 把FIFO语义和采样时刻固定下来被测FIFO采用同步高有效复位组合首字直出空时没有同拍输入直通。满时执行保守策略即使本拍要读出也不接受新写入下一拍才能恢复ready。完整可复制模块见文末附录Artl/sync_fifo.sv。其中push/pop只取有效握手指针在末地址显式回绕占用按入队与出队更新。附录A包含完整端口与声明。指针显式在DEPTH-1回绕因此测试中特别包含深度3已运行的深度为1、3、4、5、8不等于验证了所有参数。存储器不清零m_valid0时不能解释m_data。驱动在下降沿修改输入检查器在上升沿取握手值与输出数据DUT使用非阻塞赋值更新状态。检查器先记录更新前占用再延迟1 ns核对更新后占用。时钟周期10 ns这个1 ns是本测试平台的采样安排不是接口协议规定。三 检查器至少要有三种失败出口完整检查器在文末附录Ctb/tb_fifo.sv可直接复制不需另找文件。head、tail初值均为0expected是4096项16位数组本轮最大仅接收41笔因此不会越界它是一次性、有限规模测试用的期望队列。这里有两个即时失败出口队列有内容但数据不符记为mismatch没有期望值却收到输出记为unexpected。先处理输出、再处理输入是针对本FIFO“空时不直通”的约定防止非法的同拍直通拿刚入队的值自我匹配。第三个出口是排空超时。否则丢掉最后一笔后没有后续输出触发比较测试可能静默结束。附录C中的drain任务实现这个检查tick(0,0,1)表示不再提供输入、接收端持续ready。40拍即400 ns是本实验的排空预算。测试还设有20 μs全局watchdog防止驱动本身永久等待。expected提前清空后也继续观察到排空窗口结束以捕获晚到的额外输出有限窗口无法排除窗口之后才发生的错误。真实工程需要从最大延迟、结束协议和环境服务保证中确定期限。另外保留三类协议检查背压期间valid与data保持、满空保护、占用递推及边界。数据正确与协议正确必须分别检查。例如输出暂停时不断更换data即使最终被采样的一笔碰巧正确仍然违反本实验的稳定性约定。四 用负向测试证明检查器会报错故障通道位于真实FIFO之后只改变传输事务不篡改expected。正常模式直连五个负向模式分别丢ID 5、重复ID 2、交换前两笔、从ID 5起阻断、丢最后的ID 7。它们是人为注入的错误不表示FIFO本身发现了这些缺陷。下表摘自实际日志汇总。六个案例输入均为ID 0至7FIFO深度8pending表示期望队列尚未消费的项数。案例接受/收到mismatchunexpectedpending排空超时正常 good_d88/80000丢中间笔 drop_middle8/72011重复 duplicate8/95100交换前两笔 reorder8/82000阻断 stall_timeout8/50031丢末笔 drop_tail8/70011图1由xsim导出的CSV生成。横轴是接收事务的序号不是时钟灰色虚线是期望ID蓝线是实际成功握手接收的ID。末笔丢失和阻断案例的蓝线都没有继续延伸所以仅比较已经收到的点无法发现未交付项。原始日志中的关键行如下# duplicate CHECK MISMATCH cycle13 index3 expected3 got2 CHECK UNEXPECTED cycle18 got7 # reorder CHECK MISMATCH cycle10 index0 expected0 got1 CHECK MISMATCH cycle11 index1 expected1 got0 # drop_tail CHECK TIMEOUT after40_drain_cycles pending1 next_expected7 RESULT EXPECTED_FAILURE_DETECTED mode5重复ID 2之后检查器继续逐项移队不做错误恢复因此会连带出现5次mismatch最后还有一次unexpected。不能把“5次不匹配”解读为注入了5处故障。丢ID 5后超时日志显示next_expected7也是队列继续消费后的当前位置不能据此反推根因一定是丢ID 7。负向案例以EXPECTED_FAILURE_DETECTED结束表示预期错误被检测到。测试平台还会检查错误类型乱序必须恰好产生两个mismatch且没有超时重复必须出现mismatch与unexpected若不满足则$fatal。这样可避免把“乱序变体意外卡死”误判为检查器有效。超时本身只能说明期限内未完成无法单独区分永久丢失与过度延迟。五 正常通道也要压到边界只验证错误会报警还不够检查器也不能误报正常背压。定向握手场景先填满FIFO保持一笔未接受输入随后交叠读写跨越多次指针回绕最后排空。深度接受/收到背压周期同拍入队与FIFO出队空时读机会841/4153333134/3437072336/3653338这三个案例的mismatch、unexpected、timeout、protocol均为0。深度1没有同拍读写来自本设计“满时不替换、空时不直通”的策略不能要求它具有非空非满状态的吞吐行为。表中的空时读机会是观察计数不是已经读到了数据也不是完整功能覆盖率。还有一个容易忽视的边界scoreboard只检查被接受的事务。容量实验中源总共提供5笔深度4的入口只接受4笔并丢弃1笔scoreboard仍会得到4/4正确。因此对无法立即停止的源还要单独记录offered、accepted和入口丢弃数不能用scoreboard通过替代端到端无损判断。六 运行命令与复现材料本次在Windows上使用Vivado Simulator v2022.1xsim SW Build 3526262SystemVerilog编译参数--sv时间精度1 ps。文末附录给出全部5个输入文件、建目录方法、参数生成逻辑和运行命令读者不需要访问私有实验包。完整testbench中的日志格式与上面的实测摘录一致。运行器使用xvlog.bat --sv编译、xelab.bat -f生成快照、xsim.bat -f执行案例。编译、展开、运行快照的分工见AMD UG900 2022.1从文件加载运行选项见xsim命令选项。本文附录版本已在新的工作目录完成一次完整复测Windows上的PowerShell 7.6.5解析错误数为0运行器退出码为01次编译、5次展开和14次xsim仿真共20次工具调用退出码均为0。全部14例由同一次运行器自动执行suite_result.txt记录ALL_CASES_VALIDATED14。9个正常通道案例的已接受事务全部正确交付5个故障案例产生预期检测结果。本文表格和日志与这次复测一致。早期Python教学模型使用16笔事务与随机间隙这里新增的RTL故障实验使用8笔确定性事务故障ID、周期和计数不能混用。这次结果只覆盖列出的RTL仿真场景没有验证中途复位恢复、异步CDC、综合资源、时序或板级行为。复用时先写清顺序与身份规则再让monitor只记录真实握手最后同时检查数据、额外输出和有期限的未交付事务。故障注入用来检验检查器波形与逐周期日志用来解释首个失败位置两者合起来才能把“看起来正常”变成可复现的判断。运行器自动生成参数文件。例如丢末笔案例使用的evidence/elab_d8.args与evidence/drop_tail.args分别如下无需额外手工创建tb_fifo -s fifo_d8 -generic_top DEPTH8 -debug typicalfifo_d8 -tclbatch ../scripts/run.tcl -testplusarg MODE5 -testplusarg SCENARIO0 -log drop_tail/simulator.log -wdb drop_tail/wave.wdb附录 仅用本文代码复现实验下面给出完整的5个文件。无需下载附件或访问其他文章在已安装Vivado 2022.1的Windows电脑上按文件名保存代码即可复现。三个SystemVerilog文件、Tcl和PowerShell运行器均与本次14例统一复测版本一致。运行器要求显式传入本机Vivado路径已在Windows上的PowerShell 7.6.5和Vivado 2022.1运行通过。这里不依赖Python、matplotlib或未公开脚本。先在自己选择的工作位置打开PowerShell建立一个新的空目录如果同名目录已存在请换一个目录名New-Item-ItemType Directory-Path.\fifo_reproSet-Location.\fifo_reproNew-Item-ItemType Directory-Path rtl,tb,scripts接着将附录A至E分别保存为标题中的相对路径文件名不要多出.txt。完成后目录应只有这5个输入文件evidence和参数文件由运行器自动创建fifo_repro/ rtl/sync_fifo.sv tb/fault_channel.sv tb/tb_fifo.sv scripts/run.tcl scripts/run_all.ps1保持当前工作目录为fifo_repro执行下列命令。命令中的C:\path\to\Vivado\2022.1\bin只是示意-VivadoBin必须填成本机已安装Vivado的bin目录无需把bin加入PATH。系统需允许执行自己保存的PowerShell脚本若受到组织策略限制应按本机管理要求处理不要绕过策略。.\scripts\run_all.ps1-VivadoBinC:\path\to\Vivado\2022.1\binGet-Content.\evidence\suite_result.txtSelect-String-Path.\evidence\*\console.log-Pattern^SUMMARY,^RESULT本次完整运行实际生成了ALL_CASES_VALIDATED14读者成功复现时也应得到这一标记。正常案例应出现RESULT PASS五个负向案例应出现RESULT EXPECTED_FAILURE_DETECTED。运行器检查进程退出码、对应标记和Fatal/Error任一步失败会停止不应把不完整输出当作完成。每个案例的日志、CSV、VCD和WDB位于evidence/案例名/。scoreboard案例重点看good_d8、drop_middle、duplicate、reorder、stall_timeout、drop_tail容量案例重点看burst_d3、burst_d4、burst_d5、tail_d4、tail_d5。全套还包括3个握手边界案例。波形中的无效数据只在对应valid成立时解释VCD不能记录本例的unpacked存储数组接口握手、标量状态与CSV仍可用于定位。重复执行会覆盖同名日志与波形。先备份需要保留的历史记录本文图表是既有记录的可视化不是复现脚本的必需输入。附录 Artl/sync_fifo.svtimescale 1ns/1ps // Single clock, synchronous active-high reset, first-word fall-through read. // DEPTH 1. Full is conservative: no enqueue on a fulldequeue edge. module sync_fifo #(parameter integer WIDTH16, DEPTH8)( input wire clk, rst, input wire s_valid, output wire s_ready, input wire [WIDTH-1:0] s_data, output wire m_valid, input wire m_ready, output wire [WIDTH-1:0] m_data, output reg [$clog2(DEPTH1)-1:0] occupancy ); localparam integer PW(DEPTH1)?1:$clog2(DEPTH); reg [WIDTH-1:0] mem[0:DEPTH-1]; reg [PW-1:0] wr_ptr, rd_ptr; wire pushs_valid s_ready; wire popm_valid m_ready; assign s_ready!rst (occupancyDEPTH); assign m_valid!rst (occupancy!0); assign m_datamem[rd_ptr]; // Meaningful only when m_valid1. function automatic [PW-1:0] next_ptr(input [PW-1:0] p); next_ptr(pDEPTH-1)?0:p1b1; endfunction always (posedge clk) begin if (rst) begin wr_ptr0; rd_ptr0; occupancy0; end else begin if (push) begin mem[wr_ptr]s_data; wr_ptrnext_ptr(wr_ptr); end if (pop) rd_ptrnext_ptr(rd_ptr); case ({push,pop}) 2b10: occupancyoccupancy1b1; 2b01: occupancyoccupancy-1b1; default: occupancyoccupancy; endcase end end initial if (DEPTH1) $fatal(1,DEPTH must be 1); endmodule附录 Btb/fault_channel.svtimescale 1ns/1ps // SIMULATION-ONLY channel mutation after the real FIFO. // 0pass; 1drop ID 5; 2duplicate ID 2; 3swap first pair; // 4stop forwarding ID 5 onward; 5drop final ID 7. module fault_channel( input wire clk, rst, input integer mode, input wire i_valid, output reg i_ready, input wire [15:0] i_data, output reg o_valid, input wire o_ready, output reg [15:0] o_data ); reg replay, injected; reg [15:0] saved, first, second; integer state; always * begin i_readyo_ready; o_validi_valid; o_datai_data; if ((mode1 i_data5) || (mode5 i_data7)) begin i_ready1; o_valid0; end if (mode2 replay) begin i_ready0; o_valid1; o_datasaved; end if (mode3) begin case (state) 0,1: begin i_ready1; o_valid0; end 2: begin i_ready0; o_valid1; o_datasecond; end 3: begin i_ready0; o_valid1; o_datafirst; end default: begin end endcase end if (mode4 i_valid i_data5) begin i_ready0; o_valid0; end if (rst) begin i_ready0; o_valid0; end end always (posedge clk) begin if (rst) begin replay0; injected0; state0; saved0; first0; second0; end else begin if (mode2) begin if (replay o_ready) replay0; else if (i_valid i_ready i_data2 !injected) begin savedi_data; replay1; injected1; end end if (mode3) begin case(state) 0: if(i_valid i_ready) begin firsti_data; state1; end 1: if(i_valid i_ready) begin secondi_data; state2; end 2: if(o_valid o_ready) state3; 3: if(o_valid o_ready) state4; default: begin end endcase end end end endmodule附录 Ctb/tb_fifo.svtimescale 1ns/1ps module tb_fifo; parameter integer DEPTH8; reg clk0; always #5 clk~clk; reg rst1, s_valid0, m_ready0; reg [15:0] s_data0; wire s_ready, f_valid, f_ready, m_valid; wire [15:0] f_data,m_data; wire [$clog2(DEPTH1)-1:0] occupancy; integer mode0, scenario0; sync_fifo #(.DEPTH(DEPTH)) dut(clk,rst,s_valid,s_ready,s_data,f_valid,f_ready,f_data,occupancy); fault_channel channel(clk,rst,mode,f_valid,f_ready,f_data,m_valid,m_ready,m_data); // The expected queue derives only from upstream accepted transactions. // It never uses DUT memory, pointers, or observed output as expected data. reg [15:0] expected[0:4095]; integer head0,tail0,rx0,mismatch0,unexpected0,protocol0,timed_out0; integer cycle0, physical0, peak0,blocked0,empty_checks0,simultaneous0; integer trace,accepts_before, rejects0, offered0; reg in_stall0, out_stall0, fifo_stall0; reg [15:0] prev_in,prev_out,prev_fifo; integer a,d,p,preq,sr_sample,mv_sample,md_sample; always (posedge clk) begin if (!rst) begin cyclecycle1; preqoccupancy; sr_samples_ready; mv_samplem_valid; md_samplem_data; as_valid s_ready; dm_valid m_ready; pf_valid f_ready; if (in_stall (!s_valid || s_data!prev_in)) begin protocolprotocol1; $display(CHECK INPUT_STABILITY cycle%0d,cycle); end if (out_stall (!m_valid || m_data!prev_out)) begin protocolprotocol1; $display(CHECK OUTPUT_STABILITY cycle%0d,cycle); end if (fifo_stall (!f_valid || f_data!prev_fifo)) begin protocolprotocol1; $display(CHECK FIFO_STABILITY cycle%0d,cycle); end // Consume before enqueue so an illegal empty bypass cannot self-match. if (d) begin rxrx1; if(headtail) begin unexpectedunexpected1; $display(CHECK UNEXPECTED cycle%0d got%0d,cycle,m_data); end else begin if(m_data!expected[head]) begin mismatchmismatch1; $display(CHECK MISMATCH cycle%0d index%0d expected%0d got%0d,cycle,head,expected[head],m_data); end headhead1; end end if(a) begin expected[tail]s_data; tailtail1; end if(s_valid !s_ready) blockedblocked1; if(!f_valid f_ready) empty_checksempty_checks1; if(a p) simultaneoussimultaneous1; physicalphysicala-p; if(preqDEPTH s_ready) begin protocolprotocol1; $display(CHECK FULL_READY); end if(preq0 f_valid) begin protocolprotocol1; $display(CHECK EMPTY_VALID); end in_stalls_valid !s_ready; prev_ins_data; out_stallm_valid !m_ready; prev_outm_data; fifo_stallf_valid !f_ready; prev_fifof_data; #1; if(occupancy!physical || physical0 || physicalDEPTH) begin protocolprotocol1; $display(CHECK OCCUPANCY cycle%0d actual%0d expected%0d,cycle,occupancy,physical); end if(occupancypeak) peakoccupancy; $fdisplay(trace,%0d,%0d,%0d,%0d,%0d,%0d,%0d,%0d,%0d,%0d,%0d,%0d,%0d,%0d,cycle,scenario,mode,DEPTH,s_valid,sr_sample,s_data,mv_sample,m_ready,md_sample,a,d,preq,occupancy); end end task tick(input reg v, input integer data, input reg ready); begin (negedge clk); s_validv; s_datadata; m_readyready; (posedge clk); #2; end endtask task drain; integer n; begin for(n0;n40;nn1) tick(0,0,1); if(head!tail) begin timed_outtimed_out1; $display(CHECK TIMEOUT after40_drain_cycles pending%0d next_expected%0d,tail-head,expected[head]); end end endtask integer n,id,seen; initial begin if($value$plusargs(MODE%d,mode)) begin end if($value$plusargs(SCENARIO%d,scenario)) begin end trace$fopen(trace.csv,w); $fdisplay(trace,cycle,scenario,mode,depth,s_valid,s_ready,s_data,m_valid,m_ready,m_data,enqueue,dequeue,occupancy_before,occupancy_after); $display(CONFIG depth%0d mode%0d scenario%0d period10ns languageSystemVerilog,DEPTH,mode,scenario); repeat(3) (negedge clk); rst0; // scenario 0: 8 transactions, then drain. Used for all channel mutations. if(scenario0) begin for(n0;n8;nn1) tick(1,n,0); drain(); end // scenario 1: saturate, keep valid/data stable during backpressure, // then overlap reads/writes across many pointer wraps and empty drain. if(scenario1) begin for(n0;nDEPTH;nn1) tick(1,n,0); for(n0;n4;nn1) tick(1,DEPTH,0); tick(1,DEPTH,1); // full at edge: read yes, enqueue no. tick(1,DEPTH,1); // held transaction accepted on this edge. for(nDEPTH1;nDEPTH33;nn1) begin accepts_beforetail; tick(1,n,1); while(tailaccepts_before) tick(1,n,1); end drain(); end // scenario 2: rigid 6-cycle burst; source obeys backpressure if needed. // No reads for 3 cycles, then read one item on every second cycle. if(scenario2) begin id0; for(n0;n6;nn1) begin accepts_beforetail; tick(1,id,(n3 n%21)); if(tailaccepts_before) idid1; end while(id6) begin accepts_beforetail; tick(1,id,1); if(tailaccepts_before) idid1; end drain(); $display(BURST nominal6 accepted%0d blocked_cycles%0d peak%0d,tail,blocked,peak); end // scenario 3: upstream cannot pause immediately. q02, tail3, // no reads before stop takes effect. Bridge loses rejected offers. // Offered ! accepted: scoreboard checks accepted stream; separate // ingress-loss counter is mandatory for this non-backpressurable source. if(scenario3) begin for(n0;n2;nn1) tick(1,n,0); $display(TAIL stop_issued occupancy%0d tail_offers3 required_depth5,occupancy); for(n2;n5;nn1) begin accepts_beforetail; tick(1,n,0); offeredoffered1; if(tailaccepts_before) begin rejectsrejects1; $display(CHECK INGRESS_LOSS offer_id%0d full_depth%0d,n,DEPTH); end end // Explicit lossy ingress bridge ends the offer; waive only its // source-side ready/valid hold check. The FIFO checks stay enabled. in_stall0; drain(); $display(TAIL_RESULT initial2 offered_tail%0d accepted%0d ingress_lost%0d peak%0d,offered,tail,rejects,peak); end $display(SUMMARY accepted%0d received%0d pending%0d mismatch%0d unexpected%0d timeout%0d protocol%0d peak%0d blocked%0d simultaneous%0d empty_checks%0d ingress_lost%0d,tail,rx,tail-head,mismatch,unexpected,timed_out,protocol,peak,blocked,simultaneous,empty_checks,rejects); if(mode0) begin if(mismatchunexpectedtimed_outprotocol!0) $fatal(1,GOOD_MODEL_FAILED); if(scenario1 (blocked0 || (DEPTH1 simultaneous0) || empty_checks0)) $fatal(1,COVERAGE_MISSING); if(scenario3 rejects!((DEPTH5)?5-DEPTH:0)) $fatal(1,TAIL_LOSS_COUNT_WRONG); $display(RESULT PASS correct accepted-transaction stream); end else begin if(protocol!0) $fatal(1,UNEXPECTED_PROTOCOL_ERROR); case(mode) 1: if(mismatch0 || timed_out0) $fatal(1,DROP_NOT_DETECTED); 2: if(mismatch0 || unexpected0) $fatal(1,DUPLICATE_NOT_DETECTED); 3: if(mismatch!2 || timed_out!0 || head!tail) $fatal(1,REORDER_NOT_DETECTED); 4,5: if(timed_out0) $fatal(1,STALL_OR_TAIL_DROP_NOT_DETECTED); default: $fatal(1,INVALID_MODE); endcase $display(RESULT EXPECTED_FAILURE_DETECTED mode%0d,mode); end $fclose(trace); $finish; end initial begin #20000; $fatal(1,GLOBAL_WATCHDOG); end endmodule附录 Dscripts/run.tclopen_vcd wave.vcd log_vcd [get_objects -r *] run all close_vcd quit附录 Escripts/run_all.ps1param([Parameter(Mandatory$true)][string]$VivadoBin)$ErrorActionPreferenceStop$rootSplit-Path-Parent$PSScriptRoot$evidenceJoin-Path$rootevidenceNew-Item-ItemType Directory-Force-Path$evidence|Out-NullPush-Location$evidencetry{functionInvoke-Hdl([string]$Tool,[string[]]$ToolArgs,[string]$Log){COMMAND:$Tool$($ToolArgs-join )|Add-Contentcommands.log (Join-Path$VivadoBin$Tool)ToolArgs 21|Tee-Object-FilePath$Log$code$LASTEXITCODEEXIT:$code|Add-Contentcommands.logif($code-ne0){throw$Toolfailed with exit$code}}UTC:$([DateTime]::UtcNow.ToString(o))nLanguage: SystemVerilog (xvlog --sv)nClock: 10ns; time resolution: 1ps|Set-Contentenvironment.txtforeach($toolinxvlog.bat,xelab.bat,xsim.bat){(Join-Path$VivadoBin$tool)-version 21|Add-Contentenvironment.txt}|Set-Contentcommands.logInvoke-Hdlxvlog.bat(--sv,../rtl/sync_fifo.sv,../tb/fault_channel.sv,../tb/tb_fifo.sv)compile.log$cases({Namegood_d8;Depth8;Mode0;Scenario0},{Namehandshake_d8;Depth8;Mode0;Scenario1},{Namehandshake_d1;Depth1;Mode0;Scenario1},{Namehandshake_d3;Depth3;Mode0;Scenario1},{Namedrop_middle;Depth8;Mode1;Scenario0},{Nameduplicate;Depth8;Mode2;Scenario0},{Namereorder;Depth8;Mode3;Scenario0},{Namestall_timeout;Depth8;Mode4;Scenario0},{Namedrop_tail;Depth8;Mode5;Scenario0},{Nameburst_d5;Depth5;Mode0;Scenario2},{Nameburst_d4;Depth4;Mode0;Scenario2},{Nameburst_d3;Depth3;Mode0;Scenario2},{Nametail_d5;Depth5;Mode0;Scenario3},{Nametail_d4;Depth4;Mode0;Scenario3})$built{}foreach($casein$cases){$depth$case.Depth;$name$case.Nameif(!$built.ContainsKey($depth)){tb_fifon-s fifo_d$depthn-generic_top DEPTH$depthn-debug typical|Set-Contentelab_d$depth.argsInvoke-Hdlxelab.bat(-f,elab_d$depth.args)elab_d$depth.log$built[$depth]$true}$caseDirJoin-Path$evidence$nameNew-Item-ItemType Directory-Force-Path$caseDir|Out-Nullfifo_d$depthn-tclbatch ../scripts/run.tcln-testplusarg MODE$($case.Mode)n-testplusarg SCENARIO$($case.Scenario)n-log$name/simulator.logn-wdb$name/wave.wdb|Set-Content$name.argsInvoke-Hdlxsim.bat(-f,$name.args)$name/console.logCopy-Item-LiteralPathtrace.csv-Destination$name/trace.csvCopy-Item-LiteralPathwave.vcd-Destination$name/wave.vcd$logGet-Content-LiteralPath$name/console.log-Raw$markerif($case.Mode-eq0){RESULT PASS}else{RESULT EXPECTED_FAILURE_DETECTED}if(!$log.Contains($marker)-or$log.Contains(Fatal:)-or$log.Contains(Error:)){throwMissing or invalid result for$name}}ALL_CASES_VALIDATED$($cases.Count)|Tee-Object-FilePath suite_result.txt}finally{Pop-Location}
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →