在完成了systemc库安装并运行了hello world之后,自然就是要学习基于sc_module来传递和模拟一些算法。【systemC的学习日常】安装systemC库并运行第一个demo对于简单的数据传输和仿真,在systemc的安装路径下有例子可供参考:
systemc-2.3.3\examples\sysc在看了fir和fifo之后就觉得自己又要神功大成了,对于fir初看时可以参考下这个图如果有谁不清楚fir在干嘛的话:
好,到这一步简单的模块实现就没有什么大问题了,而后我们继续向着建模层面前进。在进入tlm学习之前,个人觉得有必要实现以下自建数据类型在sc_module之间的传输,因为官方给的sysc_demo里基本都是int/bool等基础类型作为接口的数据传输例子。所以这篇来做一下这个事情,当然直接进入tlm学习也挺好,其实我也是跑通了tlm之后回头补了一下这块。最近所有有关的代码都在下面的路径,本来以为反正不会有人看就私有了,没想到竟然有人用所以又开源了一下:
好的正文开始,这次的示例里我们在两个模块间进行对象的传输。传输的具体数据结构是什么呢?就选三维卷积处理中的元素好了。假定每一个三维卷积的元素具有两个属性:位置{x, y, z}和特征向量features:#include "systemc.h"class PointStruct {private: sc_dt::sc_uint16> feature[6]; sc_dt::sc_uint8> z_crd; sc_dt::sc_uint16> y_crd; sc_dt::sc_uint16> x_crd;};为这个类封装一些方法,在本例中我只封装了四个方法,构造函数、设置feature、打印和重载public: // 默认构造函数 PointStruct() : x_crd(0), y_crd(0), z_crd(0) { for (int i = 0; i 6; ++i) { feature = 0; } } // 带参数的构造函数 PointStruct(sc_dt::sc_uint16> x, sc_dt::sc_uint16> y, sc_dt::sc_uint8> z) : x_crd(x), y_crd(y), z_crd(z) { for (int i = 0; i 6; ++i) { feature = 0; } } // Setter 和打印函数 void setFeature(int idx, sc_dt::sc_uint16> value) { if (idx >= 0 && idx 6) feature[idx] = value; else throw std::out_of_range("Index out of range"); } void print() const { std::cout this } // 重载 friend std::ostream& operatorconst PointStruct& point) { os "Point coordinates: (" to_uint() ", " to_uint() ", " to_uint() "), Features: ["; for (int i = 0; i 6; ++i) { os to_uint(); if (i 5) os ", "; } os "]"; return os; }这其中,构造函数和重载class PointStruct {public: // 默认构造函数 PointStruct() : x_crd(0), y_crd(0), z_crd(0) { for (int i = 0; i 6; ++i) { feature = 0; } } // 带参数的构造函数 PointStruct(sc_dt::sc_uint16> x, sc_dt::sc_uint16> y, sc_dt::sc_uint8> z) : x_crd(x), y_crd(y), z_crd(z) { for (int i = 0; i 6; ++i) { feature = 0; } } // Setter 和打印函数 void setFeature(int idx, sc_dt::sc_uint16> value) { if (idx >= 0 && idx 6) feature[idx] = value; else throw std::out_of_range("Index out of range"); } void print() const { std::cout this } // 重载 friend std::ostream& operatorconst PointStruct& point) { os "Point coordinates: (" to_uint() ", " to_uint() ", " to_uint() "), Features: ["; for (int i = 0; i 6; ++i) { os to_uint(); if (i 5) os ", "; } os "]"; return os; }private: sc_dt::sc_uint16> feature[6]; sc_dt::sc_uint8> z_crd; sc_dt::sc_uint16> y_crd; sc_dt::sc_uint16> x_crd;};而后我们做一个producer来生成PointStruct,再做一个consumer来消耗,并将二者通过sc_port接在一起。producer的代码如下:// Producer 模块SC_MODULE(Producer) { sc_core::sc_port> out; SC_CTOR(Producer) { SC_THREAD(produce); } void produce() { for (int i = 0; i 10; ++i) { PointStruct point(i, i * 2, i * 3); for (int j = 0; j 6; ++j) { point.setFeature(j, i * 10 + j); } std::cout "Producer: Sending PointStruct " out->write(point); } }};对应的consumer代码如下:// Consumer 模块SC_MODULE(Consumer) { sc_core::sc_portsc_fifo_in_if> in; SC_CTOR(Consumer) { SC_THREAD(consume); } void consume() { for (int i = 0; i 10; ++i) { PointStruct point; in->read(point); std::cout "Consumer: Received PointStruct " endl; point.print(); wait(15, sc_core::SC_NS); } }};注意在这里直接使用了sc_core::sc_port>和sc_core::sc_port>,这也意味着后面将会使用sc_fifo进行数据传递。如果不这样做的话需要自行构造sc_channel比较复杂,如果想尝试下的话可以看官方example里的fifo示例。完成两个模块之后,只需要在顶层将二者借助sc_fifo进行连接就可以了。
本例中例化和连接的工作为求简单都在sc_main里做了,一般来说还是封一个test_top比较好哈:
// 主函数int sc_main(int argc, char* argv[]) { sc_core::sc_fifo fifo; Producer producer("Producer"); Consumer consumer("Consumer"); producer.out(fifo); consumer.in(fifo); sc_core::sc_start(); return 0;}结构也比较简单,例化一个PointStruct为缓存类型的sc_fifo,而后分别将其连接到producer和consumer的sc_port即可。之后make all一下就可以看到仿真结果了:$ make all SystemC 2.3.3-Accellera --- Nov 20 2024 15:14:09 Copyright (c) 1996-2018 by all Contributors, ALL RIGHTS RESERVEDProducer: Sending PointStruct 0Producer: Sending PointStruct 1Producer: Sending PointStruct 2Producer: Sending PointStruct 3Producer: Sending PointStruct 4Producer: Sending PointStruct 5Producer: Sending PointStruct 6Producer: Sending PointStruct 7Producer: Sending PointStruct 8Producer: Sending PointStruct 9Consumer: Received PointStruct 0Point coordinates: (0, 0, 0), Features: [0, 1, 2, 3, 4, 5]Consumer: Received PointStruct 1Point coordinates: (1, 2, 3), Features: [10, 11, 12, 13, 14, 15]Consumer: Received PointStruct 2Point coordinates: (2, 4, 6), Features: [20, 21, 22, 23, 24, 25]Consumer: Received PointStruct 3Point coordinates: (3, 6, 9), Features: [30, 31, 32, 33, 34, 35]Consumer: Received PointStruct 4Point coordinates: (4, 8, 12), Features: [40, 41, 42, 43, 44, 45]Consumer: Received PointStruct 5Point coordinates: (5, 10, 15), Features: [50, 51, 52, 53, 54, 55]Consumer: Received PointStruct 6Point coordinates: (6, 12, 18), Features: [60, 61, 62, 63, 64, 65]Consumer: Received PointStruct 7Point coordinates: (7, 14, 21), Features: [70, 71, 72, 73, 74, 75]Consumer: Received PointStruct 8Point coordinates: (8, 16, 24), Features: [80, 81, 82, 83, 84, 85]Consumer: Received PointStruct 9Point coordinates: (9, 18, 27), Features: [90, 91, 92, 93, 94, 95]
系列文章入口【芯片设计】SoC 101(一):绪论【芯片设计】FIFO漫谈(零)从无处不在的FIFO开始说起【芯片设计】计算机体系结构(一)虚拟内存【芯片设计】深入理解AMBA总线(零)绪论
【芯片设计】握手协议的介绍与时序说明【芯片设计】复位那些小事 —— 复位消抖【芯片设计】快速入门数字芯片设计(一)Introduction【芯片验证】UVM源码计划(零)下定决心读源码前的自测环节
【芯片设计】异步电路碎碎念(一) 到底什么是异步电路
【芯片设计】从RTL到GDS(一):Introduction
【芯片设计】系统中的可维可测状态记录寄存器设计
【芯片设计】偶遇编码建议(一)为什么RTL中避免使用task
其他文章链接【芯片验证】sva_assertion: 15道助力飞升的断言练习【芯片验证】可能是RTL定向验证的巅峰之作【芯片验证】RTL仿真中X态行为的传播 —— 从xprop说起【芯片验证】年轻人的第一个systemVerilog验证环境全工程与解析【芯片设计】verilog中有符号数和无符号数的本质探究
| 【芯片设计】论RTL中always语法的消失术 | 【芯片设计】代码即注释,注释即代码 | 【芯片设计】700行代码的risc处理器你确实不能要求太多了 |
入职芯片开发部门后,每天摸鱼之外的时间我们要做些什么呢 | 如何计算系统的outstanding 和 burst length? | 芯片搬砖日常·逼死强迫症的关键词不对齐事件 | 熟人社会里,一群没有社会价值的局外人 |
|