使用不同模型相同提示词写一段systemverilog代码,deepseek太让人惊喜!
方法关键语法优点注意事项方法一join_any简洁可能误杀其他线程方法二外层隔离推荐,安全隔离多一层嵌套方法三命名块 +精确控制需要命名管理实际项目中推荐方法二,既安全又清晰,是 UVM/验证环境中最常用的模式。DeepSeek v4 pro-成功,花费0.0496在芯片验证中,经常需要并行启动多个任务,并当其中任一任务完成时立即终止其余任务。SystemVerilog 中常见的实现方式有以及基于
熟悉systemverilog的朋友应该都知道fork join_any disable有一个小陷阱,就是可能会误kill其他进程,所以需要一个guard fork。
突然奇想,看看哪个大模型可以不经过提醒(这个很重要,因为我们大概率不会把这个加入到提示词!)考虑到这个层面。
先说结论:deepseek v4 pro和claude opus 4.7胜出!
可以自行在chip.ai6800.com下调用模型做实验
GPT-5.4 -失败,花费0.0075
可以用 fork...join_any 配合 disable fork(或 disable )来实现。
推荐写法
task automatic run_taskA_taskB();
fork : ab_fork
begin : taskA_proc
taskA();
end
begin : taskB_proc
taskB();
end
join_any
// taskA 和 taskB 任意一个先结束后,杀掉另外一个
disable ab_fork;
endtask
更简洁写法
如果当前作用域明确,也可以这样写:
fork
taskA();
taskB();
join_any
disable fork;
不过在实际验证环境里,更推荐加名字,便于维护和调试:(其实还是有风险的!!!)
fork : ab_fork
taskA();
taskB();
join_any
disable ab_fork;
GPT 5.5 -失败,花费0.0205
task automatic taskA();
$display("[%0t] taskA start", $time);
// taskA执行内容
#100;
$display("[%0t] taskA done", $time);
endtask
task automatic taskB();
$display("[%0t] taskB start", $time);
// taskB执行内容
#200;
$display("[%0t] taskB done", $time);
endtask
task automatic run_taskA_taskB();
fork : TASK_FORK
begin
taskA();
end
begin
taskB();
end
join_any
// taskA/taskB中任意一个完成后,终止另一个还在运行的task
disable TASK_FORK;
$display("[%0t] one task finished, remaining task disabled", $time);
endtask
说明:
fork ... join_any:并行启动taskA和taskB,任意一个结束后继续往下执行。disable TASK_FORK:关闭该fork块中仍在运行的其他线程。- 如果
taskA先完成,则taskB会被终止。 - 如果
taskB先完成,则taskA会被终止。
Claude sonnet-4.6-失败,花费0.0646
这是一个使用SystemVerilog实现两个任务并行执行,任一完成后终止另一个的代码示例:
module parallel_task_example;
// 任务A
task automatic taskA();
begin
$display("[%0t] taskA started", $time);
#100ns; // 模拟任务A需要100ns完成
$display("[%0t] taskA completed", $time);
end
endtask
// 任务B
task automatic taskB();
begin
$display("[%0t] taskB started", $time);
#150ns; // 模拟任务B需要150ns完成
$display("[%0t] taskB completed", $time);
end
endtask
// 主控制逻辑
initial begin
fork
begin
taskA();
end
begin
taskB();
end
join_any // 任何一个分支完成就继续执行
// 终止所有未完成的并行进程
disable fork;
$display("[%0t] One task completed, both tasks disabled", $time);
#10ns;
$finish;
end
endmodule
关键点说明:
- fork...join_any - 启动并行执行,任一分支完成后继续
- disable fork - 终止当前fork块中所有未完成的进程
- automatic - 确保任务可重入,支持并发调用
如果需要更精细的控制(比如只disable特定任务),可以使用命名的fork块:
initial begin
fork : parallel_block
begin
taskA();
end
begin
taskB();
end
join_any
disable parallel_block; // 通过名称disable特定fork块
$display("[%0t] Tasks disabled", $time);
end
这段代码中,taskA会在100ns完成,此时taskB还在执行中(需要150ns),join_any会立即继续执行,然后disable fork会终止还在运行的taskB。
Claude opus 4.7-成功,花费0.0283
方法一:使用 fork...join_any + disable fork
module tb_top;
// 定义 taskA
task taskA();
$display("[%0t] taskA started", $time);
#100; // 模拟一些耗时操作
$display("[%0t] taskA completed", $time);
endtask
// 定义 taskB
task taskB();
$display("[%0t] taskB started", $time);
#50; // 模拟一些耗时操作(比taskA快)
$display("[%0t] taskB completed", $time);
endtask
initial begin
fork
taskA();
taskB();
join_any
// 任一 task 完成后,disable 掉 fork 内所有剩余线程
disable fork;
$display("[%0t] Both taskA and taskB have been disabled/finished", $time);
end
endmodule
注意:
disable fork会终止当前进程派生的所有子线程。如果调用环境中还有其他fork产生的线程,可能会被误杀。为了避免这个问题,推荐使用下面的方法二。
方法二:使用 fork...join_any + disable fork(加隔离层)
通过额外包裹一层 fork...join,将 disable fork的作用范围限定在内部,避免影响外部线程:
module tb_top;
task taskA();
$display("[%0t] taskA started", $time);
#100;
$display("[%0t] taskA completed", $time);
endtask
task taskB();
$display("[%0t] taskB started", $time);
#50;
$display("[%0t] taskB completed", $time);
endtask
initial begin
// 外层 fork...join 用于隔离 disable fork 的作用范围
fork begin
fork
taskA();
taskB();
join_any
disable fork; // 只会 disable 内层 fork 派生的线程
$display("[%0t] Both taskA and taskB have been disabled/finished", $time);
end join
$display("[%0t] Continue with other work...", $time);
end
endmodule
方法三:使用命名 Block + disable
使用命名块可以精确控制要 disable 的目标:
module tb_top;
task taskA();
$display("[%0t] taskA started", $time);
#100;
$display("[%0t] taskA completed", $time);
endtask
task taskB();
$display("[%0t] taskB started", $time);
#50;
$display("[%0t] taskB completed", $time);
endtask
initial begin
fork : parallel_block
begin : blk_a
taskA();
end
begin : blk_b
taskB();
end
join_any
// 精确 disable 命名的 fork block
disable parallel_block;
$display("[%0t] Both taskA and taskB have been disabled/finished", $time);
end
endmodule
仿真输出(以方法二为例)
[0] taskA started
[0] taskB started
[50] taskB completed
[50] Both taskA and taskB have been disabled/finished
[50] Continue with other work...
要点总结
| 方法 | 关键语法 | 优点 | 注意事项 |
|---|---|---|---|
| 方法一 | join_any + disable fork |
简洁 | 可能误杀其他线程 |
| 方法二 | 外层 fork begin...end join隔离 |
推荐,安全隔离 | 多一层嵌套 |
| 方法三 | 命名块 + disable block_name |
精确控制 | 需要命名管理 |
实际项目中推荐方法二,既安全又清晰,是 UVM/验证环境中最常用的模式。
DeepSeek v4 pro-成功,花费0.0496
在芯片验证中,经常需要并行启动多个任务,并当其中任一任务完成时立即终止其余任务。SystemVerilog 中常见的实现方式有 fork...join_any + disable fork 以及基于 process 类的精细控制。下面给出两种典型写法,并说明各自的适用场景。
方法一:fork...join_any + disable fork(简洁、常用)
module tb;
initial begin
// 在独立的 begin...end 块内使用 fork,可限制 disable fork 的影响范围
begin : isolated_fork_block
fork
taskA();
taskB();
join_any
disable fork; // 终止本块内所有活动的子进程(即 taskA / taskB)
end
$display("One of the tasks finished, the other is disabled.");
// 继续后续测试逻辑...
end
// 示例 taskA(实际工作中可替换为真实的验证任务)
task taskA();
$display("taskA started");
#10ns; // 模拟耗时操作
$display("taskA finished");
endtask
// 示例 taskB
task taskB();
$display("taskB started");
#5ns; // 模拟耗时更短的任务
$display("taskB finished");
endtask
endmodule
说明:
fork...join_any等待taskA与taskB中任一完成即解除阻塞。disable fork会杀死当前线程(即initial块)中所有尚未完成的子进程。为避免误杀同一initial块中的其他并行进程,通常把fork封装在一个独立的begin...end块中,并立即使用disable fork。- 优点:代码简洁,适合大多数验证场景。
- 注意:如果
taskA/taskB内部又开启了子fork,disable fork也会终止那些子孙进程(有时这正是期望的行为,有时则需要避免)。
方法二:使用 process 类精确控制(推荐用于复杂环境)
当需要精确地只终止 taskA 和 taskB,而不影响其他可能存在的并行进程时,可以保存进程句柄并单独 kill。
module tb;
initial begin
process pA, pB;
fork
begin
pA = process::self(); // 获取当前进程句柄
taskA();
end
begin
pB = process::self();
taskB();
end
join_any
// 哪个没完成就 kill 哪个
if (pA != null && pA.status != process::FINISHED)
pA.kill();
if (pB != null && pB.status != process::FINISHED)
pB.kill();
$display("One task completed, the other was killed precisely.");
end
task taskA();
$display("taskA started");
#10ns;
$display("taskA finished");
endtask
task taskB();
$display("taskB started");
#5ns;
$display("taskB finished");
endtask
endmodule
说明:
process::self()返回当前进程的句柄。status属性可以检查进程是否已经结束(FINISHED、KILLED等)。kill()方法可以精确终止特定进程,不影响其他并行进程。- 优点:控制粒度细,不会误杀其他进程,适合复杂验证环境。
- 要求:需要仿真器支持 IEEE 1800-2012 及以上标准。
总结
对于大多数芯片验证场景,方法一足够使用且书写快捷;当验证环境中有多个并行的 fork 或需要精细控制时,推荐采用方法二以避免副作用。
更多推荐



所有评论(0)