news 2026/9/29 1:58:54

Synopsys AXI VIP Port Monitor接入Scoreboard:TLM连接与实战要点

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Synopsys AXI VIP Port Monitor接入Scoreboard:TLM连接与实战要点

第一次把 Synopsys AXI VIP 接进自研 testbench 的兄弟,基本都会卡在同一个地方:VIP 明明跑得很欢,可我需要的事务对象到底怎么喂给 Scoreboard?有人去抓 interface 上的信号,一拍一拍地拼 AXI 事务;有人退回回调函数,费劲从 VIP 内部导数据;还有人在svt_axi_*一堆类里翻半天,最后干脆在 driver 里自己打印一份“假数据”去比对。其实 Synopsys AXI VIP 早就把这条数据通路准备好了——Port Monitor。它会把你关心的 AXI 事务对象通过 TLM 端口发出来,你要做的只是把它和 Scoreboard 里的 analysis fifo 连起来,本质上就是一行connect()。这篇文章就以 Synopsys AXI VIP 为例,围绕 Port Monitor 的定位、配置、TLM 连接和 Scoreboard 侧处理,完整跑一遍;顺手把两个高频问题也聊透:怎么关掉铺天盖地的 transaction 打印,以及uvm_tlm_fifo和uvm_tlm_analysis_fifo到底怎么选。

1. 先搞明白:AXI VIP里到底有几个Monitor,各自盯什么

1.1 system monitor 和 port monitor 的职责分工

很多人第一次看 Synopsys AXI VIP 会晕,因为这里面的 monitor 不是一个,而是两个:一个叫 system monitor,一个叫 port monitor。这个命名不是随便起的,背后是两类完全不同的职责。

system monitor,全名大概是svt_axi_system_monitor。它干的是协议合规检查的活,盯着 AXI 总线上每一拍信号是否符合 AMBA AXI 协议规范。比如 AW 和 W 通道的乱序关系、burst 长度和实际传输的 beat 数是否一致、DATA 总线上 WSTRB 有没有越界、READY/VALID 握手有没有违例。发现违规之后,它通过 UVM report 机制向外报警,打印 error 或者 warning,但不会也没有义务把这些信号整理成一个完整的事务对象丢给你。

port monitor,对应的是svt_axi_port_monitor。它干的就是采样和对象化:把 AXI 的五个通道(AW/W/B/AR/R)上的握手时序、地址、数据、响应等全部捕获下来,组合成一个完整的svt_axi_transaction,然后从这个 monitor 的 TLM 端口推出去。举个例子,一个 AXI 写事务,raw signal 是分散在 AW(写地址)、W(写数据)、B(写响应)三个通道上的,port monitor 会把它们按协议规则合并成一次完整的 burst 事务,addr、burst_len、data、resp都在里面。

如果还要打个比方:system monitor 是交警,只负责看你有没有违章;port monitor 是行车记录仪,只负责把整条行驶路线录下来导出视频。两者都重要,但给 Scoreboard 提供食材的,是 port monitor。

1.2 为什么Scoreboard要的是Port Monitor的数据

Scoreboard 的职责是对比:把 DUT 的实际行为和一个期望结果做比较,从而判断设计对不对。这个“实际行为”必须来自一个可靠、客观、覆盖面完整的观测点。port monitor 恰好就是这样的观测点——它贴在 AXI 接口上,能看到 master 发出的写数据、从接口返回的读数据,以及所有响应信号。

如果不用 port monitor 的数据,常见的替代方案都有问题。比如直接从 driver 的回调里拿事务,那拿到的其实是“你自己想发出去的数据”,只能验证发送端有没有把预期事务发出去,没法验证 DUT 是不是按协议把数据收对、回对。又比如自己抓 interface 信号重组事务,工作量巨大且容易漏掉一些边界情况(outstanding、乱序返回、窄带传输等等),跟 port monitor 一比完全没必要。

还有一个容易忽略的好处:port monitor 输出的svt_axi_transaction,里面字段类型和枚举都是 AXI 语义化的。你在 Scoreboard 里可以直接按req_type、burst、addr、data这样的字段名来写比对逻辑,而不是对着一个bit [31:0] data_signal去猜含义。这也是 Synopsys VIP 作为商业级验证 IP 的价值所在——事务模型已经把协议层次包装干净了。

所以,Scoreboard 要接的数据源,就是 port monitor。

2. 动手之前:把Port Monitor通过配置打开

2.1 关键配置项 has_port_monitor

Synopsys AXI VIP 的 port monitor 不是默认就有的,它跟 agent 的创建是一套配置配合的。最核心的一个开关,是svt_axi_agent_configuration里的has_port_monitor字段。这个字段通常是一个 bit,置 1,agent 在 build 阶段才会创建 port monitor 组件;如果你不管它,好几个版本默认是 0。

下面这段是典型的配置代码,我一般写在 env 的 build_phase 里:

function void build_phase(uvm_phase phase); super.build_phase(phase); svt_axi_agent_configuration axi_cfg = new("axi_cfg"); axi_cfg.has_port_monitor = 1; axi_cfg.has_system_monitor = 1; axi_agent = new("axi_agent", this); axi_agent.set_config(axi_cfg); scoreboard = axi_scoreboard::type_id::create("scoreboard", this); endfunction

这里有几个点要说清楚。

第一,has_system_monitor如果环境里没有特别原因,建议保留为 1。协议检查器虽然打印多,但它能帮你快速发现 DUT 协议层面的违例。不要为了让日志干净就顺手关掉,后面关打印有更精准的办法。

第二,set_config只是其中一种给 agent 传配置的方式。如果你在项目里已经封装了 agent,或者你们习惯用svt_config_db或者uvm_config_db把配置下发到 agent 内部,那核心只记住一件事:agent 在 build 阶段必须能拿到这份has_port_monitor=1的配置对象,否则port_monitor永远不会创建。至于是 set 还是 svt_config_db,项目统一就好。

第三,有的版本里,svt_axi_agent_configuration下还会带一个port_monitor_configuration对象,里面又有一些细粒度的控制,比如has_user_ext_cb。如果你完全走 TLM 方式拿事务,has_user_ext_cb可以保持默认不用管。

2.2 启动后自查:确认port_monitor不是空句柄

配置做完,不要急着往下连,先加一个自查代码。空句柄是这类接线最容易出现的问题,而且错误往往不在 connect 那行,而在更早的 build 阶段。

我习惯在 connect_phase 正式开始之前,对 agent 内部的 port monitor 做一次空指针检查:

function void end_of_elaboration_phase(uvm_phase phase); if (axi_agent.port_monitor == null) `uvm_error("CFG", "port_monitor is NULL, check has_port_monitor config!") else `uvm_info("CFG", $sformatf("port_monitor created: %s", axi_agent.port_monitor.get_full_name()), UVM_LOW) endfunction

看到打印出现一个路径类似uvm_test_top.env.axi_agent.port_monitor的东西,就说明这一步通了。如果这里报 null,优先检查三件事:配置字段有没有设置成功;set_config是不是在 agent 的 build 之前调用;有没有上层代码在某个地方把配置覆盖回了 0。

还有一个容易踩的细节:在 agent 里暴露的成员名,不同 VIP 版本可能叫port_monitor,也可能叫port_monitor_handle。如果你在源码里发现 agent 里实际成员名不是port_monitor,换成源码里的名字即可。

3. 核心一步:让Port Monitor把事务推给Scoreboard

3.1 真正的TLM连接就一行

port monitor 创建好之后,一切就变得简单了。Synopsys AXI VIP 的svt_axi_port_monitor里,有一个标准 TLM 端口,长这样:

uvm_analysis_port #(svt_axi_transaction) item_observed_port;

item_observed_port这个名字很直白:观测到 item 之后的出口,也就是观察到的svt_axi_transaction从哪个口出去。它是个uvm_analysis_port,意味着 port monitor 每观测到一次完整的 AXI 事务,都会在这里调用一次write(),把这个事务广播给所有挂在这个口上的下游组件。

我们要做的,就是在 env 的 connect_phase 里,把这个口连到 Scoreboard 的 analysis fifo 上:

function void connect_phase(uvm_phase phase); axi_agent.port_monitor.item_observed_port.connect( scoreboard.axi_txn_fifo.analysis_export ); endfunction

这样就完事了。真的,核心连接就是这么一行。之后每当 AXI 总线上跑完一次 transaction,port monitor 就会把它推进scoreboard.axi_txn_fifo,你的 Scoreboard 再从这个 fifo 里取数据慢慢比对。

为什么这里用analysis_port而不是put_port或者get_port?关键在于 AXI 总线事务频率很高,而且 port monitor 是“旁路观察”的角色,它不能也不应该因为下游处理慢就卡住总线。analysis 端口走的是write(),非阻塞、广播式、一对多,非常适合这种数据流。

3.2 连接不上的两条排查思路

如果你在 connect 阶段遇到了问题,最常见的无非两种情况。

第一种,找不到item_observed_port这个成员。不同版本的 Synopsys VIP 对内部字段命名有差异,有些版本可能叫item_ap,有些版本可能叫txn_ap。不要死记名字,直接打开 VIP 安装目录下的svt_axi_port_monitor.sv,在里面搜uvm_analysis_port,看到哪个成员的名字就连接哪个。我遇到过好几个项目,改版之后端口名字换掉了,源码里一搜就清楚。

第二种,connect 时类型不匹配。uvm_analysis_port #(svt_axi_transaction)的连接目标必须是uvm_analysis_export #(svt_axi_transaction),两边括号里的 transaction 类型要完全一致。如果你在 Scoreboard 里定义的 fifo 是uvm_tlm_analysis_fifo #(uvm_sequence_item)或者别的什么类型,connect 会直接编译报错。遇到这种错误,不要怀疑语法,去把两边的类型参数对齐。

万一中间还想加转发层,比如你想在 env 里做一层 TLM 中转,把 port monitor 的数据重新广播给 scoreboard 和 coverage collector,那就可以在 env 里声明一个自己的uvm_analysis_port #(svt_axi_transaction) axi_middle_ap,然后把item_observed_portconnect 到它上面,再把它分别 connect 给下游。这属于进阶玩法,但原理也是同一套 analysis 连接。

4. Scoreboard侧:从Analysis FIFO取出事务并对齐

4.1 最基础的Scoreboard骨架

数据链路通了,接下来要保证 Scoreboard 这边能接得住、接得对。下面是一个最基础的 Scoreboard 骨架:

class axi_scoreboard extends uvm_scoreboard; `uvm_component_utils(axi_scoreboard) uvm_tlm_analysis_fifo #(svt_axi_transaction) axi_txn_fifo; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); axi_txn_fifo = new("axi_txn_fifo", this); endfunction task run_phase(uvm_phase phase); svt_axi_transaction txn; forever begin axi_txn_fifo.get(txn); do_compare(txn); end endtask virtual task do_compare(svt_axi_transaction txn); // 你的比对逻辑 endtask endclass

有几个细节值得注意。axi_txn_fifo必须在 build_phase 里创建出来,否则外面连接的时候analysis_export是空的,仿真跑起来直接挂在 connect 上。get()是阻塞的,没有数据时 task 会一直等,所以你放在forever循环里是安全的,不存在忙等空转的问题。

如果你希望 Scoreboard 的 run_phase 不阻塞、能做更多事情,也可以改用try_get()轮询,但这种写法容易带来时序判断上的复杂度,我个人建议还是顺着 fifo 的阻塞get()走,职责单一,行为也清晰。

4.2 拿到transaction后怎么比对才靠谱

现在重点来了:拿到svt_axi_transaction之后,怎么比对才是靠谱的。

首先要明确一点——port monitor 给出来的 transaction 是整笔 burst,不是单拍。AXI 事务模型里,一次 burst 可以包含多个 beat,svt_axi_transaction内部通常用队列保存这些 beat 的数据。所以你在 Scoreboard 里写逻辑时,眼睛不要只盯着某一个信号,要先看这次事务的burst_len,决定数据队列里到底该有多少拍。

举个例子,一个写事务,你期望的数据应该是从 reference model 或某个期望队列里来的;实际数据则来自 port monitor 捕获到的写事务。比对的时候可以按 beat 逐一比对:

virtual task do_compare(svt_axi_transaction txn); string tag; if (txn.req_type == svt_axi_pkg::WRITE) begin // 枚举名以VIP版本为准 tag = "WR"; // 把期望数据从 reference queue 中弹出,这里只做示意 foreach (txn.data[i]) begin // 数据字段名以 svt_axi_transaction 为准 if (txn.data[i] !== expected_q[i]) begin `uvm_error(get_full_name(), $sformatf("%s DATA MISMATCH beat %0d, exp=%h act=%h", tag, i, expected_q[i], txn.data[i])) end end end else begin tag = "RD"; // 读事务同理,比较返回的读数据 end endtask

这里还要特别注意写方向与读方向的处理。写事务里,port monitor 看到的是 master 往 DUT 写入的数据;读事务里,它看到的是 DUT 返回给 master 的读数据。这两类数据来源不同,期望数据也不一样,不要用一个逻辑生搬硬套。

还有一个小建议:刚开始调试链路时,别急着把比对逻辑写复杂。先把txn原样打出来,确认数据确实到了 Scoreboard,字段也确实是我们期望的 AXI 语义,再逐步加断言和比对。我在项目里见过太多人一次写了三层嵌套加状态机比对,结果 fifo 里面压根没数据进来,查了半天才发现是has_port_monitor没开。先跑通,再优化。

5. 顺手干掉烦人的Transaction打印:3种有效手段

5.1 从仿真命令行控制verbosity

接完线,第一件事就是跑仿真。然后你会发现一个现象:日志里一堆svt_axi_transaction的打印,几乎把关键信息全淹没了。这是 Synopsys AXI VIP 的“默认热情”,transaction 对象在 monitor 发布时会被当成 UVM_INFO 打出来。

最快、最不影响代码的清理方式是命令行控制 verbosity。UVM 1.2 之后支持+uvm_set_verbosity,可以在不修改 RTL/testbench 的情况下,把指定组件的打印级别压下去。比如只关掉 port monitor 的打印:

+uvm_set_verbosity="*axi_agent.port_monitor*,_ALL_,UVM_NONE,run"

_ALL_表示不区分消息 ID,UVM_NONE表示该组件内所有UVM_INFO都不显示,run表示在 run phase 阶段生效。如果通配符在你跑仿真时失效,就直接写完整路径,比如uvm_test_top.env.axi_agent.port_monitor。

这个方式的好处是:关打印的时候只动命令行,代码和 VIP 配置都不用改。适合快速确认波形、定位问题时临时把日志关干净。

5.2 从VIP配置类控制打印

命令行适合临时关,但如果你想在代码层面、让整个仿真环境统一的日志策略更干净,建议从 VIP 配置类下手。

Synopsys VIP 一般在svt_global_configuration或者对应的svt_axi_configuration里提供一个日志级别控制字段,常见的名字是log_verbosity或者verbosity。可以在环境初始阶段设置:

svt_global_configuration global_cfg; global_cfg = svt_global_configuration::get(); global_cfg.log_verbosity = UVM_LOW;

不过这里必须提醒一句:不同版本的 VIP,这个字段名字可能不同,有的叫log_verbosity,有的就叫print_transactions,甚至有的版本通过静态方法控制字段显示。最靠谱的办法是打开你安装的svt_global_configuration.sv或者svt_axi_configuration.sv,用搜索框搜verbosity、print、display这几个关键词,找到对应字段再下手。版本升级后也要重新确认一次。

5.3 全局降低verbosity的代价

很多人到最后会烦了,直接在 testbench 里来一句粗暴的set_report_verbosity_level_hier(UVM_NONE),想一刀切。这个我不推荐。

原因很简单:set_report_verbosity_level_hier是作用在整个组件子树上的。如果你对uvm_test_top调,那你自己在 scoreboard、reference model 里打的UVM_MEDIUM、UVM_HIGH信息也全没了,以后环境出问题,连基本调试日志都看不到。

更精准的做法是在start_of_simulation_phase里只对 agent 子树降 verbosity:

function void start_of_simulation_phase(uvm_phase phase); axi_agent.set_report_verbosity_level_hier(UVM_LOW); endfunction

这样 VIP 内部的事务打印被压下去,你自己写的 scoreboard 打印还能留着。注意这里降到UVM_LOW而不是UVM_NONE,因为UVM_LOW已经能过滤掉绝大部分 VIP 的默认事务打印,同时还能保留一些重要消息;UVM_NONE容易把 error 之外的所有信息都干掉,后期排错会很难受。如果你确实只想关 port monitor 一个组件,也可以把这个调用换成axi_agent.port_monitor.set_report_verbosity_level(UVM_LOW)。

6. 顺带聊清楚:uvm_tlm_fifo和uvm_tlm_analysis_fifo到底选哪个

6.1 两张FIFO的接口语义区别

很多人在写 Scoreboard 时纠结过:连接 monitor 的 data,到底用uvm_tlm_fifo还是uvm_tlm_analysis_fifo?这里其实不是一个“谁更好”的问题,而是两个 fifo 的握手语义从根本上就不同。

uvm_tlm_fifo对外提供的是 put/get 接口。producer 通过put()往里写,如果 fifo 满,put()会阻塞等待;consumer 通过get()取,如果 fifo 空,也会阻塞等待。这是一种“点对点、带背压”的生产消费模型。你可以把它理解成两个人之间的一根水管:上游灌水,下游放水,水满了就等。

uvm_tlm_analysis_fifo对外提供的接口是analysis_export,producer 只需要调用write(),它永远非阻塞、立即返回。至于有多少消费者在接、消费速度多快,producer 一概不管。这是 analysis 语义:广播、观察、旁路。它更像是广场上的大喇叭,广播一响,谁听到谁记,广播员不等任何人。

为了更直观,简单列个表:

对比维度uvm_tlm_fifouvm_tlm_analysis_fifo
对外接口语义put/get 模型analysis 模型(write)
producer 入口put()/try_put()write()
consumer 出口get()/try_get()get()/try_get()(由内部 tlm_fifo 继承而来)
阻塞行为put 在有界且满时可阻塞write 不阻塞
典型场景点对点数据流、需要流量控制monitor 广播、Scoreboard 采样、coverage 收集

还有一个底层细节:uvm_analysis_fifo本质上继承自uvm_tlm_fifo,只是把对外暴露的端口换成了 analysis 相关的接口,底层存储机制是一样的。所以“analysis fifo 比 tlm fifo 慢”这种说法并不成立,性能差异主要在接口语义,不在存储本身。

6.2 为什么Port Monitor场景默认选Analysis FIFO

回到 AXI Port Monitor 这个具体场景:port monitor 的出口是uvm_analysis_port,它的连接对象必须是uvm_analysis_export。uvm_tlm_analysis_fifo正好对外提供了analysis_export,所以它天生就是为 monitor 的 analysis_port 准备的。

反过来,如果非要用uvm_tlm_fifo去接item_observed_port,两者接口类型不匹配,连都连不上。除非你中间再加一个适配层,把write()转成put(),这种操作完全没必要。

那什么时候可能优先考虑uvm_tlm_fifo?比如你的 producer 是一个主动发起数据的 generator、并且下游处理不过来时希望它阻塞等待,这是典型的 put/get 场景。而 monitor 是旁路观察者,它不应该因为 Scoreboard 处理慢就反过来阻塞总线协议,所以 analysis 语义天然更合适。

有人担心 analysis fifo 无限增长:monitor 一直write(),Scoreboard 来不及get(),内存膨胀怎么办。这个担心合理,但通常事务数据在验证环境中被消费速度是足够的,而且如果真出现长期堆积,说明 Scoreboard 里可能存在死等或死循环,这是功能问题,不是 fifo 选型能解决的。真要做流量控制,也可以在 Scoreboard 里用try_get()加超时机制来监控队列长度,而不是换一个 put 模型来卡 monitor 的出口。

7. 实测最容易踩的坑:版本差异、空句柄和类型不匹配

7.1 空句柄:9成新手倒在connect之前

我在前面已经反复强调过自查port_monitor是否为空,这里还是要再补一刀,因为在真实项目里,这个问题的排查时间往往比想象中长。

一种更隐蔽的情况是:你在 env 里定义了axi_agent,但 agent 内部有自己的一套 build 流程,它会先读配置,如果has_port_monitor=0,它根本不会创建port_monitor成员。表面上axi_agent.port_monitor可以访问,实际上是个 null。如果直接去 connect 它下面的item_observed_port,仿真会在connect_phase直接报 null pointer。这个时候去查has_port_monitor才是正路。

还有一种情况:agent 创建了 port monitor,但你的 Scoreboard 里axi_txn_fifo还没 new。connect 的时候analysis_export是 null,同样报空。所以建议把前面那段end_of_elaboration_phase的检查代码加进去,在整个编译链路上把两个 null 风险一次性排掉。

7.2 类型参数不一致:编译都不让你过

TLM connect 是强类型的。item_observed_port的类型是uvm_analysis_port #(svt_axi_transaction),所以它只能 connect 到uvm_analysis_export #(svt_axi_transaction)。如果你在 Scoreboard 里手滑写成了:

uvm_tlm_analysis_fifo #(uvm_sequence_item) axi_txn_fifo;

编译阶段就会报类型不匹配,这种错误通常很好发现。但有一种情况比较隐蔽:你的环境里同时 import 了多个 VIP package,某些版本下svt_axi_transaction有两个类名非常相近的版本,比如一个是标准版、一个是带扩展的svt_axi_extension或者带缓存的扩展事务,如果把 fifo 定义成了扩展类型,而item_observed_port里发出来的是基类型,connect 在编译时不一定会立刻报错(因为存在继承关系),但运行时get出来 cast 会失败,或者数据根本对不上。遇到这种情况,直接确认两边的 transaction 参数是不是同一个类。

7.3 回调方式误用和版本差异

除了 TLM 直连,Synopsys AXI VIP 也支持用户通过扩展回调类来获取事务。有的团队习惯用回调,比如:

class my_axi_port_monitor_cb extends svt_axi_port_monitor_callbacks; virtual task post_transmit(svt_axi_transaction txn); // 把 txn 送到 scoreboard endtask endclass

然后把这个回调注册给 port monitor。这个方案也能跑通,但坑在于“你以为注册了,其实没注册”。很多新手把回调类写好了,忘了在port_monitor_configuration里把has_user_ext_cb打开,或者忘了把回调对象加到 callback 队列里,最后代码一行没报错,但回调方法从头到尾没被调用。

用 TLM 直连就没有这个问题——连接代码摆在那里,连不连一眼就能看出来。所以我个人的建议是:能走item_observed_port就优先走 TLM 直连,回调只作为补丁手段。如果某些老版本 VIP 没有开放item_observed_port,再去看回调方式的官方 demo 是怎么注册的,照着抄。

版本差异这块再强调一次:不同 Release 的 Synopsys AXI VIP,内部成员名、配置字段名、甚至创建流程都可能微调。遇到问题时,第一反应应该是去安装目录下翻 VIP 源码,而不是死记网上某个教程的写法。比如svt_axi_port_monitor.sv里搜uvm_analysis_port,svt_axi_configuration.sv里搜has_port_monitor,svt_global_configuration.sv里搜log_verbosity,这三个搜索点基本能解决 80% 的迷路。

最后再分享一个我个人的习惯:我会把 port monitor 到 scoreboard 的这一段 TLM 连接固化在 base_env 里,模式固定为“port_monitor.item_observed_port → scoreboard.axi_txn_fifo.analysis_export”,后续子环境直接继承。这样一来,新搭的验证环境天然就有事务采集通路,不需要每个测试平台重新接线,也少了很多“为什么我的 scoreboard 拿不到数据”的深夜排查。跑通之后,再根据项目需要去加断言、加覆盖率收集,或者扩展成多通道对比,都不会再动到这条主干。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 1:58:31

群晖无法正确安装此套件?签名、套件源与SSH日志排查指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 1:58:23

Agent智能体开发实战指南:从ReAct原理到LangGraph框架选型

简介:《2025智能体Agent实用指南》系统讲解了构建智能体的最佳实践,适合具备一定编程基础、对AI与自动化感兴趣的产品经理、工程师和技术团队成员。文档从智能体的基本概念出发,阐释其与传统软件的区别,并针对复杂决策、规则维护困…

作者头像 李华
网站建设 2026/9/29 1:57:58

Log4j.xml与log4j2.xml配置实战:加载、滚动、继承与排错

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 1:56:53

MoE论文合集整理指南:算法、系统与应用三条主线

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 1:56:36

PCIe电学规范第8章拆解:从链路预算到信号完整性实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华