本章介绍另一个开源PSS解析工具zuspec:
zuspec 提供了一组用于处理 actions relationship level 的工具 (ARL) 模型,主要是使用 Accellera 便携式测试和刺激 (PSS) 语言描述的模型。ARL 模型用于为数字设计指定系统级测试。zuspec 具有非常模块化的设计来支持快速探索这种建模方法的应用。
zuspec 组件都是用 C++ 实现的,可通过 C++ API 和 Python API 获得。这样它们就可以通过 Python 集成,但要全速交互是通过 C++ 来实现(感觉有点像gem5的框架设计)。
应用
应用程序是大多数用户体验 zuspec 的方式。应用连接一个或多个 zuspec 组件,以及一些集成代码,以满足特定需求。zuspec主要由parser,solver和generateTest三部分组成; paser负责PSS语法解析,solver负责对约束语法和调度语法做求解,generateTest负责生成指定类型的测试激励。
- zuspec -- 支持代码生成;
- zuspec-SV -- 对 SystemVerilog 测试平台环境的集成支持;
- zuspec-be-sw -- 对 SoC 测试平台环境的集成支持;
前端(Parser)
前端进程和输入描述(例如 PSS 语法),通常目标是填充 zuspec 的 ARL 数据模型,以便进一步处理和评估。
- zuspec-parser -- 基于 ANTLR 的解析器和 Accellera PSS 的 AST(抽象语法树);
- fe-parser -- AST 到 ARL 数据模型转换器;
核心数据模型和评估(Solver)
ARL 模型通常主要是声明性描述。换句话说,他们在很大程度上基于约束。评估工具将数据模型处理执行它并进行优化。
- arl-dm -- 捕获 ARL 建模语义的核心数据模型;
- arl-eval -- 核心评估器,支持对 ARL 模型进行解释性评估;
- vsc-dm -- 约束随机描述的外部数据模型;
- vsc-solvers -- 赋值器使用的约束求解器包;
后端(GenerateTest)
后端将 zuspec 评估集成到特定环境中或直接生成 ARL 模型的可执行表示。
- be-sv -- SystemVerilog 集成和代码生成器
- be-sw -- 用于 C 和 C++ 输出的代码生成器
--------------------------------------------------------------------------------------------------------------------------------
测试用例
1. 获取测试用例
git clone https://github.com/zuspec/zuspec-examples.git
2. 执行脚本(注意把python环境配置好)
cd zuspec-examples
./bootstrap.sh
3. 运行测试用例
$./packages/python/bin/ivpm activate
Note: Reading ivpm.yaml from project ./workspace/pss-tool/zuspec/zuspec-examples
Using dep-set default-dev-src for package zuspec-sv
Using dep-set default-dev for package dv-flow-mgr
Using dep-set default-dev for package dv-flow-libhdlsim
Using dep-set default-dev for package dv-flow-libpss
3.1 hello_world.pss测试用例代码
import std_pkg::*;
component pss_top {
action test_a {
rand int a, b, c;
constraint a == 100;
constraint (b + c) > a;
exec body {
message(LOW, "Hello World! a=%d b=%d c=%d \n", a, b, c);
}
};
action Hello {
activity {
sequence {
do test_a;
}
}
}
}
3.2 执行zupsec 生成测试激励
zuspec synth.sv.actor ./hello_world.pss -action pss_top::Hello
3.3 测试激励
`include "zsp_sv_macros.svh"
package pss_types;
import zsp_sv::*;
typedef class pss_import_api;
// TODO: define model-specific executor class
typedef executor_base executor_base_c;
typedef executor_base executor_t;
typedef class addr_region_base_s;
typedef class pss_top;
typedef class pss_top__aa;
typedef class pss_top__bb;
typedef class pss_top__Hello;
class addr_region_base_s extends object;
bit[63:0] size;
function new();
endfunction
virtual function void dtor();
endfunction
virtual function void init(executor_base exec_b);
endfunction
virtual function void __assign__(addr_region_base_s rhs);
size = rhs.size;
endfunction
static function addr_region_base_s create_default();
addr_region_base_s ret = new();
return ret;
endfunction
static function addr_region_base_s create_init(
longint unsigned size);
addr_region_base_s ret = new();
ret.size = size;
return ret;
endfunction
function void do_pre_solve();
pre_solve();
endfunction
function void do_post_solve(executor_base exec_b);
post_solve(exec_b);
endfunction
endclass
class pss_top extends component_c;
`zsp_typed_obj_util(pss_top)
function new(string name, component_ctor_ctxt ctxt, component_c parent=null);
super.new(name, ctxt, parent);
if (ctxt != null) begin
ctxt.enter(this);
end
executor_m = new[ctxt.executor_m.size()](ctxt.executor_m);
// Note: 'enter' handled by the component_c constructor
ctxt.leave(this);
endfunction
function void do_init(executor_base exec_b);
init_down(exec_b);
init_up(exec_b);
endfunction
virtual function bit check();
bit ret = 1;
return ret;
endfunction
endclass
typedef class pss_top;
class pss_top__aa extends action_c;
`zsp_typed_obj_util(pss_top__aa)
`zsp_action_comp_type(pss_top)
pss_top comp;
rand bit signed[31:0] a;
rand bit signed[31:0] b;
rand bit signed[31:0] c;
function new();
endfunction
constraint c_0x29d76240 {
this.a == 32'h64;
}
constraint c_0x29d76290 {
this.b + this.c > this.a;
}
function void do_pre_solve();
pre_solve();
endfunction
function void do_post_solve(executor_base exec_b);
post_solve(exec_b);
endfunction
task body(executor_base exec_b);
executor_t executor;
pss_import_api api;
$cast(executor, exec_b);
$cast(api, exec_b.get_api());
begin
`zsp_message(exec_b, LOW, ("Hello World! a=%0d b=%0d c=%0d \n", this.a, this.b, this.c));
end
endtask
virtual function void set_component(component_c comp);
$cast(this.comp, comp);
endfunction
virtual function component_c get_component();
return this.comp;
endfunction
endclass
typedef class pss_top;
class pss_top__bb extends action_c;
`zsp_typed_obj_util(pss_top__bb)
`zsp_action_comp_type(pss_top)
pss_top comp;
rand bit signed[31:0] a;
rand bit signed[31:0] b;
rand bit signed[31:0] c;
function new();
endfunction
constraint c_0x29c5f4c0 {
this.a == 32'h64;
}
constraint c_0x29d6af60 {
this.b + this.c > this.a;
}
function void do_pre_solve();
pre_solve();
endfunction
function void do_post_solve(executor_base exec_b);
post_solve(exec_b);
endfunction
task body(executor_base exec_b);
executor_t executor;
pss_import_api api;
$cast(executor, exec_b);
$cast(api, exec_b.get_api());
begin
`zsp_message(exec_b, LOW, ("Hello World! a=%0d b=%0d c=%0d \n", this.a, this.b, this.c));
end
endtask
virtual function void set_component(component_c comp);
$cast(this.comp, comp);
endfunction
virtual function component_c get_component();
return this.comp;
endfunction
endclass
typedef class pss_top;
class pss_top__Hello extends action_c;
`zsp_typed_obj_util(pss_top__Hello)
`zsp_action_comp_type(pss_top)
pss_top comp;
function new();
endfunction
function void do_pre_solve();
pre_solve();
endfunction
function void do_post_solve(executor_base exec_b);
post_solve(exec_b);
endfunction
virtual function void set_component(component_c comp);
$cast(this.comp, comp);
endfunction
virtual function component_c get_component();
return this.comp;
endfunction
endclass
class pss_import_api #(type BaseT=zsp_sv::empty_t) extends backend_api #(BaseT);
endclass
endpackage
`include "zsp_sv_macros.svh"
package pss_top__Entry_prv;
import zsp_sv::*;
import pss_types::*;
typedef class pss_top__Entry_actor;
typedef pss_top__Entry_actor actor_t;
typedef class activity_0x29d457f0;
typedef class activity_0x29cfa310;
class activity_0x29d457f0 extends activity_c;
function new(actor_c actor, component_c parent_comp);
super.new(actor, parent_comp);
endfunction
virtual task run();
// Traverse action pss_top::Hello
begin
activity_traverse_compound_c #(pss_top__Hello, activity_0x29cfa310) activity = new(actor, parent_comp);
activity.run();
activity.dtor();
end
endtask
endclass
class activity_0x29cfa310 extends activity_c;
pss_top__Hello self;
function new(actor_c actor, component_c parent_comp, pss_top__Hello self);
super.new(actor, parent_comp);
this.self = self;
endfunction
virtual task run();
endtask
endclass
class pss_top__Entry_actor extends actor_c;
pss_top comp_tree;
pss_import_api api;
executor_base_c default_executor;
function new(pss_import_api api=null);
component_ctor_ctxt ctxt;
super.new("<actor>", null, null);
ctxt = new(this, 0);
this.api = api;
this.default_executor = new("default_executor", this);
comp_tree = new("pss_top", ctxt, this);
endfunction
virtual task run();
activity_0x29d457f0 root_activity = new(this, comp_tree);
comp_tree.init(this.default_executor);
comp_tree.do_init(this.default_executor);
if (comp_tree.check()) begin
if (api == null) begin
api = new();
end
comp_tree.start(this.default_executor);
foreach(listeners[i]) begin
listeners[i].enter_actor(this);
end
root_activity.run();
foreach(listeners[i]) begin
listeners[i].leave_actor(this);
end
end else begin
$display("Error: initialization check failed");
end
endtask
virtual function pss_import_api get_api();
return api;
endfunction
virtual function executor_base get_default_executor();
return default_executor;
endfunction
virtual function backend_api get_backend();
return api;
endfunction
endclass
endpackage
package pss_top__Entry_pkg;
import zsp_sv::*;
import pss_top__Entry_prv::*;
typedef pss_top__Entry_prv::pss_top__Entry_actor pss_top__Entry;
endpackage