SystemC:Dynamic Processes(动态进程)

SystemC 的动态进程机制,核心是在仿真运行时(而非 elaboration 阶段)动态创建、调度和管理进程,突破静态进程(SC_THREAD/SC_METHOD)的 "预注册" 限制,大幅提升建模灵活性,尤其适用于测试台动态配置、事务跟踪、动态流量生成等场景。

一、动态进程的核心概念

  1. 定义 :仿真执行期间(sc_start () 之后)通过sc_spawn创建的进程,可按需创建 / 终止,支持带参数、返回值的进程调用,弥补静态进程 "elaboration 阶段固定注册" 的局限性。

  2. 核心优势

    • 适配动态场景:如测试台根据配置启动不同数量的流量生成器、跟踪拆分事务的完成状态。
    • 资源优化:无需预分配最大数量的静态进程,仅在需要时创建,节省仿真资源。
  3. 与静态进程的关键区别

    特性 静态进程(SC_THREAD/SC_METHOD) 动态进程(sc_spawn 创建)
    创建时机 elaboration 阶段(模块构造时) 仿真运行时(sc_start () 之后)
    参数传递 不支持直接传递 支持最多 8 个参数(值 / 引用传递)
    返回值 不支持 支持通过引用接收返回值
    灵活性 固定数量和行为 按需创建 / 终止,动态配置

二、动态进程的启用与基础语法

(一)启用动态进程

必须在包含 SystemC 头文件前定义宏SC_INCLUDE_DYNAMIC_PROCESSES,启用动态进程功能:

cpp

运行

复制代码
#define SC_INCLUDE_DYNAMIC_PROCESSES // 必须在#include <systemc>之前
#include <systemc>

(二)动态进程的函数声明

被 spawn 的函数可是普通函数模块成员函数,支持参数和返回值(静态进程不支持):

cpp

运行

复制代码
// 普通函数示例(无参数、无返回值)
void inject(void);

// 普通函数示例(带参数、带返回值)
int count_changes(sc_signal<int>& sig);

// 模块成员函数示例
class TestChan : public sc_module {
public:
    bool Track(sc_signal<packet>& pkt); // 带引用参数、返回bool
};

(三)动态进程注册:sc_spawn

通过sc_spawn函数注册动态进程,返回sc_process_handle对象,用于后续进程控制(如等待终止、暂停 / 恢复)。

1. 核心语法
  • 注册普通函数(无返回值): cpp

    运行

    复制代码
    sc_process_handle h = sc_spawn(
        sc_bind(&funcName, ARGS...), // 绑定函数与参数(sc_bind用于参数传递)
        "process_name", // 进程名(可选,建议唯一)
        spawnOptions    // 进程选项(可选,如设置为SC_METHOD)
    );
  • 注册成员函数(带返回值): cpp

    运行

    复制代码
    int ret_val; // 存储返回值的变量
    sc_process_handle h = sc_spawn(
        sc_bind(&ClassName::methName, this, ARGS...), // this指向当前模块实例
        "process_name",
        spawnOptions,
        &ret_val // 接收返回值的引用
    );
2. 参数传递规则
  • 默认按值传递:参数会被拷贝到进程栈中。

  • 按引用 / 常量引用传递:需使用sc_ref(var)sc_cref(var)包装,避免拷贝大对象或修改外部变量:

    cpp

    运行

    复制代码
    sc_signal<int> sig;
    sc_spawn(sc_bind(&count_changes, sc_ref(sig))); // 引用传递sig

(四)进程选项:sc_spawn_option

通过sc_spawn_option配置动态进程的特性,核心用法:

cpp

运行

复制代码
sc_spawn_option opt;
opt.spawn_method(); // 设置为SC_METHOD类型(默认是SC_THREAD)
opt.dont_initialize(); // 跳过初始化执行
opt.set_sensitivity(&evt); // 设置静态灵敏度(绑定事件)
opt.set_stack_size(1024); // 设置进程栈大小(仅专家级使用)

三、动态进程的关键操作

(一)进程句柄:sc_process_handle

sc_spawn返回的sc_process_handle是动态进程的 "控制接口",核心功能:

  • 等待进程终止:wait(h.terminated_event())(仅适用于 SC_THREAD,SC_METHOD 无终止逻辑)。
  • 获取进程名:h.name()
  • 进程控制:暂停、恢复、终止等(见下文 "进程控制方法")。
示例:简单动态进程创建与等待

cpp

运行

复制代码
void spawned_thread() {
    cout << "动态进程启动:" << sc_get_current_process_handle().name() << endl;
    wait(10, SC_NS);
    cout << "动态进程退出" << endl;
}

void main_thread() {
    // 创建动态进程,获取句柄
    sc_process_handle h = sc_spawn(sc_bind(&spawned_thread), "dyn_thread");
    wait(h.terminated_event()); // 等待动态进程终止
    cout << "主进程:动态进程已完成" << endl;
}

(二)SC_FORK/SC_JOIN:并行启动多个动态进程

用于批量启动多个动态进程,并等待所有进程完成(类似 Verilog 的 fork/join),核心语法:

cpp

运行

复制代码
SC_FORK
    sc_spawn(sc_bind(&func1, args1), "p1"),
    sc_spawn(sc_bind(&func2, args2), "p2"),
    sc_spawn(sc_bind(&func3, args3), "p3")
SC_JOIN
示例:多接口并行测试

cpp

运行

复制代码
SC_MODULE(ForkTest) {
    sc_fifo<double> fifo1, fifo2;
    SC_CTOR(ForkTest) { SC_THREAD(main_thread); }

    void main_thread() {
        // 并行启动两个动态进程,分别处理两个FIFO
        SC_FORK
            sc_spawn(sc_bind(&ForkTest::process_fifo, this, sc_ref(fifo1)), "fifo1_proc"),
            sc_spawn(sc_bind(&ForkTest::process_fifo, this, sc_ref(fifo2)), "fifo2_proc")
        SC_JOIN
        cout << "所有FIFO处理完成" << endl;
    }

    void process_fifo(sc_fifo<double>& fifo) {
        double data;
        while (fifo.nb_read(data)) {
            cout << "处理数据:" << data << endl;
            wait(5, SC_NS);
        }
    }
};

(三)进程控制方法(提议中的标准特性)

SystemC 2.3+ 提议在sc_process_handle中添加进程控制方法,支持暂停、恢复、终止等操作,核心接口:

cpp

运行

复制代码
// 枚举:控制是否影响子进程
enum sc_descendant_inclusion_info {
    SC_NO_DESCENDANTS,    // 仅影响当前进程
    SC_INCLUDE_DESCENDANTS // 影响当前进程及子进程
};

// 核心控制方法
h.suspend(SC_NO_DESCENDANTS);  // 暂停进程
h.resume(SC_NO_DESCENDANTS);   // 恢复进程
h.disable(SC_NO_DESCENDANTS);  // 禁用进程(忽略灵敏度)
h.enable(SC_NO_DESCENDANTS);   // 启用进程
h.kill(SC_NO_DESCENDANTS);     // 终止进程
h.reset(SC_NO_DESCENDANTS);    // 异步重启进程
h.throw_it(exc, SC_NO_DESCENDANTS); // 向进程抛出异常(模拟中断)
关键说明:
  • 这些方法目前是标准提议,需确认所用 SystemC 版本是否支持。
  • suspend/resume:暂停时仍收集事件,恢复后立即响应;disable/enable:禁用时忽略所有事件。

四、核心要点与实践建议

  1. 启用动态进程的宏必须前置SC_INCLUDE_DYNAMIC_PROCESSES需在#include <systemc>之前定义,否则编译报错。
  2. 参数传递注意事项
    • 引用传递必须用sc_ref/sc_cref包装,否则编译失败。
    • 返回值的存储变量需保证在进程生命周期内有效(避免栈变量被释放)。
  3. 进程名唯一性:动态进程名会自动拼接父模块层级名,建议显式指定唯一名称,便于调试。
  4. SC_METHOD 类型的动态进程 :需通过sc_spawn_option::spawn_method()设置,且不可调用wait()(与静态 SC_METHOD 规则一致)。
  5. 资源管理 :动态进程创建后需通过sc_process_handle跟踪,避免 "孤儿进程" 导致仿真资源泄漏。
  6. 适用场景优先 :动态进程适合测试台、事务跟踪等灵活场景;核心功能建模(如固定硬件逻辑)仍建议用静态进程(仿真效率更高)

五、练习指引

  • 核心示例:simple_spawn(基础动态进程创建)、Fork(SC_FORK/SC_JOIN 并行测试)、process_control(进程控制方法演示)。
  • 练习重点:尝试动态创建带参数的进程、用sc_process_handle等待进程终止、通过 SC_FORK/SC_JOIN 实现多接口并行仿真。
相关推荐
数字IC那些事儿23 天前
SystemC:时间建模
system c