惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
Stack Overflow Blog
Stack Overflow Blog
人人都是产品经理
人人都是产品经理
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
D
DataBreaches.Net
GbyAI
GbyAI
Microsoft Security Blog
Microsoft Security Blog
博客园_首页
大猫的无限游戏
大猫的无限游戏
Jina AI
Jina AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
IT之家
IT之家
MongoDB | Blog
MongoDB | Blog
The GitHub Blog
The GitHub Blog
月光博客
月光博客
U
Unit 42
Hugging Face - Blog
Hugging Face - Blog
博客园 - 叶小钗
腾讯CDC
B
Blog RSS Feed
博客园 - Franky
爱范儿
爱范儿

Пусть этот камень будет более крепким, чем человек

【MLIR】Transform Dialect【0】保持计算结构 【MLIR】跟着Toy语言学习MLIR【6】支持复合结构类型 【MLIR】跟着Toy语言学习MLIR【5】降级到LLVM及CodeGen 【MLIR】跟着Toy语言学习MLIR【4】部分降级到低层方言 【MLIR】跟着Toy语言学习MLIR【3】通过接口实现通用转换 【MLIR】跟着Toy语言学习MLIR【2】pattern匹配和重写 【MLIR】跟着Toy语言学习MLIR【1】Toy语言和 Toy Dialect 【琐记】你的爱好能坚持多少年 【琐记】烟火与尘埃 【Triton】Triton实现矩阵乘 【LLM推理加速】FlashAttention 【LLM推理加速】PagedAttention 【LLM推理加速】Online Softmax LLM基础知识【1】 Transformer模型 【AI编译】LayerGroup Tiling Tile的疑惑和思考 【AI编译】深度优先的Tile调度,万事大吉? 【AI编译】多级流水线Tile调度策略 【CUDA C++】GPU内存使用【3】 【AI编译】Cache缓存地址映射 【CUDA C++】GPU存储【2】 【CUDA C++】GPU基本介绍【1】 【00】0序章-不受欢迎的来客 【转载】我来了——持续低熵 【Halide】调度优化【2】 【感想】写作进度报告5 【Halide】调度优化【1】 【转载】北大中文男足战报2 【BYOC】TVM切分子图 【转载】北大中文男足战报1
SystemC 用寄存器同步建模方法
Post author: XianMu@Пусть этот камень будет более крепким, чем ч · 2025-08-23 · via Пусть этот камень будет более крепким, чем человек

本文为 SystemC 实现寄存器来同步的建模方法。

# 应用场景

仿真时可能有类似这样的需求:
将一系列的指令发送到三个模块 A、B、C,三个模块相互独立地执行这些指令。
为了进行同步控制,这些指令中含有 sync 类型的指令,并借助寄存器来实现模块之间的同步。
比如我创建 20 个寄存器,A 模块的 Sync 指令是往寄存器 0 号位写入 1,B 收到的 sync 指令是读寄存器 0 号位,读到 1 才能执行后续指令;然后 B 往寄存器 1 号位写入 10,C 在寄存器 1 号位读到 10,才能够执行后续指令。以此实现执行同步。

# 初步尝试

依据上述需求,我非常直接地创建了 sc_signal<int> reg[20] 来作为寄存器。

每个模块通过以下方式对 sync 指令进行读和写

mSyncRegisters->reg[reg_id].write(num); 
while (mSyncRegisters->reg[reg_id].read() != num) {
    wait(mSyncRegisters->reg[reg_id].value_changed_event());  
}

但是发现了如下错误:

Error: (E115) sc_signal<T> cannot have more than one driver

原来 sc_signal 这个变量不能被多个 module 驱动。此时,问题就变得棘手起来。

# 解决方案

报错寻找问题,以及询问 deepseek,花费大半天时间。

终究还是没能继续使用 sc_signal 。deepseek 帮我用 sc_event 手写了整个逻辑。

这里是解决方案:

#include <systemc.h>
#include <vector> 
class reg_file_if : public virtual sc_core::sc_interface {
public:
    virtual void write(int reg_index, int value) = 0;
    virtual int read(int reg_index) = 0;
    virtual void wait_until(int reg_index, int value) = 0;
};
class SyncRegFile : public sc_core::sc_module, public reg_file_if {
public:
    SC_HAS_PROCESS(SyncRegFile);
    SyncRegFile(sc_core::sc_module_name name, size_t num_regs) 
        : sc_core::sc_module(name), 
          reg_array(num_regs, 0),
          reg_events(num_regs){}
    virtual void write(int reg_index, int value) override {
        if (reg_index < 0 || static_cast<size_t>(reg_index) >= reg_array.size()) 
            return;
        
        mutex.lock();
        reg_array[reg_index] = value;
        mutex.unlock();
        reg_events[reg_index].notify(sc_core::SC_ZERO_TIME);
    }
    virtual int read(int reg_index) override {
        if (reg_index < 0 || static_cast<size_t>(reg_index) >= reg_array.size()) 
            return 0;
        
        mutex.lock();
        int value = reg_array[reg_index];
        mutex.unlock();
        return value;
    }
    virtual void wait_until(int reg_index, int value) override {
        if (reg_index < 0 || static_cast<size_t>(reg_index) >= reg_array.size()) 
            return;
        
        while (true) {
            mutex.lock();
            bool condition_met = (reg_array[reg_index] == value);
            mutex.unlock();
            
            if (condition_met) break;
            
            wait(reg_events[reg_index]);
        }
    }
private:
    std::vector<int> reg_array;
    std::vector<sc_core::sc_event> reg_events;
    sc_core::sc_mutex mutex;
};
class WorkerModule : public sc_core::sc_module {
public:
    SC_HAS_PROCESS(WorkerModule);
    sc_core::sc_port<reg_file_if> reg_file;
    
    const std::string module_name;
    
    WorkerModule(sc_core::sc_module_name name, const char* mod_name) 
        : sc_module(name), module_name(mod_name) 
    {
        SC_THREAD(main_process);
    }
    void main_process() {
        if (module_name == "A") {
            std::cout << "[" << sc_core::sc_time_stamp() << "] ModuleA: Writing reg0=1" << std::endl;
            reg_file->write(0, 1);
            wait(10, sc_core::SC_NS);
            std::cout << "[" << sc_core::sc_time_stamp() << "] ModuleA: Finished" << std::endl;
        } 
        else if (module_name == "B") {
            std::cout << "[" << sc_core::sc_time_stamp() << "] ModuleB: Waiting for reg0==1" << std::endl;
            reg_file->wait_until(0, 1);
            std::cout << "[" << sc_core::sc_time_stamp() << "] ModuleB: Writing reg1=10" << std::endl;
            reg_file->write(1, 10);
            wait(5, sc_core::SC_NS);
            std::cout << "[" << sc_core::sc_time_stamp() << "] ModuleB: Finished" << std::endl;
        }
        else if (module_name == "C") {
            std::cout << "[" << sc_core::sc_time_stamp() << "] ModuleC: Waiting for reg1==10" << std::endl;
            reg_file->wait_until(1, 10);
            std::cout << "[" << sc_core::sc_time_stamp() << "] ModuleC: Starting execution" << std::endl;
            wait(15, sc_core::SC_NS);
            std::cout << "[" << sc_core::sc_time_stamp() << "] ModuleC: Finished" << std::endl;
        }
    }
};
class Top : public sc_core::sc_module {
public:
    SyncRegFile reg_file;
    WorkerModule mod_a, mod_b, mod_c;
    Top(sc_core::sc_module_name name) 
        : sc_module(name),
          reg_file("RegFile", 20),  
          mod_a("ModuleA", "A"),
          mod_b("ModuleB", "B"),
          mod_c("ModuleC", "C") 
    {
        mod_a.reg_file(reg_file);
        mod_b.reg_file(reg_file);
        mod_c.reg_file(reg_file);
    }
};
int sc_main(int argc, char* argv[]) {
    Top top("Top");
    
    std::cout << "Starting simulation..." << std::endl;
    sc_core::sc_start(100, sc_core::SC_NS); 
    
    std::cout << "Simulation finished at " << sc_core::sc_time_stamp() << std::endl;
    return 0;
}

预期输出:

Starting simulation...
[0 s] ModuleA: Writing reg0=1
[0 s] ModuleB: Waiting for reg0==1
[0 s] ModuleC: Waiting for reg1==10
[0 s] ModuleB: Writing reg1=10
[0 s] ModuleC: Starting execution
[10 ns] ModuleA: Finished
[5 ns] ModuleB: Finished
[15 ns] ModuleC: Finished
Simulation finished at 15 ns

# 后记

本博客目前以及可预期的将来都不会支持评论功能。各位大侠如若有指教和问题,可以在我的 github 项目 或随便一个项目下提出 issue,并指明哪一篇博客,我看到一定及时回复!