SystemC 学习之与 Verilog 的混合仿真(十)

1、SC 与 Verilog 的通信方式

Systemc 和 verilog 通信方式有两种,一种是 PLI,但是 PLI 只能 verilog 调用 c/c++,不能从 c/c++ 直接调用 verilog,想要从 c/c++ 调用 verilog 的话,需要先用 verilog 调用 c/c++ 函数,然后在 c++ 里面给对应的参数设置好值,然后 verilog 里面再拿这些数据,比较麻烦。还有一种是使用 DPI-C,DPI-C 是 system verilog 里面的,这样的话需要在编译的时候加上 -sverilog 编译选项

这里我们选用 DPI-C 将接口导入和导出,由于不会 verilog,所以对于 verilog 代码写的比较简单,如果有错误欢迎指正

2、一个简单例子

下面给出一个简单例子来说明 systemc 和 verilog 之间的数据传输

Makefile

SYSCAN = syscan -cpp g++ -cc gcc -tlm2                                          \
         -cflags -g                                                             \
         -cflags -DVCS                                                          \
         -cflags -std=c++11                                                     \
         -cflags -I${VCS_HOME}/etc/systemc/tlm/include/tlm/tlm_utils            \
         -cflags -I${UVMC_HOME}/src/connect/sc                                  \
         -cflags -I${UVMC_HOME}/src                                             \
         -cflags -Icpp                                                          \
         ${UVMC_HOME}/src/connect/sc/uvmc.cpp                                   \
         ${UVMC_HOME}/src/connect/sc/uvmc_export_stubs.cpp

VLOGAN = vlogan -q -sverilog                                                          \
         +incdir+${UVM_HOME}/src ${UVM_HOME}/src/uvm_pkg.sv                           \
         +incdir+${UVMC_HOME}/src/connect/sv ${UVMC_HOME}/src/connect/sv/uvmc_pkg.sv  \
         -timescale=1ns/1ps

VCS_ELAB = vcs -q -sysc=deltasync -lca                                          \
           -sysc -cpp g++ -cc gcc                                               \
           -timescale=1ns/1ps                                                   \
           -CFLAGS -DVCS ${UVM_HOME}/src/dpi/uvm_dpi.cc

CURRENT_DIR = $(shell pwd)
CPP_DIR = $(shell find $(CURRENT_DIR)/cpp -maxdepth 20 -type d)
SRCS_CPP += $(foreach dir, $(CPP_DIR), $(wildcard $(dir)/*.cpp))
SRCS_CC += $(foreach dir, $(CPP_DIR), $(wildcard $(dir)/*.cc))
SRCS_C += $(foreach dir, $(CPP_DIR), $(wildcard $(dir)/*.c))
VERILOG_DIR = $(shell find $(CURRENT_DIR)/verilog -maxdepth 20 -type d)
SRCS_VERILOG += $(foreach dir, $(VERILOG_DIR), $(wildcard $(dir)/*.v))

comp:
    $(VLOGAN) -full64 $(SRCS_VERILOG) +define+UVM_OBJECT_MUST_HAVE_CONSTRUCTOR
    $(SYSCAN) -full64 $(SRCS_CPP) $(SRCS_CC) $(SRCS_C)
    $(VCS_ELAB) -full64 verilog_main sc_main  # 这里要写 verilog、sv、sc 对外的模块名字
    
clean:
    rm -rf simv* work csrc ucli.key vc_hdrs.h vcs.log AN* *.log *.log.cmp *.vpd DVE* .vlogan*
    
run:
    ./simv

Systemc 模块

对外的头文件,extern 表示要调用的 verilog 接口

// sc2v.h
#ifndef SC2V_H
#define SC2V_H

extern "C" {
    // export
    void VerilogSendToSCModule(char* data, int len);

    void SaveScope();

    // import
    extern void SCSendToVerilog(char* data, int len);
}

#endif // SC2V_H


// sc2v.cpp
#include "sc2v.h"
#include <iostream>
#include "instance_manager.h"

void VerilogSendToSCModule(char* data, int len) {
    std::shared_ptr<DataManager> data_manager = InstanceManager::CreateInstance()->GetDataManager("receive_module");
    data_manager->ReceiveData(data, len);
}

void SaveScope() {
    std::cout << "SaveScope" << std::endl;
    InstanceManager::CreateInstance()->my_scope = svGetScope();
    InstanceManager::CreateInstance()->init_ = true;
}

因为 SCSendToVerilog 代码是在 verilog 里面的,单纯编译 c++ 代码会报错,所以这里要在 c++ 里面声明一个弱符号

// sc2v_stubs.cpp
#include <cstdio>
#include "sc2v.h"

void SCSendToVerilog(char* data, int len) __attribute__((weak));
// 不然 c++ 会报错
void SCSendToVerilog(char* data, int len) {
    printf("fake func\n");
}

c++ 收到 verilog 发过来的数据后,先将数据存放在一个队列里面,然后 systemc 有一个进程以一定时钟周期访问这个队列获取数据

// data_manager.h
#pragma once
#include <string>
#include <queue>

class DataManager {
public:
    DataManager();
    ~DataManager();

    void ReceiveData(const std::string& data, int len);
    bool GetData(std::string& data);

private:
    std::queue<std::string> data_queue_{};
};

// data_manager.cpp
DataManager::DataManager() = default;

DataManager::~DataManager() = default;

void DataManager::ReceiveData(const std::string& data, int len) {
    data_queue_.push(data);
}

bool DataManager::GetData(std::string& data) {
    if (data_queue_.empty()) {
        return false;
    }
    data = data_queue_.front();
    data_queue_.pop();
}
// instance_manager.h
#pragma once
#include <unordered_map>
#include <memory>
#include <string>
#include <svdpi.h>
#include "data_manager.h"

class InstanceManager {
public:
    static InstanceManager* CreateInstance();

    void Init();
    
    std::shared_ptr<DataManager> GetDataManager(const std::string& module_name);

public:
    svScope my_scope;
    bool init_ = false;

private:
    InstanceManager();
    ~InstanceManager();

    InstanceManager(const InstanceManager&) = delete;
    InstanceManager operator=(const InstanceManager& ) = delete;

private:
    std::unordered_map<std::string, std::shared_ptr<DataManager>> data_manager_map_{};
};

// instance_manager.cpp
#include "instance_manager.h"

const std::string receive_name = "receive_module";

InstanceManager* InstanceManager::CreateInstance() {
    static InstanceManager* instance = new InstanceManager();
    return instance;
}
    
std::shared_ptr<DataManager> InstanceManager::GetDataManager(const std::string& module_name) {
    if(data_manager_map_.find(module_name) == data_manager_map_.end()) {
        return nullptr;
    }
    return data_manager_map_[module_name];
}

void InstanceManager::Init() {
    data_manager_map_[receive_name].reset(new DataManager());
}

InstanceManager::InstanceManager()  = default;

InstanceManager::~InstanceManager() {
    data_manager_map_.clear();
}
// receiver.h
#pragma once
#include <systemc.h>

class Receiver : public sc_module {
public:
    SC_HAS_PROCESS(Receiver);
    Receiver(sc_module_name ins_name);
    ~Receiver();

    void ReceiverData();

public:
    sc_in_clk clk;
};

// receiver.cpp
#include "receiver.h"
#include "instance_manager.h"

Receiver::Receiver(sc_module_name ins_name) : sc_module(ins_name) {
    SC_METHOD(ReceiverData);
    sensitive << clk.pos();
    dont_initialize();
}

Receiver::~Receiver() = default;

void Receiver::ReceiverData() {
    std::shared_ptr<DataManager> data_manager = InstanceManager::CreateInstance()->GetDataManager("receive_module");
    std::string data;
    if (data_manager->GetData(data)) {
        std::cout << sc_time_stamp() << " " << data << std::endl;
    }
}
// sender.h
#pragma once
#include <systemc.h>
#include <string>

class Sender : public sc_module {
public:
    SC_HAS_PROCESS(Sender);
    Sender(sc_module_name instname);
    ~Sender();
    void SendData();

public:
    sc_in_clk clk;

private:
    int val_{};
};

// sender.cpp
#include "sender.h"

#include <string>

#include "instance_manager.h"
#include "sc2v.h"

Sender::Sender(sc_module_name instname) : sc_module(instname) {
    SC_METHOD(SendData);
    sensitive << clk.pos();
    dont_initialize();
}

Sender::~Sender() = default;

void Sender::SendData() {
    if(!InstanceManager::CreateInstance()->init_) {
        return;
    }
    std::string data = "systemc " + std::to_string(val_++);
    svSetScope(InstanceManager::CreateInstance()->my_scope);
    SCSendToVerilog((char*)data.c_str(), data.length());
}
// main.cpp
#include <systemc.h>
#include "receiver.h"
#include "sender.h"
#include "instance_manager.h"

int sc_main(int argc, char* argv[]) {
    InstanceManager::CreateInstance()->Init();
    Receiver receiver("receiver");
    Sender sender("sender");
    sc_clock clk("clk", 20, SC_NS);
    receiver.clk(clk);
    sender.clk(clk);
    sc_start(200, SC_NS);
    return 0;
}

Verilog 模块

import:表示 verilog 调用 c++ 的接口

export:导出接口,表示提供给 c++ 可以调用的接口

module verilog_main;
    import "DPI-C" context function VerilogSendToSCModule(string data, int len);
    import "DPI-C" context function void SaveScope(); 
    export "DPI-C" function SCSendToVerilog;
    function void SCSendToVerilog(string data, int len);
        $display("Verilog::data:%s", data);
        VerilogSendToSCModule(data, len);
        endfunction
    initial begin
        SaveScope();
    end
endmodule

这里调用 SaveScope 是因为只有在 verilog 初始化之后才能拿到当前的 scope,每次 c++ 传输数据给 verilog 时需要先设置 scope,然后才能发送数据

编译运行

make comp
./simv

运行结果如下所示

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/146810.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

github镜像访问方法

https://ghproxy.com/ &#xff08;GitHub 文件 , Releases , archive , gist , raw.githubusercontent.com 文件代理加速下载服务&#xff09; https://mirror.ghproxy.com/ 在这个网址后面直接加上github的网址&#xff0c;如&#xff1a; https://mirror.ghproxy.com/htt…

光刻机ASML CYMER光电模块组件维修114122,S111310

1&#xff1a;436nm g-line 可以满足0.8-0.35 微米制程芯片的生产&#xff0c;对应设备有接触式和接近式光刻机。 2&#xff1a;365nm i-line 同样可以满足0.8~0.35微米制程芯片的生产。设备于上相同。 早期的光刻机采用接触式光刻&#xff0c;即掩模贴在硅片上进行光刻&…

hadoop 大数据集群环境配置 配置hadoop配置文件 hadoop(七)

1. 虚拟机的三台机器分别以hdfs 存储, mapreduce计算&#xff0c;yarn调度三个方面进行集群配置 hadoop 版本3.3.4 官网&#xff1a;Hadoop – Apache Hadoop 3.3.6 jdk 1.8 三台机器尾号为&#xff1a;22&#xff0c; 23&#xff0c; 24。&#xff08;没有用hadoop102, 103,10…

C 语言数组

C 语言数组 在本教程中&#xff0c;您将学习如何使用数组。您将借助示例学习如何声明&#xff0c;初始化和访问数组的元素。 数组是可以存储多个值的变量。例如&#xff0c;如果要存储100个整数&#xff0c;则可以为其创建一个数组。 示例 cint data[100];如何声明数组&…

vue3 el-menu初始化时选中没有高亮的问题(default-active和index的问题)

首先看官方文档的示例&#xff1a; 需要注意的是&#xff1a; 1、default-active的值是字符串&#xff0c;那么index绑定的值也要是字符串&#xff0c;且数字对应。不能default-avtive绑定的是1&#xff0c;而menu-item的index绑定的是45 2、default-active的值是当前选中me…

[工业自动化-20]:西门子S7-15xxx编程 - 软件编程 - 基本编程指令与梯形图基本元素:位逻辑指令、定时器指令、计数器指令、触发器指令

目录 一、PLC编程的基本指令 1.1 什么是PLC指令 1.2 PLC指令的分类 1.3 PLC指令与梯形图基本元素的关系 三、基本的位运算指令 四、边沿触发指令 4.1 什么是沿 4.2 沿的持续时间 4.3 使用场景 五、定时器指令 六、计数器指令 七、触发器指令 一、PLC编程的基本指令…

gpt-4-vision-preview 识图

这些图片都是流行动画角色的插图。 第一张图片中的角色是一块穿着棕色方形裤子、红领带和白色衬衫的海绵&#xff0c;它站立着并露出开心的笑容。该角色在一个蓝色的背景前&#xff0c;显得非常兴奋和活泼。 第二张图片展示的是一只灰色的小老鼠&#xff0c;表情开心&#xf…

esp32cam串口问题

选择的串口 Failed to execute script esptool不存在或开发板没有连接 设置串口参数时出错&#xff1a;9,600 N 8 1注意到他说的串口设置错误,但是在设置里不能设置串口参数 所以说是串口打印的问题 把他换成esp32用的115200就行

大模型的全面回顾,看透大模型 | A Comprehensive Overview of Large Language Models

大模型的全面回顾&#xff1a;A Comprehensive Overview of Large Language Models 返回论文和资料目录 论文地址 1.导读 相比今年4月的中国人民大学发表的大模型综述&#xff0c;这篇综述角度更侧重于大模型的实现&#xff0c;更加硬核&#xff0c;更适合深入了解大模型的一…

《从零开始读懂相对论》

内容简介 相对论诞生至今已逾百年&#xff0c;但依然被人们津津乐道。相对论为什么如此有魅力&#xff1f;爱因斯坦为什么要创立相对论&#xff1f;本书从“零”开始&#xff0c;紧抓“相对”二字&#xff0c;将所有问题置于历史的背景下&#xff0c;竭力展现人类探索运动本质…

实用篇-ES-DSL操作文档

一、mapping属性 mapping属性的官方文档: https://elastic.co/guide/en/elasticsearch/reference/current/index.html 下面的表格是介绍elasticsearch中的各个概念以及含义&#xff0c;看的时候重点看第二、三列&#xff0c;第一列是为了让你更理解第二列的意思&#xff0c;所…

论文精读 MediaPipe BlazeFace

BlazeFace:Sub-millisecond Neural Face Detection on Mobile GPUs BlazeFace&#xff1a;基于移动GPUs的亚毫秒神经人脸检测 论文地址&#xff1a;arxiv.org/pdf/1907.05047.pdf 源码地址&#xff1a;GitHub - tkat0/PyTorch_BlazeFace: Unofficial PyTorch implementation…

无需数据库服务器部署脚本,全能型开源数据库监控平台lepus

Lepus 是一款开源的数据库监控平台&#xff0c;目前已经支持 MySQL、Oracle、SQLserver、MongoDB、Redis 等数据库的基本监控和告警。 Lepus 在监控数据库时&#xff0c;无需在每台数据库服务器上部署脚本或 Agent&#xff0c;只需要在数据库中创建授权账号后&#xff0c;即可…

Python-Python高阶技巧:HTTP协议、静态Web服务器程序开发、循环接收客户端的连接请求

版本说明 当前版本号[20231114]。 版本修改说明20231114初版 目录 文章目录 版本说明目录HTTP协议1、网址1.1 网址的概念1.2 URL的组成1.3 知识要点 2、HTTP协议的介绍2.1 HTTP协议的概念及作用2.2 HTTP协议的概念及作用2.3 浏览器访问Web服务器的过程 3、HTTP请求报文3.1 H…

算法萌新闯力扣:x的平方根

力扣热题&#xff1a;69.x的平方根 开篇 这是一道练习二分查找的题目&#xff0c;简单但也有一些细节需要注意&#xff0c;如判断条件、溢出等。 题目链接:69.x的平方根 题目描述 代码思路 1.一开始使用暴力解&#xff0c;发现超时了&#xff0c;看了标签&#xff0c;原来又…

thinkphp6(TP6)访问控制器报404(Nginx)

起因&#xff1a; 安装thinphp6后&#xff0c;发现无法访问控制器&#xff0c;直接通过URL访问&#xff0c;就报错404。 错误原因&#xff1a; Nginx不支持URL的 PathInfo。 解决方法&#xff1a; 配置伪静态。 伪静态代码&#xff1a; location / {if (!-e $request_filen…

MyBatis源码分析

MyBatis源码分析 MyBatis是常用的持久层框架&#xff0c;帮助我们减少了很多的访问数据库的代码。这次我们就来看看MyBatis是怎么做到这些的&#xff1f;看看它里面用到了哪些值得我们借鉴的技术。 一、示例程序 为了方便后续在本地进行debug调试&#xff0c;首先准备一个示…

【Hello Algorithm】单调栈(未完待续)

单调栈解决的问题 我们单调栈的提出主要是为了解决这么一个问题 现在给我们一个数组 现在要求你建立一张表 这张表中能够查询到两个信息 这两个信息分别是 当前数字左边小于该数字并且下标位置最相近的下标当前数字右边小于该数字并且下标位置最相近的下标 同理 大于也可以…

机器学习入门案例(3)之使用决策树预测是否适合打网球

大家好&#xff0c;我是邵奈一&#xff0c;一个不务正业的程序猿、正儿八经的斜杠青年。 1、世人称我为&#xff1a;被代码耽误的诗人、没天赋的书法家、五音不全的歌手、专业跑龙套演员、不合格的运动员… 2、这几年&#xff0c;我整理了很多IT技术相关的教程给大家&#xff0…

如何解决网页中的pdf文件无法下载?pdf打印显示空白怎么办?

问题描述 偶然间&#xff0c;遇到这样一个问题&#xff0c;一个网页上的附件pdf想要下载打印下来&#xff0c;奈何尝试多种办法都不能将其下载下载&#xff0c;点击打印出现的也是一片空白 百度搜索了一些解决方案都不太行&#xff0c;主要解决方案如&#xff1a;https://zh…