SystemC中的模块和程序

摘要:本节包含一个完整的简单设计,用于演示 SystemC 中模块和流程的使用。 为简单起见,它是非常低级的 - 不是您通常在系统级设计语言中期望的编码风格!主要有以下几个部分:

  • Creating hierarchy
  • The sc_signal primitive channel
  • (Specialized) ports
  • Processes (SC_METHOD, SC_THREAD, SC_CTHREAD)
  • A simple test bench

一、SystemC Background

为什么要看模块和流程? 原因是 SystemC 旨在同时处理硬件和软件,并允许对大型系统进行建模。

进程是与其他进程同时运行的一小段代码。 几乎所有已开发的高级系统级设计 (SLD) 工具都使用流程网络的底层模型。 SystemC 提供了支持构建独立(并发/并行)代码段网络的过程。

SLD 需要处理大型设计。 为了解决这个问题,通常使用层次结构。 层次结构在 SystemC 中通过使用模块实现,该类可以使用端口链接到其他模块。 模块允许单独处理一个设计。 模块可能包含进程和其他模块的实例。

二、设计实例分析

该设计包括一个用四个 NAND 门实现的 EXOR 门。 同样,重要的是要注意这不是典型的设计风格 - 但它很好而且易于理解。 设计如下所示:

第一步是对与非门进行建模。 与非门是组合电路; 它的输出纯粹是输入值的函数。 它没有记忆,也不需要时钟。 因此,模型可以使用最简单的 SystemC 进程,即 SC_METHOD。

SC_METHOD 只是 C++ 函数。 因此,SystemC 类库必须使它们表现得像进程。 尤其是:

  • SystemC 类库包含一个模拟内核——一段模拟时间流逝的代码,并在输入发生变化时调用函数来计算其输出。
  • 该函数必须声明为 SC_METHOD 并对其输入敏感。

这是与非门的代码,在一个文件中,nand.h

#include "systemc.h"
SC_MODULE(nand2)          // declare nand2 sc_module
{sc_in<bool> A, B;       // input signal portssc_out<bool> F;         // output signal portsvoid do_nand2()         // a C++ function{F.write( !(A.read() && B.read()) );}SC_CTOR(nand2)          // constructor for nand2{SC_METHOD(do_nand2);  // register do_nand2 with kernelsensitive << A << B;  // sensitivity list}
};

SystemC 中的层次结构是使用类 sc_module 创建的。 sc_module 可以直接使用,也可以使用宏 SC_MODULE “隐藏”。 上面的示例 SC_MODULE 创建了一个名为 nand2 的 sc_module 类对象。

接下来是声明的输入和输出端口。 通常,使用类 sc_port 声明端口。 例如,将声明使用 sc_signal 的输入端口:

sc_port<sc_signal_in_if<bool>,1> A,B;

但正如你所看到的,这是很多打字。 为方便起见,还可以创建和使用专用端口。 sc_in 是 sc_signal 类的专用端口的示例。

端口可以是任何 C++ 或 SystemC 类型 - 该示例使用 bool,一种内置的 C++ 类型。

接下来,声明完成这项工作的函数。 输入和输出(专用)端口包括方法 read() 和 write() 以允许读取和写入端口。 读取 A 和 B,计算 NAND 函数,并使用 write() 方法将结果写入 F。

请注意,您通常可以在不使用 read() 和 write() 方法的情况下摆脱困境,因为 = 运算符和类型转换运算符已被重载。 所以你可以写:

F = !(A && B);

但是使用 read() 和 write() 是一个好习惯,因为它可以帮助 C++ 编译器消除表达式的歧义。

函数do_nand2()写完后,就有了sc_module实例nand2的构造函数。 SystemC 提供了一种简写方式,使用宏 SC_CTOR。 构造函数执行以下操作:

  • 创建层次结构(在这种情况下没有)
  • 将函数注册为仿真内核的进程
  • 声明进程的敏感度列表

也可以在这里初始化任何需要初始化的东西——例如,可以初始化一个类数据成员。

在上面的示例中,构造函数声明 do_nand2 是一个 SC_METHOD,并表示端口 A 和 B 上的任何事件都必须使内核运行该函数(从而为 F 计算一个新值)。

三、Hierarchy

EXOR 门由 NAND 门的四个副本(或实例)构成。 这是通过使用 EXOR 门构造函数连接 NAND 门实例来实现的。 这是 EXOR 门的代码:

#include "systemc.h"
#include "nand2.h"
SC_MODULE(exor2)
{sc_in<bool> A, B;sc_out<bool> F;nand2 n1, n2, n3, n4;sc_signal<bool> S1, S2, S3;SC_CTOR(exor2) : n1("N1"), n2("N2"), n3("N3"), n4("N4"){n1.A(A);n1.B(B);n1.F(S1);n2.A(A);n2.B(S1);n2.F(S2);n3.A(S1);n3.B(B);n3.F(S3);n4.A(S2);n4.B(S3);n4.F(F);}
};

开头看起来与 NAND 门非常相似,但请注意它包含文件 nand2.h。这允许访问包含与非门的模块。

创建了模块 exor2,并声明了端口。请注意,允许重复使用名称 A、B 和 F,因为这是层次结构的不同级别。

原始图表显示了一些连接 NAND 门的“线”。这些是通过声明 sc_signals S1、S2 和 S3 创建的。 sc_signal 是一个带有模板参数的类,该参数指定信号可以保存的数据类型 - 在本例中为 bool。 sc_signal 是原始通道的示例,它是 SystemC 类库中的内置通道。它的行为类似于 VHDL 中的信号。

EXOR 门的构造函数比 NAND 门的构造函数更复杂,因为它必须有四个 nand2 实例。在端口声明之后,声明了 nand2 的四个实例:n1、n2、n3 和 n4。必须给每个实例一个标签。四个标签“N1”、“N2”、“N3”和“N4”通过使用 exor2 构造函数上的初始化列表传递给 nand2 实例的构造函数。

最后,将端口连接起来。如图所示,这是在构造函数中完成的。

四、验证环境

为了测试设计,有一个刺激发生器。 这是另一个模块,与上面的非常相似。 唯一重要的一点是它使用了一个线程 (SC_THREAD),这是一种可以暂停的进程。 这是 stim.h 的代码:

#include "systemc.h"
SC_MODULE(stim)
{sc_out<bool> A, B;sc_in<bool> Clk;void StimGen(){A.write(false);B.write(false);wait();A.write(false);B.write(true);wait();A.write(true);B.write(false);wait();A.write(true);B.write(true);wait();sc_stop();}SC_CTOR(stim){SC_THREAD(StimGen);sensitive << Clk.pos();}
};
  • 请注意对 sc_stop() 的最终调用,它使模拟停止。 监视器代码看起来非常相似,因此被省略 - 它位于文件 mon.h 中。

这是顶层 - 它位于包含上述所有子模块的文件 main.cpp 中:

#include "systemc.h"
#include "stim.h"
#include "exor2.h"
#include "mon.h"int sc_main(int argc, char* argv[])
{sc_signal<bool> ASig, BSig, FSig;sc_clock TestClk("TestClock", 10, SC_NS,0.5);stim Stim1("Stimulus");Stim1.A(ASig);Stim1.B(BSig);Stim1.Clk(TestClk);exor2 DUT("exor2");DUT.A(ASig);DUT.B(BSig);DUT.F(FSig);mon Monitor1("Monitor");Monitor1.A(ASig);Monitor1.B(BSig);Monitor1.F(FSig);Monitor1.Clk(TestClk);sc_start();  // run foreverreturn 0;};

包括模块的头文件,声明用于布线的顶层信号,以及使用 sc_clock 创建的时钟; 然后每个模块都被实例化和连接。之后,调用 sc_start() 会启动模拟并永远运行(或者更确切地说,直到在刺激模块中遇到对 sc_stop() 的调用)。

  • 这是此示例的输出
      Time A B F0 s 0 0 110 ns 0 0 020 ns 0 1 130 ns 1 0 140 ns 1 1 0
  • 如果你看它,你会注意到一些非常奇怪的东西——时间 0 的第一行说 F 是 1(真),而 A 和 B 是 0——这不是一个非常令人信服的异或门!到 10 ns,一切正常。时间 0 发生了什么?

五、仿真

SystemC 库包含一个仿真内核。这决定了运行哪些进程(软件线程)。在时间 0,所有 SC_METHOD 和 SC_THREAD 将以未定义的顺序运行,直到它们挂起。然后 SC_CTHREADs 将在时钟沿出现时运行。上述问题是由于多种情况造成的:

  1. sc_clock 语句在时间 0 产生一个上升沿,因此监视器和激励进程都将运行(以未定义的顺序,不知道哪个将首先运行)。
  2. C++ 中的变量并不总是具有定义的初始值(除非它们被声明为静态)。所以 F 持有的数据值恰好从 1 开始(真)。
  3. do_nand2 SC_METHOD在时间0运行,调度F更新,但是F是一个信号,不能瞬间更新,所以monitor进程运行时值1仍然存在。

为了证明是这样,可以修改sc_clock语句来延迟时钟的第一个边沿,如下:

sc_clock TestClk("TestClock", 10, SC_NS,0.5, 1, SC_NS);

最后的 1,SC_NS 参数指定第一个时钟边沿出现之前的 1 ns 延迟。 现在时间已经过去,所以 F 将被更新。 这是对应的输出:

     Time A B F1 ns 0 0 011 ns 0 0 021 ns 0 1 131 ns 1 0 141 ns 1 1 0
  • 现在你可以看到 F 总是正确的。

六、结论

对模块和流程的快速浏览到此结束。 您已经看到了解 SystemC 仿真内核的并发特性以及 sc_signal 原始通道的行为的重要性。

您还看到了在顶级模块中实例化较低级别模块的一些基本示例,以及如何使用 sc_main。

[SystemC]SystemC中的模块和程序相关推荐

  1. PHP laravel 加模块,php – 如何在Laravel 5中构建模块化应用程序?

    我想在模块中划分我的应用程序.例如,将有一个"核心"模块,其中包含基本登录功能,应用程序布局/格式化(CSS等),用户管理和日记. 稍后我可以创建其他模块,如联系人管理器,可以轻松 ...

  2. 站在巨人的肩膀上,Adrian与dlib中face_recongnition模块的贡献者Adam的采访部分翻译

    这篇博客是Adrain对Adam Geitgey的采访部分翻译 Adrian:pyimagesearch博客作者,博士,写了很多关于OpenCV,人脸识别,机器学习,深度学习,计算机视觉等的高质量博客 ...

  3. node.js中模块_在Node.js中需要模块:您需要知道的一切

    node.js中模块 by Samer Buna 通过Samer Buna 在Node.js中需要模块:您需要知道的一切 (Requiring modules in Node.js: Everythi ...

  4. 关于学习Python的一点学习总结(52->模块就是程序)

    91.模块就是程序 # hello.py print("Hello, world!") 将其保存在文件hello.py中,这个文件的名称(不包括扩展名.py)将成为模块的名称.这个 ...

  5. python中导入模块用什么命令_Python导入模块的技巧

    作为使用Python的开发者,我们一开始学习的内容之一就是如何导入Python的各种模块或库.但是我们注意到,那些经常使用Python的用户并不一定都知道Python的导入机制其实非常灵活.在本文中, ...

  6. 请教如何改善C#中socket通信机客户端程序的健壮性

    请教如何改善c#中socket通信机客户端程序的健壮性 我是做socket的新手,最近做了一个socket客户端程序,连接server的时候,如果server存在,并且允许连接的话,程序无错,正常执行 ...

  7. python sys模块作用_浅谈Python中的模块

    模块 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式.在Python中,一个.py文件就称之为一个模块(Mod ...

  8. python中Scipy模块求取积分

    python中Scipy模块求取积分的方法: SciPy下实现求函数的积分的函数的基本使用,积分,高等数学里有大量的讲述,基本意思就是求曲线下面积之和. 其中rn可认为是偏差,一般可以忽略不计,wi可 ...

  9. python中copy模块的使用,深拷贝和浅拷贝

    python中copy模块的使用,深拷贝和浅拷贝 文章目录: 一.copy模块的介绍 1.copy模块 二.copy模块的使用 拓展说明: 1.id( )函数的使用 2.is和== 的区别 pytho ...

  10. python中的模块和包

    模块 一 什么是模块 模块就是一组功能的集合体,可以通过导入模块来复用模块的功能. 比如我在同一个文件夹定义两个.py文件,分别命名为A.py和B.py,那么可以通过在A文件里通过import B来使 ...

最新文章

  1. R语言基于自定义函数构建xgboost模型并使用LIME解释器进行模型预测结果解释:基于训练数据以及模型构建LIME解释器解释多个iris数据样本的预测结果、使用LIME解释器进行模型预测结果解释
  2. 利用matlab对xml文件进行批量处理
  3. POJ 1269 Intersecting Lines(求直线交点)
  4. [react-router] React-Router 4怎样在路由变化时重新渲染同一个组件?
  5. 软件设计是怎样炼成的(1)——什么是优秀的设计?
  6. anaconda查看conda主环境、虚拟环境的python执行路径
  7. 裁员之后人手却不够,马斯克和母亲只好亲自上阵帮忙了
  8. pgsql 筛选中文字符正则_PostgreSQL正则及模糊查询优化
  9. Angular 2 之七 依赖注入
  10. linux之type命令
  11. 一个前端如何画各种特效或图案
  12. 配置maven使用阿里云仓库
  13. 日语单词记忆方法(正在试用)
  14. sunshine in the rainsunshine in the rain
  15. Linux使用grep查找文件内容
  16. 师范大学计算机专业研究生,2019考研调剂:福建师范大学计算机类学硕研究生调剂生...
  17. 创作者基金 11 月亮点
  18. 三次多项式的因式分解
  19. Python实现冒泡排序,从小到大输出(bubble)
  20. kirin710f是什么处理器_HUAWEIKirin710F处理器是什么机型?

热门文章

  1. (已解决)vue数组添加数据后页面无法实时渲染
  2. matlab 函数定义 属性,matlab class()函数类定义技巧
  3. cass等距离等分线段的命令键_教你用CAD将线段等分,弧线也可定距等分!
  4. 微信小程序怎么做淘宝客优惠券商城手把手教你完成从申请到上线
  5. 微信小程序使用sass
  6. clickhouse-backup数据备份
  7. 动态规划之《高楼扔鸡蛋》问题详解 LeetCode 887.鸡蛋掉落
  8. blackbox_exporter 黑盒监测
  9. mysql union 慢_mysql查询慢的原因和解决方案
  10. 动态规划 -- 活动时间问题