You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SystemC中SC_THREAD内调用wait()触发E519错误的问题求助

问题描述

使用SystemC实现卷积神经网络仿真,Conv2d模块通过SC_THREAD注册前向传播函数forward_pass,函数内使用wait()等待输入就绪信号。调用sc_start()启动仿真时触发以下错误:

Error: (E519) wait() is only allowed in SC_THREADs and SC_CTHREADs:
in SC_METHODs use next_trigger() instead
In file: ../../../src/sysc/kernel/sc_wait.cpp:94
make: *** [all] Error 1

尽管已明确将forward_pass注册为SC_THREAD,但错误仍然发生。模块定义与测试代码如下:

Conv2d模块定义(Conv2d.h)

// Conv2d.h
#ifndef CONV2D_H
#define CONV2D_H

#include <systemc.h>

SC_MODULE(Conv2d) {
private:
    unsigned int in_channels, out_channels;
    unsigned int kernel_height, kernel_width;
    unsigned int stride_height, stride_width;
    unsigned int padding_height, padding_width;
    bool apply_relu;

    unsigned int input_feature_map_height, input_feature_map_width;
    unsigned int output_feature_map_height, output_feature_map_width;

    std::vector<std::vector<std::vector<std::vector<float>>>> weights;
    std::vector<float> bias;

public:
    sc_vector<sc_fifo_in<float>> input_feature_map;
    sc_vector<sc_fifo_out<float>> output_feature_map;
    sc_in<bool> input_ready;
    sc_out<bool> output_ready;

    SC_HAS_PROCESS(Conv2d);
    Conv2d(sc_module_name name)
        : in_channels(1), out_channels(1),
          kernel_height(3), kernel_width(3),
          stride_height(1), stride_width(1),
          padding_height(1), padding_width(1),
          apply_relu(false),
          input_feature_map_height(3), input_feature_map_width(3),
          output_feature_map_height(3), output_feature_map_width(3),
          input_ready("input_ready"), output_ready("output_ready") {
        initialize_parameters();

        SC_THREAD(forward_pass);
        sensitive << input_ready.pos();
        dont_initialize();
    }

    void configure(unsigned int in_c, unsigned int out_c,
                   std::pair<unsigned int, unsigned int> kernel_size,
                   std::pair<unsigned int, unsigned int> stride,
                   std::pair<unsigned int, unsigned int> padding,
                   bool relu,
                   unsigned int in_feature_map_size, unsigned int out_feature_map_size,
                   std::pair<unsigned int, unsigned int> in_feature_map_dimension, std::pair<unsigned int, unsigned int> out_feature_map_dimension) {
        in_channels = in_c;
        out_channels = out_c;
        kernel_height = kernel_size.first;
        kernel_width = kernel_size.second;
        stride_height = stride.first;
        stride_width = stride.second;
        padding_height = padding.first;
        padding_width = padding.second;
        apply_relu = relu;

        input_feature_map_height = in_feature_map_dimension.first;
        input_feature_map_width = in_feature_map_dimension.second;
        input_feature_map.init(in_feature_map_size);
        output_feature_map_height = out_feature_map_dimension.first;
        output_feature_map_width = out_feature_map_dimension.second;
        output_feature_map.init(out_feature_map_size);

        initialize_parameters();
    }

    void forward_pass() {
        while(true) {
            wait();
            for (unsigned int out_c = 0; out_c < out_channels; ++out_c) {
                for (unsigned int h = 0; h < output_feature_map_height; ++h) {
                    for (unsigned int w = 0; w < output_feature_map_width; ++w) {
                        float sum = 0.0;
                        for (unsigned int in_c = 0; in_c < in_channels; ++in_c) {
                            for (unsigned int kh = 0; kh < kernel_height; ++kh) {
                                for (unsigned int kw = 0; kw < kernel_width; ++kw) {
                                    int h_index = h * stride_height + kh - padding_height;
                                    int w_index = w * stride_width + kw - padding_width;

                                    if (h_index >= 0 && h_index < input_feature_map_height && w_index >= 0 && w_index < input_feature_map_width) {
                                        int input_index = in_c * input_feature_map_height * input_feature_map_width + h_index * input_feature_map_width + w_index;
                                        sum += input_feature_map[input_index].read() * weights[out_c][in_c][kh][kw];
                                    }
                                }
                            }
                        }
                        sum += bias[out_c];
                        if (apply_relu && sum < 0) {
                            sum = 0.0;
                        }
                        int output_index = out_c * output_feature_map_height * output_feature_map_width + h * output_feature_map_width + w;
                        output_feature_map[output_index].write(sum);
                    }
                }
            }

            output_ready.write(true);
            wait(1, SC_NS);
            output_ready.write(false);
        }
    }
};

#endif // CONV2D_H

测试代码(main.cpp)

// main.cpp
#include <systemc.h>

#include <vector>
#include <tuple>
#include <iostream>
#include <iomanip>
#include <fstream>

#include <Conv2d.h>
#include <helpers.h>


int sc_main(int argc, char* argv[]) {
    Conv2d conv_layer("ConvolutionalLayer");
    conv_layer.configure(
        3, 64,
        std::make_pair(11, 11),
        std::make_pair(4, 4),
        std::make_pair(2, 2),
        true,
        150528,
        193600,
        std::make_pair(224, 224),
        std::make_pair(55, 55)
        );

    auto conv_layer_shape = conv_layer.weight_shape();
    int out_channels = std::get<0>(conv_layer_shape);
    int in_channels = std::get<1>(conv_layer_shape);
    int rows = std::get<2>(conv_layer_shape);
    int cols = std::get<3>(conv_layer_shape);

    auto weights = reshape_weights(load_weights("./data/conv1_weight.txt"), out_channels, in_channels, rows, cols);
    auto biases = load_weights("./data/conv1_bias.txt");
    conv_layer.load_parameters(weights, biases);

    auto image_data = load_image("./data/cat.txt");

    sc_vector<sc_fifo<float>> input_feature_map_sig("input_feature_map_sig", 150528);
    for (size_t i = 0; i < input_feature_map_sig.size(); i++) {
        conv_layer.input_feature_map[i](input_feature_map_sig[i]);
    }
    sc_vector<sc_fifo<float>> output_feature_map_sig("output_feature_map_sig", 193600);
    for (size_t i = 0; i < output_feature_map_sig.size(); i++) {
        conv_layer.output_feature_map[i](output_feature_map_sig[i]);
    }
    sc_signal<bool> input_ready_sig;
    conv_layer.input_ready(input_ready_sig);
    sc_signal<bool> output_ready_sig;
    conv_layer.output_ready(output_ready_sig);

    for (size_t i = 0; i < input_feature_map_sig.size(); i++) {
        input_feature_map_sig[i].write(image_data[i]);
    }
    input_ready_sig.write(true);

    sc_start();

    return 0;
}
原因分析

错误的核心原因是**wait()调用发生在非SystemC进程上下文**,而非forward_pass线程内:

  1. 代码中initialize_parameters()函数在Conv2d构造函数和configure()函数中被调用,这两个函数均执行于sc_main()上下文(不属于任何SC_THREAD/SC_CTHREAD)。如果initialize_parameters()中存在wait()调用(或间接调用了会触发wait()的SystemC操作,如sc_fifo::read()),就会触发E519错误。
  2. 当前测试代码中,input_ready_sig.write(true)在sc_start()之前执行,导致信号初始值为true,线程的wait()无法检测到posedge事件,但这不会直接触发错误,只是会导致线程一直挂起。
解决方案

1. 修复initialize_parameters()函数

检查并修改initialize_parameters(),移除所有SystemC同步操作:

  • 权重/偏置初始化仅使用纯C++逻辑(如随机数生成、文件读取),不要调用wait()、sc_fifo的阻塞读写等操作。
  • 示例实现(仅供参考):
void initialize_parameters() {
    // 初始化权重:(out_channels, in_channels, kernel_height, kernel_width)
    weights.resize(out_channels, std::vector<std::vector<std::vector<float>>>(
        in_channels, std::vector<std::vector<float>>(
            kernel_height, std::vector<float>(kernel_width, 0.01f)
        )
    ));
    // 初始化偏置
    bias.resize(out_channels, 0.0f);
}

2. 调整测试逻辑,确保信号触发在仿真上下文内

将input_ready_sig的触发逻辑移到SystemC进程中,确保posedge事件在仿真开始后产生:

  • 封装测试逻辑到Testbench模块(SystemC最佳实践):
SC_MODULE(Testbench) {
    sc_signal<bool> input_ready_sig;
    sc_signal<bool> output_ready_sig;
    sc_vector<sc_fifo<float>> input_fifos;
    sc_vector<sc_fifo<float>> output_fifos;
    Conv2d conv_layer;

    SC_CTOR(Testbench) 
        : conv_layer("conv_layer"),
          input_fifos("input_fifos", 150528),
          output_fifos("output_fifos", 193600) {
        // 连接端口
        conv_layer.input_ready(input_ready_sig);
        conv_layer.output_ready(output_ready_sig);
        for (size_t i = 0; i < input_fifos.size(); ++i) {
            conv_layer.input_feature_map[i](input_fifos[i]);
        }
        for (size_t i = 0; i < output_fifos.size(); ++i) {
            conv_layer.output_feature_map[i](output_fifos[i]);
        }
        // 注册测试线程
        SC_THREAD(run_test);
    }

    void run_test() {
        // 加载图像数据
        auto image_data = load_image("./data/cat.txt");
        // 写入输入FIFO
        for (size_t i = 0; i < input_fifos.size(); ++i) {
            input_fifos[i].write(image_data[i]);
        }
        // 等待数据写入完成,触发输入就绪信号
        wait(1, SC_NS);
        input_ready_sig.write(true);
        // 等待输出就绪
        wait(output_ready_sig.pos());
        // 读取输出数据(示例)
        // for (size_t i = 0; i < output_fifos.size(); ++i) {
        //     float val = output_fifos[i].read();
        //     std::cout << "Output " << i << ": " << val << std::endl;
        // }
        // 停止仿真
        sc_stop();
    }
};

int sc_main(int argc, char* argv[]) {
    Testbench tb("testbench");
    // 配置卷积层
    tb.conv_layer.configure(
        3, 64,
        std::make_pair(11, 11),
        std::make_pair(4, 4),
        std::make_pair(2, 2),
        true,
        150528,
        193600,
        std::make_pair(224, 224),
        std::make_pair(55, 55)
    );
    // 加载权重和偏置
    auto conv_layer_shape = tb.conv_layer.weight_shape();
    int out_channels = std::get<0>(conv_layer_shape);
    int in_channels = std::get<1>(conv_layer_shape);
    int rows = std::get<2>(conv_layer_shape);
    int cols = std::get<3>(conv_layer_shape);
    auto weights = reshape_weights(load_weights("./data/conv1_weight.txt"), out_channels, in_channels, rows, cols);
    auto biases = load_weights("./data/conv1_bias.txt");
    tb.conv_layer.load_parameters(weights, biases);

    // 启动仿真,指定超时时间避免无限挂起
    sc_start(1000, SC_NS);
    return 0;
}

3. 其他优化建议

  • 调用sc_start()时指定仿真超时时间(如sc_start(1000, SC_NS)),避免因线程挂起导致仿真无限运行。
  • 确保所有端口连接操作在仿真启动前完成,避免运行时连接错误。

内容的提问来源于stack exchange,提问作者weinfailed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 17:50:56