4.2【A】

CXL 是一种和 PCIe 兼容的扩展协议,CXLMemory 本质是插在 PCIe 插槽上的扩展内存设备(可以理解成 "外置内存条")。它的核心能力:

  1. 能被主机识别(走 PCIe 枚举流程,配置空间 / BAR 这些是识别的关键);
  2. 有自己的存储空间,能响应主机的读写请求;
  3. 能解析 CXL 协议的数据包(区分读 / 写指令,模拟协议处理延迟)。

自己的存储空间:通过实现一个Memory嵌套类,子类成员变量包括存储空间地址范围、指向存储地址的指针;成员函数主要包括access()访问函数,以根据不同的命令访问存储空间

读写功能:通过对PciDevice的继承,实现read()和write()函数,在read()和write()内部会调用access()访问存储空间

解析cxl协议的数据包:主要是在这里确定数据包的格式并模拟一个解析的延迟返回回去

  • PCIe 接口 ↔ 连主机(gem5/QEMU)
  • Ethernet 接口 ↔ 连网络(ns-3/switch

核心作用是:创建可同时支持 PCIe 总线 + 以太网功能的虚拟网卡(如 Intel I40e、E1000 真实网卡的仿真模型)

class SimplePCIeNIC(pcie.PCIeSimpleDevice, eth.EthSimpleNIC):

这个类同时继承两个父类 ,让虚拟网卡拥有双重能力

  1. pcie.PCIeSimpleDevice → 让网卡支持 PCIe 总线连接(电脑主板插卡的接口)
  2. eth.EthSimpleNIC → 让网卡支持以太网功能(收发网络数据包)

核心方法:add_if(添加接口)

这是整个代码最重要的方法,作用是:给网卡绑定对应的硬件接口。

参数 interface:可以是 以太网接口PCIe 设备接口| 是 Python 类型注解:二选一)

在静态类型语言(如 Java, C++)中,类型检查通常发生在编译阶段(代码运行之前)。如果类型不对,代码根本无法编译通过。

但在 Python 这种动态类型语言中,变量的类型是在程序运行过程中才确定的

  • 编译时 :Python 解释器通常不知道 c 到底是不是 EthChannel
  • 运行时 :当代码执行到 connect 函数时,程序必须停下来检查一下:"传入的 c 到底是不是 EthChannel 类型?"

这行代码正在检查传入参数 c数据类型

  • 检查对象 :变量 c(它代表一个 Channel/通道)。
  • 预期目标EthChannel(以太网通道类型)。
  • 检查逻辑utils_base.has_expected_type 这个函数的作用是判断 c 是否属于 EthChannel 类(或者是它的子类)。
  • 后果 :如果 c 不是 EthChannel 类型,这个检查通常会抛出一个错误(Exception),阻止程序继续执行,防止后续代码因为类型不匹配而崩溃。

NIC1 (EthSimpleNIC)

↓ (EthInterface)

网线 (EthWire)

↓ (EthInterface)

NIC2 (EthSimpleNIC)

nic1.connect_eth_peer_if(eth_wire)

nic2.connect_eth_peer_if(eth_wire)

是 Python 模型(system/nic.py、pcie.py)与真实 C++ 模拟器之间的 "胶水"

它不做模拟,只做 3 件事:

  1. 告诉框架要启动哪个 C++ 可执行文件
  2. 把 PCIe 接口、以太网接口的连接信息传给 C++ 模拟器
  3. 生成启动命令(命令行参数)
  • 把 Python 模型(SimplePCIeNIC)绑定到模拟器
  • 一个网卡模拟器 只能绑定一个网卡

. class NICSim(PCIDevSim)

所有网卡模拟器的父类

它处理 所有网卡共通逻辑:

双接口(PCIe + Ethernet)

延迟、同步周期

生成通用启动命令

绑定网卡设备

1.2 toJSON / fromJSON

作用:

  • 序列化 / 反序列化
  • 把模拟器配置保存成 JSON,供底层 C++ 读取

1.4 add(nic) 🔥【关键:绑定设备】

python

运行

复制代码
def add(self, nic: sys_nic.SimplePCIeNIC):
    assert len(self._components) < 1
    super().add(nic)

作用:

  • 把 Python 定义的 NIC 设备绑定到模拟器

  • 一个模拟器 只能绑定一个网卡

  • 建立 设备模型 ↔ 模拟器 的关系

  • latency(延迟)

    • 数据从一端传到另一端需要的时间
    • 单位:picoseconds 皮秒
    • 例:PCIe 延迟 200ns
  • sync_period(同步周期)

    • 模拟器之间多久同步一次时间
    • 单位:picoseconds
    • 例:每 1000ns 同步一次
  • run_sync(是否同步模式)

    • True = 严格时序同步(高精度仿真)

    • False = 异步运行(速度快,但精度低)

      sync_period = (
      min(sync_period, channel.sync_period)
      if sync_period
      else channel.sync_period
      )

所有通道里,同步周期 取 最小的那个!

  • 同步周期越小,精度越高
  • 必须按最小的同步周期运行,否则会时序错乱

只要有一个通道需要同步,整个模拟器就必须同步!

  • False or False → False
  • False or True → True
  • True or True → True

所有通道里,延迟 取 最大的那个!

  • 必须保证最坏情况的延迟
  • 不能用最小延迟,否则会出现数据提前到达

1. 同步周期 = 取最小的

要保证最快的同步频率

2. 延迟 = 取最大的

要保证最坏情况的延迟

3. 是否同步 = 只要有一个是同步,整体就必须同步

一票否决制

因为 NIC 有两个接口

  1. PCIe 接口
  2. Ethernet 接口

两边的延迟、同步周期可能不一样!

所以必须:

  • 把 PCIe 的参数
  • 把 Ethernet 的参数合并成一组参数,给 C++ 模拟器用!

返回 SimBricks 源码根目录 + 你传入的相对路径

它做了什么?

找到 SimBricks 项目根目录

把你给的 相对路径 拼在后面

返回 完整绝对路径

inst = Instantiation(实例化)

inst.env = Instantiation Environment

意思:

当前仿真运行的环境对象

它里面保存了:

SimBricks 根目录

输出目录

日志目录

临时文件目录

环境变量

路径工具(例如 repo_base)

所以:

inst.env.repo_base()

就是:让当前运行环境帮我找到模拟器的可执行文件路径

给 C++ 模拟器传递它必须的 "连接参数"

让 C++ 模拟器知道:

我要连哪个 socket

同步模式开不开

延迟是多少

同步周期是多少

从什么时候开始运行

复制代码
def get_socket(self, interface: sys_base.Interface) -> inst_socket.Socket | None:

作用:给一个硬件接口(Eth 口、PCIe 口)分配一个通信 Socket

  • 生成一个唯一的路径,例如 /tmp/simbricks-1234
  • 创建一个 Unix Socket(进程间通信通道)

get_socket = 给每个硬件接口创建一根 "虚拟电线"

这根电线就是 Socket

Socket = 两个模拟器之间的【虚拟电线】

现实世界:

  • 网卡 ↔ 交换机 → 用网线连接
  • CPU ↔ 网卡 → 用PCIe 插槽连接

SimBricks 仿真世界:

  • 模拟器 A ↔ 模拟器 B → 用 Socket 连接

本质:

**Socket 就是 Linux 系统提供的【进程间通信通道】**让两个独立的 C++ 程序(比如主机模拟器、网卡模拟器)互相发数据。

第 3 层:IPv4 地址(你配置的 IP)

第 2 层:以太网帧(Eth 接口收发的包)

第 1 层:Socket(真正传输数据的通道)

1. EthInterface(Python)

  • 模型:网卡有一个网口
  • 作用:逻辑上的网口

2. EthChannel(Python)

  • 模型:两根网口连起来
  • 作用:逻辑连线

3. Socket(Instantiation)

  • 真实:创建 Unix Socket
  • 作用:真正的物理传输通道

4. C++ 模拟器

  • 真实收发数据包
  • 通过 Socket 传输

nic_devices = self.filter_components_by_type(ty=sys_nic.SimplePCIeNIC)

assert len(nic_devices) == 1

nic_device = nic_devices[0]

在NICSim中,要得到自身模拟的对象nic_device,

整个流程 = 搭积木 → 配对 → 绑定 → 生成命令 → 启动进程

  • 搭积木sys = System(),创建主机、网卡、交换机(只是模型)
  • 配对compmap={ 模型类: 模拟器类 },告诉系统 "这个模型用哪个模拟器"
  • 绑定simulator.add(comp) 这就是 component 被赋值的时刻!
  • 生成命令run_cmd() 把模型参数变成 C++ 启动命令
  • 启动进程:运行 C++ 模拟器,真正开始仿真

simulator = I40eNicSim(simulation) # 新建模拟器,此时 components = []

simulator.add(nic0) # 🔥 绑定!

  • I40eNicSim → 对应 sims/nic/i40e_bm/i40e_bm(可执行文件)
  • E1000NIC → 对应 sims/nic/e1000_gem5/e1000_gem5(可执行文件)
复制代码
e1000_gem5.cc
├── 全局变量:runner(SimBricks 运行器)、debug
├── Gem5DMAOp:DMA 操作封装类
├── IGbE 类方法:E1000 硬件实现 + SimBricks 回调
│   ├── SetupIntro:配置PCIe信息
│   ├── RegRead/RegWrite:寄存器读写
│   ├── DmaComplete:DMA 完成回调
│   ├── EthRx:收到以太网包
│   ├── Timed:事件调度
│   ├── gem5 API:schedule/intrPost/dmaRead/dmaWrite/sendPacket
├── 工具函数:warn/panic/debug_printf
└── main:主函数(模拟器入口)
相关推荐
Fanmeang2 小时前
江苏信息安全管理与评估赛项任务一交换部分参考答案
网络·职业院校技能大赛·信息安全管理与评估
wuhui21002 小时前
宿主机与虚拟机网络配置打通
网络·kali·虚拟机
大公产经晚间消息2 小时前
上海15万辆美团单车春季焕新,多重保障迎骑行高峰
网络·人工智能·美团·携程
电商API&Tina2 小时前
【京东item_getAPI 】高稳定:API 、非爬虫、不封号、不掉线、大促稳跑
大数据·网络·人工智能·爬虫·python·sql·json
上海云盾安全满满2 小时前
高防IP是什么 都适用于哪些行业
网络·网络协议·tcp/ip
摄影图2 小时前
隐私保护数字盾牌设计图片素材 满足各类网络安全创作需求
网络·安全·aigc·贴图·插画
txinyu的博客2 小时前
muduo http优化 —— 在原本数据监测http上 多支持了功能完善的http_1
网络·网络协议·http
华科大胡子2 小时前
Workstation避坑指南:网络总连不上?
运维·服务器·网络
特别关注外国供应商2 小时前
Netskope 安全与网络重塑人工智能
网络·人工智能·安全·零信任·访问控制·sase·netskope