尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

TLM2.0

TLM2.0
📅 发布时间:2026/6/18 13:32:58

在数字芯片验证(SystemVerilog UVM)中,TLM 2.0(Transaction-Level Modeling)的通用净核类(Generic Payload)和套接字(Socket)是实现高效组件通信的核心机制。TLM2.0将模块间事务的传递抽象出发起者、目标、套接字和桥,发起者通过发起者套接字向目标套接字发送消息,目标从目标套接字接收消息并处理。

1 通用净核类 (Generic Payload - tlm_generic_payload)

为了在不同模块间实现标准化通信,TLM2.0定义了一个通用的事务包 tlm_generic_payload,它几乎包含了总线事务所需的所有信息:

  • m_address:地址(64位)。
  • m_command:操作类型(读 TLM_READ_COMMAND、写TLM_WRITE_COMMAND 或忽略)。
  • m_data:数据阵列(byte 数组)。
  • m_length:传输的数据长度。
  • m_response_status:返回状态(是否成功、是否发生错误,如TLM_OK_RESPONSE)。
  • m_byte_enable:字节使能(用于部分写操作)。
    通用净核类 (Generic Payload)是 TLM 2.0 统一的数据语言。大家都用同一种格式的数据包,组件之间才能无缝对接。

2 套接字 (Sockets)

Socket 是TLM2.0最重要的概念之一,它是 TLM 2.0 统一的硬件接口。它在内部封装了 port、export 和 imp,极大地简化了模块间接口的连接,实现了“即插即用”。主要分为:

  • tlm_initiator_socket:由事务发起方(Initiator)使用。通常留在 Driver 或 Master 组件中,用来发起事务。
  • tlm_target_socket:由事务接收方(Target)使用。通常留在 Monitor、Scoreboard 或 Slave 模型中,用来接收并处理事务。
    每个socket又根据传输方式分为阻塞(b)和非阻塞(nb)类型。套接字将发送端口(Port) 和 接收端口(Export) 组合成了一个双向的通道。它既能发送请求(Request),又能同时接收回应(Response)。

3 核心接口:阻塞与非阻塞传输

阻塞传输 (Blocking Transport):通过 b_transport 函数实现。调用会阻塞发起方线程,直到目标方完成事务处理并返回。适合对时序要求不高的快速模型。
非阻塞传输 (Non-blocking Transport):通过 nb_transport_fw (前向) 和 nb_transport_bw (后向) 函数实现。将一次完整事务拆分为请求和响应多个阶段,通过返回值 tlm_sync_enum 和引用参数 phase 来同步状态。适合需要精细时序建模的场景。

非阻塞传输

nb_transport_fw (Forward, 前向):由发起端Initiator 调用,把消息传给目标端Target。
nb_transport_bw (Backward, 后向):由目标端Target 调用,把消息传回发起端Initiator。

举例:
一个 Master(Initiator) 和一个 Slave(Target)之间要传输一个 tlm_generic_payload(简称 trans)。在传输时需要用到两个辅助参数:

  • phase(阶段):类型为 tlm_phase,用来标记当前走到哪一步了。
  • delay(延迟):时序控制。

(1)Phase1:发送请求 (Master -> Slave)
Master 准备好了数据,把 phase 设置为 BEGIN_REQ(开始请求),然后调用 nb_transport_fw 发送。

// Master 内部代码tlm_phase phase=BEGIN_REQ;uvm_tlm_time delay=new("delay",0);// Master发送请求status=initiator_socket.nb_transport_fw(trans,phase,delay);

(2)Phase2:确认请求 (Slave -> Master)
Slave 收到请求后,发现是 BEGIN_REQ。Slave 把 phase 改为 END_REQ(结束请求),通过 nb_transport_bw 发回给 Master。

// Slave 内部代码(在 nb_transport_fw 的实现中,或者稍后通过另一个 thread)phase=END_REQ;// Slave 确认请求status=target_socket.nb_transport_bw(trans,phase,delay);

此时,Master 收到 END_REQ,知道 Slave 已经成功接单,Master 就可以去准备下一个数据或者等待了。

(3)Phase3:发送响应 (Slave -> Master)
Slave 内部的存储器真正完成了写操作(或者准备好了读数据)。它把 phase 改为 BEGIN_RESP(开始响应),再次通过 nb_transport_bw 发给 Master。

// Slave 内部代码trans.set_response_status(TLM_OK_RESPONSE);// 写入成功phase=BEGIN_RESP;// Slave 发送响应status=target_socket.nb_transport_bw(trans,phase,delay);

(4)Phase4:确认响应 (Master -> Slave)
Master 收到 BEGIN_RESP,检查 trans 的状态发现成功了。
Master 把 phase 改为 END_RESP(结束响应),通过 nb_transport_fw 传给 Slave,宣告这次传输彻底结束。

// Master 内部代码(在 nb_transport_bw 的实现中)if(phase==BEGIN_RESP)begin phase=END_RESP;// Master 确认响应status=initiator_socket.nb_transport_fw(trans,phase,delay);end

核心返回值:tlm_sync_enum
在写代码时,不管是调用 fw 还是 bw,都会收到一个返回值(上面代码中的 status)。这个返回值决定了是不是立刻返回结果:

TLM_ACCEPTED:

含义:消息收到了,对方需要花时间处理,晚点会异步调用另一个方向的函数把结果返回来。

对应现实:上面的例子中,如果大家动作都慢,每一步都返回 TLM_ACCEPTED,那就是标准的 4 次函数调用。

TLM_UPDATED:

含义:对方是个快手,在调用函数把请求发过去的同时,他在同一个函数返回时就把 phase 改了并把结果返回。

好处:可以把 4 阶段缩短为 3 阶段甚至 2 阶段,极大地减少函数调用次数,提高仿真速度。

TLM_COMPLETED:

含义:传输结束,不需要后续的任何握手了。

阻塞传输

b_transport:发起方调用后阻塞,直到事务完成。

对比

特性b_transport(阻塞)nb_transport_fw (非阻塞前向)
完整函数名‌void b_transport(…)tlm_sync_enum nb_transport_fw(…)
‌执行行为‌调用后‌阻塞‌,等待目标处理完毕返回调用后‌立即返回‌,事务异步进行
‌ 参数特征‌(payload, delay)(payload, phase, delay)
‌建模风格‌LT (Loosely Timed),适合快速架构探索AT (Approximately Timed),适合精确时序/流水线建模
配套反向接口‌无需配合 nb_transport_bw 实现双向通信

4 时间建模(Timing)

TLM2.0通过 sc_time 对象来携带时间信息。b_transport 函数中的 delay 参数按引用传递,允许目标方在返回前增加延时,从而模拟读写延迟或总线仲裁延迟

5 核心时间模式

TLM 2.0 主要有两种模式:

  1. LT 模式 (Loose-Timely,宽松时序模式)
    LT模式使用基于wait()的阻塞传送接口,当一个调用请求发出后,直到请求被处理完成后该调用才返回。LT模式支持“时间解耦”,用于平衡仿真速度与仿真精度。
    应用场景:只关心功能,不关心具体时钟周期(比如快速搭建的虚拟原型、软件算法模型)。
    工作原理:Initiator 通过 Socket 调用 b_transport(payload, delay)。这是一个阻塞(Blocking)方法。数据包(Payload)送过去后,由 Target 直接修改 Payload 中的数据或状态,函数返回后,Initiator 直接从同一个 Payload 里读取结果。

  2. AT 模式 (Approximately-Timely,近似时序模式)
    AT模式使用基于相位(phase)的非阻塞传送接口,当请求发出后,发送方只需获知接收方已经接收消息,接收方在处理完成事务后,主动通知发送方事务已完成。典型的相位变化如BEGIN_REQ -> END_REQ -> BEGIN_RESP -> END_RESP。
    应用场景:需要精确到时钟周期的总线仿真(比如 AXI 的 4 阶段握手)。
    工作原理:通过 Socket 调用 nb_transport_fw(前向)和 nb_transport_bw(后向)。这是一个非阻塞(Non-blocking)方法。数据包(Payload)在 Initiator 和 Target 之间像打乒乓球一样来回传送,每次传送代表一个状态(如开始地址、开始数据、结束等待等)。

在发起者socket与目标socket中,注册forward或者backward的接口需要根据实际需要确定。通常发起者socket与目标socket相连接,发起方会调用目标socket的transport_fw()方法实现向前传输,目标方会调用发起者socket的transport_bw()方法实现向后传输。

6 代码示例

下面以一个发起方(Initiator)向一个目标方(Target Memory)发起写并读回验证的完整流程为例。

6.1 阻塞传输

1、目标方 (Target) 实现
目标方需要实现 b_transport 方法,并注册到其socket上

// target.h#include<systemc>#include<tlm.h>#include<tlm_utils/simple_target_socket.h>classMemory:publicsc_core::sc_module{public:// 1. 定义目标方套接字,接收来自发起方的事务tlm_utils::simple_target_socket<Memory>socket;SC_CTOR(Memory):socket("socket"){// 2. 将 b_transport 方法注册到套接字上socket.register_b_transport(this,&Memory::b_transport);// 初始化内存数组for(inti=0;i<256;++i)mem[i]=0;}// 3. 实现核心的阻塞传输函数voidb_transport(tlm::tlm_generic_payload&trans,sc_core::sc_time&delay){// 获取事务详情tlm::tlm_command cmd=trans.get_command();sc_dt::uint64 addr=trans.get_address();unsignedchar*ptr=trans.get_data_ptr();unsignedintlen=trans.get_data_length();// 模拟延迟 (例如 10ns)delay+=sc_core::sc_time(10,sc_core::SC_NS);if(cmd==tlm::TLM_WRITE_COMMAND){std::cout<<sc_core::sc_time_stamp()<<" [Target] WRITE to addr "<<addr<<std::endl;// 执行写操作for(unsignedinti=0;i<len;++i){mem[addr+i]=ptr[i];}}elseif(cmd==tlm::TLM_READ_COMMAND){std::cout<<sc_core::sc_time_stamp()<<" [Target] READ from addr "<<addr<<std::endl;// 执行读操作for(unsignedinti=0;i<len;++i){ptr[i]=mem[addr+i];}}// 设置事务完成状态trans.set_response_status(tlm::TLM_OK_RESPONSE);}private:unsignedcharmem[256];// 模拟内存};

2、发起方 (Initiator) 实现
发起方包含一个线程,持续发起事务

// initiator.h#include<systemc>#include<tlm.h>#include<tlm_utils/simple_initiator_socket.h>structInitiator:sc_core::sc_module{// 1. 定义发起方套接字tlm_utils::simple_initiator_socket<Initiator>socket;SC_CTOR(Initiator){SC_THREAD(thread_process);}voidthread_process(){// 初始化一个通用事务包tlm::tlm_generic_payload trans;sc_core::sc_timedelay(sc_core::SC_ZERO_TIME);// --- 执行一次写事务 ---unsignedintwrite_data=0xDEADBEEF;trans.set_command(tlm::TLM_WRITE_COMMAND);trans.set_address(0x10);trans.set_data_ptr(reinterpret_cast<unsignedchar*>(&write_data));trans.set_data_length(4);std::cout<<sc_core::sc_time_stamp()<<" [Initiator] Sending WRITE transaction"<<std::endl;// 2. 调用 socket 的 b_transport,这将最终调用目标方的 b_transportsocket->b_transport(trans,delay);std::cout<<sc_core::sc_time_stamp()<<" [Initiator] WRITE completed, status = "<<trans.get_response_status()<<std::endl;// --- 执行一次读事务 ---unsignedintread_data=0;trans.set_command(tlm::TLM_READ_COMMAND);trans.set_address(0x10);trans.set_data_ptr(reinterpret_cast<unsignedchar*>(&read_data));trans.set_data_length(4);std::cout<<sc_core::sc_time_stamp()<<" [Initiator] Sending READ transaction"<<std::endl;socket->b_transport(trans,delay);std::cout<<sc_core::sc_time_stamp()<<" [Initiator] READ completed, data = 0x"<<std::hex<<read_data<<std::endl;}};

3、顶层连接 (Top-Level)
在顶层模块中将两个socket绑定在一起

// main.cpp#include<systemc>#include"initiator.h"#include"target.h"intsc_main(intargc,char*argv[]){Initiatorinitiator("initiator");Memorymemory("memory");// 将发起方套接字绑定到目标方套接字initiator.socket.bind(memory.socket);sc_core::sc_start();return0;}

进阶:引入时间标记
如果希望精确控制延迟,目标方可以修改传入的 delay 引用,而不是直接使用 # 等待。在目标方 b_transport 中添加如下代码:

// 模拟不同地址的访问延迟if(addr==0x00){delay+=sc_core::sc_time(20,sc_core::SC_NS);// 特殊地址慢一些}else{delay+=sc_core::sc_time(5,sc_core::SC_NS);}

6.2 非阻塞传输

1、目标方(Target)实现 —— 接受请求,延迟响应
Target 需要实现 nb_transport_fw(前向接口),并拥有一个内部线程来处理延迟响应。

// target_nb.h#include<systemc>#include<tlm.h>#include<tlm_utils/simple_target_socket.h>classTargetNB:publicsc_core::sc_module{public:// 目标方套接字tlm_utils::simple_target_socket<TargetNB>socket;SC_CTOR(TargetNB):socket("socket"),pending_trans(nullptr){// 注册前向非阻塞传输函数socket.register_nb_transport_fw(this,&TargetNB::nb_transport_fw);// 启动响应处理线程SC_THREAD(response_thread);sensitive<<resp_event;dont_initialize();}// 核心函数:接收来自 Initiator 的请求(前向路径)tlm::tlm_sync_enumnb_transport_fw(tlm::tlm_generic_payload&trans,tlm::tlm_phase&phase,sc_core::sc_time&delay){// 只处理请求开始阶段if(phase==tlm::BEGIN_REQ){std::cout<<sc_core::sc_time_stamp()<<" [Target] Received BEGIN_REQ, addr=0x"<<std::hex<<trans.get_address()<<", delay="<<delay.to_string()<<std::endl;// 保存事务指针,以便在响应线程中处理pending_trans=&trans;// 模拟总线延迟:假设需要 50ns 才能准备好数据// 注意:这里不阻塞当前调用,而是通知线程在 50ns 后触发resp_event.notify(50,sc_core::SC_NS);// 返回 TLM_ACCEPTED 表示:我收下了请求,但不会立即完成,// 发起方可以去做其他事情,不用等我。returntlm::TLM_ACCEPTED;}// 如果收到 END_RESP(来自发起方的确认),可以忽略或做清理returntlm::TLM_COMPLETED;}// 内部线程:延迟后通过后向路径发送响应voidresponse_thread(){while(true){// 等待事件触发(50ns 延时到达)wait(resp_event);if(pending_trans){std::cout<<sc_core::sc_time_stamp()<<" [Target] Processing response (DELAY expired)"<<std::endl;// 执行实际的读/写操作if(pending_trans->get_command()==tlm::TLM_WRITE_COMMAND){unsignedint*data_ptr=(unsignedint*)pending_trans->get_data_ptr();mem[pending_trans->get_address()/4]=*data_ptr;std::cout<<" [Target] WRITE completed"<<std::endl;}else{// TLM_READ_COMMANDunsignedintval=mem[pending_trans->get_address()/4];memcpy(pending_trans->get_data_ptr(),&val,4);std::cout<<" [Target] READ value = 0x"<<std::hex<<val<<std::endl;}pending_trans->set_response_status(tlm::TLM_OK_RESPONSE);// ----- 关键步骤:发起后向传输(Backward Path)-----tlm::tlm_phase phase=tlm::BEGIN_RESP;sc_core::sc_time delay=sc_core::SC_ZERO_TIME;// 此处不再额外延时// 通过套接字调用 Initiator 实现的 nb_transport_bw// 这会立即触发 Initiator 的接收函数tlm::tlm_sync_enum status=socket->nb_transport_bw(*pending_trans,phase,delay);// 如果 Initiator 返回 TLM_UPDATED,意味着它把 phase 改为了 END_RESP// 表示对方已收下响应,本目标可以释放资源了if(status==tlm::TLM_UPDATED){std::cout<<sc_core::sc_time_stamp()<<" [Target] Initiator confirmed END_RESP, transaction done."<<std::endl;}pending_trans=nullptr;}}}private:unsignedintmem[256];// 模拟内存tlm::tlm_generic_payload*pending_trans;// 当前待处理的事务sc_core::sc_event resp_event;// 触发响应的事件};

2、发起方(Initiator)实现 —— 发送请求,接收异步响应
Initiator 需要实现 nb_transport_bw(后向接口),并在内部线程中发起请求。

// initiator_nb.h#include<systemc>#include<tlm.h>#include<tlm_utils/simple_initiator_socket.h>classInitiatorNB:publicsc_core::sc_module{public:// 发起方套接字tlm_utils::simple_initiator_socket<InitiatorNB>socket;SC_CTOR(InitiatorNB):socket("socket"),response_received(false){// 注册后向非阻塞传输函数(接收 Target 发来的响应)socket.register_nb_transport_bw(this,&InitiatorNB::nb_transport_bw);SC_THREAD(run_thread);}// 核心函数:接收来自 Target 的响应(后向路径)tlm::tlm_sync_enumnb_transport_bw(tlm::tlm_generic_payload&trans,tlm::tlm_phase&phase,sc_core::sc_time&delay){if(phase==tlm::BEGIN_RESP){std::cout<<sc_core::sc_time_stamp()<<" [Initiator] Received BEGIN_RESP from Target!"<<std::endl;// 读取返回的数据(如果是读操作)if(trans.get_command()==tlm::TLM_READ_COMMAND){unsignedintval;memcpy(&val,trans.get_data_ptr(),4);read_result=val;std::cout<<" [Initiator] Data received = 0x"<<std::hex<<val<<std::endl;}// 告诉 Target:我已经收下响应,事务可以彻底结束phase=tlm::END_RESP;response_received=true;done_event.notify(sc_core::SC_ZERO_TIME);// 通知主线程任务完成returntlm::TLM_UPDATED;// 返回 UPDATED,告知 Target 阶段已变}returntlm::TLM_COMPLETED;}// 主线程:发起请求voidrun_thread(){// 等待仿真启动稳定wait(sc_core::SC_ZERO_TIME);// ----- 发起一次读请求 -----tlm::tlm_generic_payload trans;unsignedintread_data=0;trans.set_command(tlm::TLM_READ_COMMAND);trans.set_address(0x100);trans.set_data_ptr((unsignedchar*)&read_data);trans.set_data_length(4);trans.set_response_status(tlm::TLM_INCOMPLETE_RESPONSE);tlm::tlm_phase phase=tlm::BEGIN_REQ;sc_core::sc_time delay=sc_core::SC_ZERO_TIME;std::cout<<sc_core::sc_time_stamp()<<" [Initiator] Sending READ BEGIN_REQ (Non-blocking)"<<std::endl;// 调用 Target 的 nb_transport_fwtlm::tlm_sync_enum status=socket->nb_transport_fw(trans,phase,delay);if(status==tlm::TLM_ACCEPTED){// 对方接受了请求,但尚未完成。我们阻塞主线程等待 done_eventstd::cout<<sc_core::sc_time_stamp()<<" [Initiator] Request accepted, waiting for async response..."<<std::endl;wait(done_event);// 主线程挂起,等待后向路径触发}// 到这里,异步响应已完成std::cout<<sc_core::sc_time_stamp()<<" [Initiator] Transaction fully completed. Final data = 0x"<<std::hex<<read_result<<std::endl;sc_core::sc_stop();}private:boolresponse_received;unsignedintread_result;sc_core::sc_event done_event;};

3、顶层连接(Top-Level)

// main.cpp#include"initiator_nb.h"#include"target_nb.h"intsc_main(intargc,char*argv[]){InitiatorNBinitiator("initiator");TargetNBmemory("memory");// 绑定套接字initiator.socket.bind(memory.socket);sc_core::sc_start();return0;}

相关新闻

  • 外贸快车怎么样?实力测评解析 - 栗子测评
  • Motorola Suite56 ADS调试器:OnCE与MFAX技术深度解析与实战指南
  • 5分钟搞定Windows和Office激活:KMS智能脚本终极指南

最新新闻

  • 3大突破性策略:让Perfetto性能分析从被动监控到主动优化的跨越式升级
  • 2026成都麒麟珠宝 Qeelin 葫芦回收:国风奢饰二手流通现状,出手渠道推荐 - 逸程
  • Windows虚拟显示器驱动终极指南:5分钟免费扩展你的桌面空间
  • 成都本地黄金回收怎么避坑?2026收的顶合规回收经验分享 - 奢侈品回收评测
  • 产绝版钻石回收会涨价?聊聊2026成都二手市场稀缺款溢价真相 - 逸程
  • 命令行中的参数和引号

日新闻

  • 2026年不锈钢卷板厂家推荐排行榜:冷轧热轧/304/201不锈钢卷板,高颜值耐腐蚀源头厂家实力精选 - 企业推荐官【官方】
  • FLUX.1-dev FP8模型实战指南:24GB以下显卡高效部署方案
  • 2026佛山长途搬家价目表:跨省跨市搬家费用完整计算指南 - 从来都是英雄出少年

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号