Verilog硬件描述语言入门:从编程思维到硬件电路设计
1. 从“连线”到“描述”为什么Verilog不是编程语言如果你是从单片机或者软件编程转过来的第一次接触Verilog最大的误区可能就是把它当成C语言或者Python来学。我见过不少新手一上来就琢磨“这个for循环怎么写”、“这个函数怎么调用”结果代码一综合要么面积爆炸要么时序完全不对甚至根本生成不了电路。这背后的根本原因是思维模式的差异软件是顺序执行的指令流而硬件是并行发生的物理连接。Verilog的全称是Verilog HDLHDL是Hardware Description Language硬件描述语言。这个“描述”二字是精髓。你不是在“写程序”告诉CPU一步一步做什么你是在“画图纸”用文本的方式告诉综合器比如Vivado、Quartus“我这里要一个与门它的两个输入分别来自A和B输出接到C旁边还要一个寄存器每个时钟上升沿把D的数据存进去”。综合器读你的“图纸”把它翻译成目标FPGA芯片里实际存在的查找表LUT、触发器FF、布线资源等最终生成一个电路网表。举个例子软件里你写c a b;CPU会在一个特定的时钟周期从内存取a和b送到加法器算出结果再写回c的地址。但在Verilog里你写assign c a b;你描述的是一个加法器电路。只要a或b变化c几乎同时经过一个很小的门延迟就会变化这是一个持续不断的物理过程没有“执行”的概念。所以学习Verilog语法第一步是建立“硬件思维”你写的每一行代码最终都会对应芯片上的一块硅片区域和金属连线。代码的简洁、清晰、可综合比软件的“奇技淫巧”重要得多。接下来我们就从最基础的构建单元开始拆解这张“电路图纸”该怎么画。2. 构建硬件世界的“原子”数据类型与运算符任何电路都在处理信号信号就有类型和值。Verilog的数据类型体系直接映射了硬件信号的特质理解它们是避免后期诡异错误的基础。2.1 线网与变量信号的两大载体这是Verilog中最核心、也最容易混淆的一对概念。线网Net最常用的就是wire。它代表的是电路单元之间的物理连接线。想象一下PCB板上的铜线它本身不存储信息只是传递信息。因此驱动wire必须被持续驱动。驱动源可以是模块的输出端口、一个assign连续赋值语句或者一个门实例的输出。如果一根wire没有被任何东西驱动它的值就是高阻态z。赋值使用assign语句进行赋值代表一种永久的连接关系。用途主要用于模块间的连接或者组合逻辑中信号的传递。wire a, b, sum; // 声明三根连线 assign sum a b; // 描述一个与门a和b是输入线sum是输出线三者被永久连接变量Variable最常用的是reg。这个名字极具误导性它不一定对应硬件寄存器它代表一个数据存储单元。在Verilog的抽象层次reg是一种可以在always和initial块中被赋值的变量。行为reg保存的是最后一次被赋予的值。赋值必须在always或initial过程块中使用过程赋值语句或赋值。硬件对应reg最终综合成什么取决于它被如何使用。在时序逻辑的always (posedge clk)块中它通常被综合成触发器Register在组合逻辑的always (*)块中它会被综合成连线Wire加一些逻辑。用途用于表示在特定条件下如时钟边沿才更新的数据存储点。reg q; // 声明一个reg型变量 always (posedge clk) begin q d; // 在时钟上升沿将d的值锁存到q。这里q会被综合成一个D触发器。 end关键心得一个简单的记忆法是——看赋值语句在哪里。assign后面跟wirealways块里用reg。在大多数可综合设计中模块的输入端口默认为wire输出端口可以是wire或reg但内部连接推荐用wire需要存储状态或用于过程赋值的信号用reg。2.2 向量与数值如何表示总线数字电路很少只处理1比特信号更多的是4位数据线、8位地址线、32位数据总线。Verilog用向量来表示。wire [7:0] data_bus; // 一个8位宽的wire型向量高位在左索引7低位在右索引0 reg [31:0] counter; // 一个32位宽的reg型向量你可以访问向量的某一位或某一段assign led data_bus[0]; // 取最低位 assign high_byte data_bus[7:4]; // 取高4位即第7到第4位 assign merged {data_bus[3:0], 4b0000}; // 拼接操作将低4位和高4位0拼接成一个8位数数值的表示方法也很重要位宽进制数值。4b1010 4位二进制数 1010 (十进制10)8hFF 8位十六进制数 FF (十进制255)16d100 16位十进制数 1001b1,1b0 明确的逻辑1和0。直接写1或0会被解释为32位的整数在赋值给1位信号时可能产生警告建议养成使用明确位宽的习惯。2.3 运算符描述逻辑功能Verilog的运算符和C语言类似但硬件意义不同。位运算符(与)|(或)~(非)^(异或)。它们按位操作直接对应与门、或门等。assign c a b; // 一个与门 assign parity ^data_bus; // 对data_bus所有位进行异或得到奇偶校验位缩减运算符对向量的所有位进行位操作产生1位结果。如data_bus表示data_bus[0] data_bus[1] ... data_bus[7]。逻辑运算符||!。它们操作的结果是布尔值真或假通常用于条件判断。注意和的区别4b0011 4b0101 4b0001而4b0011 4b0101 1b1因为两个操作数都不为0。关系与算术运算符!-*/。这些运算符会被综合成相应的比较器、加法器、乘法器等电路。要特别注意*和/会消耗大量逻辑资源在FPGA中非2的幂次的除法和乘法通常需要调用IP核。移位运算符(左移)(右移)。左移一位相当于乘2右移一位相当于除2在硬件上只是连线的重新排列几乎不消耗逻辑资源是非常高效的运算。assign power_of_two 8b1 shift_amount; // 根据shift_amount生成2的幂次数3. 描述电路行为的核心结构过程块与赋值掌握了基本材料数据类型接下来就需要用特定的“语法结构”来描述电路的行为。过程块always和initial和赋值语句是这里的核心。3.1 always块硬件行为的“发动机”always块是描述硬件并行行为最重要的结构。一个模块里可以有多个always块它们同时、并行地执行从仿真角度看。其语法为always (敏感列表) begin // 过程语句 end敏感列表是灵魂它决定了这个块在什么条件下“触发”执行。时序逻辑敏感列表always (posedge clk or posedge rst)。这描述了一个由时钟clk上升沿和复位rst上升沿触发的触发器组。这是描述寄存器同步逻辑的标准形式。块内应使用非阻塞赋值。组合逻辑敏感列表always (*)或always (a or b or sel)。(*)是 Verilog-2001 标准引入的便捷写法编译器会自动列出块内所有读取信号的列表。这用于描述组合逻辑如多路选择器、译码器。块内必须使用阻塞赋值并且要确保所有输入信号的变化都能导致输出重新计算否则会隐含锁存器Latch这通常是设计错误。3.2 阻塞赋值与非阻塞赋值顺序与并行的艺术这是Verilog学习中最经典的坑没有之一。阻塞赋值如同其名会“阻塞”后续语句的执行。在同一个always块中语句按书写顺序依次执行前一句赋值完成值立即更新后一句再使用这个新值。它模拟了软件的顺序执行行为主要用于组合逻辑建模。always (*) begin temp a b; // 执行完temp立即变成ab的和 c temp * 2; // 这里使用的temp是上一句更新后的值 end综合后temp可能只是一个中间连线最终电路是c (ab)*2的组合逻辑。非阻塞赋值所有语句同时计算右侧表达式RHS但在当前时间步结束时才统一将结果更新到左侧变量LHS。它完美模拟了寄存器在时钟边沿同时更新的硬件行为专用于时序逻辑。always (posedge clk) begin reg1 data_in; // 计算data_in的值但reg1并未立即改变 reg2 reg1; // 计算reg1的值注意是时钟沿到来时reg1的旧值 end这个块描述了一个经典的移位寄存器。在时钟上升沿data_in被锁存到reg1而reg1的旧值被锁存到reg2。两个寄存器的更新是同时发生的。血泪教训记住这个黄金法则——在描述组合逻辑的always (*)块中用在描述时序逻辑的always (posedge clk)块中用。混合使用或者在同一个块里混用两种赋值是导致仿真与综合结果不一致、产生竞争冒险的常见根源。在刚入门时请严格遵守此规则。3.3 条件与循环语句实现逻辑分支与重复结构if-else和case语句用于实现条件分支它们通常被综合成多路选择器MUX。// 使用 if-else 描述一个带优先级的2选1 MUX always (*) begin if (sel_a) begin out in_a; end else if (sel_b) begin out in_b; end else begin out default_val; end end // 使用 case 描述一个不带优先级的4选1 MUX always (*) begin case (sel) 2b00: out in0; 2b01: out in1; 2b10: out in2; 2b11: out in3; default: out 1b0; // 良好的习惯加上default避免产生锁存器 endcase end关键点在组合逻辑的always块中必须为if-else或case的所有可能分支都明确赋值否则会综合出锁存器来“记忆”未赋值的情况。这通常不是你想要的功能会浪费资源并引入时序问题。for循环在Verilog中用于描述重复的硬件结构而不是软件中的循环执行。综合器会将循环“展开”。// 描述一个8位奇偶校验生成器 always (*) begin parity 1b0; // 初始化 for (int i0; i8; ii1) begin parity parity ^ data[i]; // 这会被展开成7个级联的异或门 end end循环次数必须在编译时确定不能是变量。generate for循环更强大用于实例化多个模块或生成重复的代码块是构建参数化设计的重要工具。4. 模块化设计与层次化构建复杂系统的基石任何复杂的数字系统都是由一个个功能相对独立的模块像搭积木一样连接起来的。Verilog的模块module就是这个“积木块”。4.1 模块的定义与实例化一个模块包括接口声明和内部实现。// 模块定义一个简单的2输入与门 module my_and ( input wire a, // 输入端口通常省略wire直接写 input a input wire b, output reg y // 输出端口如果在always块中赋值需声明为reg ); always (*) begin y a b; end endmodule在其他模块中使用这个“积木”叫做实例化。module top ( input wire x1, x2, x3, output wire z ); wire net1; // 内部连接线 // 实例化my_and模块方式一按顺序连接不推荐易错 // my_and U1 (x1, x2, net1); // 实例化my_and模块方式二按名称连接推荐清晰 my_and U1 ( .a (x1), // 将顶层模块的x1连接到实例U1的端口a .b (x2), .y (net1) ); my_and U2 ( .a (net1), .b (x3), .y (z) ); endmodule按名称连接是工程实践中的最佳选择它避免了因端口顺序改变而导致的隐蔽错误代码可读性也强得多。4.2 参数化设计让模块更灵活使用parameter可以定义模块参数让模块像函数一样可配置。module generic_adder #( parameter WIDTH 8 // 默认参数为8 )( input wire [WIDTH-1:0] a, b, output reg [WIDTH-1:0] sum ); always (*) begin sum a b; end endmodule // 实例化时传递参数 generic_adder #(.WIDTH(16)) adder_16bit (.a(a_bus), .b(b_bus), .sum(sum_bus)); generic_adder adder_8bit (.a(a8), .b(b8), .sum(sum8)); // 使用默认8位宽度参数化设计极大地提高了代码的复用性是构建IP核和复杂子系统的基础。4.3 测试平台Testbench的初步认识Verilog不仅是设计语言也是验证语言。测试平台Testbench是一个特殊的顶层模块它没有输入输出端口其任务是实例化待测设计DUT并产生激励信号检查其输出。timescale 1ns/1ps // 定义时间单位/精度 module tb_my_and(); reg a, b; // 驱动DUT输入用reg wire y; // 接收DUT输出用wire // 实例化待测设计 my_and dut (.a(a), .b(b), .y(y)); // 产生测试激励 initial begin a 0; b 0; #10; // 初始值等待10个时间单位 a 0; b 1; #10; a 1; b 0; #10; a 1; b 1; #10; $finish; // 结束仿真 end // 监控输出在仿真器中打印 initial begin $monitor(Time%t, a%b, b%b, y%b, $time, a, b, y); end endmoduleinitial块在仿真开始时执行一次常用于初始化或生成非周期的激励。$monitor等系统任务用于调试和观察波形。虽然现代FPGA开发更多依赖于在Vivado/Quartus中直接编写约束和进行上板调试但掌握简单的Testbench编写对于模块级的功能验证和仿真调试依然非常有用。5. 可综合风格与常见陷阱写出能变成电路的代码并非所有符合语法的Verilog代码都能被综合工具转换成有效的硬件电路。可综合子集Synthesizable Subset是RTL设计者必须遵守的规则。5.1 不可综合或慎用的语法initial块除用于Testbench和某些特殊的FPGA初始化如初始化存储器内容但通常有更好方式外不可用于设计代码。上电后寄存器的初始状态应通过复位信号来设定。#延迟控制如#5 a b;这是仿真用的综合工具会忽略。电路延迟由实际物理路径决定。real类型浮点数大部分综合工具不支持。FPGA中需使用定点数或调用浮点IP核。fork...join进程并行块主要用于高级验证不可综合。循环边界不确定的while/forever综合工具需要确定硬件规模循环必须能在编译时静态展开。5.2 避免隐含锁存器Latch这是新手最常踩的坑。锁存器由电平触发对毛刺敏感在ASIC设计中要尽量避免在FPGA中也会带来时序和验证问题。它通常在组合逻辑的always块中由于条件分支赋值不完整而产生。// 错误示例会产生锁存器 always (*) begin if (en) begin q data; end // 当en为0时q没有新值硬件为了“保持”原值便生成了一个锁存器。 end // 正确写法1为所有分支赋值 always (*) begin if (en) begin q data; end else begin q 1b0; // 或者 q q; (但这样逻辑意义可能不对) end end // 正确写法2在块开始处赋默认值推荐 always (*) begin q 1b0; // 默认值 if (en) begin q data; end end养成在组合逻辑always块开头为所有输出信号赋默认值的习惯能有效避免隐含锁存器。5.3 时序逻辑中的异步复位与同步复位复位是数字系统可靠工作的保障。根据复位信号是否与时钟同步分为两种风格// 异步复位复位信号独立于时钟一旦有效立即生效 always (posedge clk or posedge rst_async) begin if (rst_async) begin q 1b0; end else begin q d; end end // 同步复位复位信号仅在时钟有效边沿被采样 always (posedge clk) begin if (rst_sync) begin q 1b0; end else begin q d; end end异步复位优点是可以立即恢复系统状态对时钟是否稳定无要求。缺点是复位释放时如果刚好在时钟边沿附近可能导致寄存器输出亚稳态复位恢复问题且不利于静态时序分析。同步复位优点是完全在时钟域控制下避免亚稳态STA分析简单。缺点是复位信号需要像数据一样满足建立/保持时间且需要时钟有效才能复位。FPGA的底层触发器通常有专用的异步复位/置位端使用异步复位可以直接映射到该硬件资源效率高。但为了系统的可靠性工程上常采用“异步复位同步释放”的电路结构来兼顾两者的优点。这通常通过编写一个复位同步模块来实现。5.4 关于代码风格与可维护性最后一些软性的经验同样重要命名清晰使用有意义的信号名、模块名如clk_50m,rst_n,data_valid,fifo_rd_en。避免使用a,b,tmp等。注释得当在模块头部说明功能、接口、参数在复杂逻辑旁说明意图。但避免用注释重复代码。一个always块只做一件事尽量让一个always块只描述一组相关的寄存器或一块组合逻辑。如果一个always块过于庞大就拆分它。这有利于综合、调试和后期修改。使用localparam对于模块内部常量使用localparam而非parameter避免被外部修改。小心使用integer和int在可综合循环中常用作索引但需注意其是32位有符号数可能产生非预期的符号扩展问题。语法是骨架思维是灵魂。把Verilog当成画电路图的工具而不是写程序的工具时刻思考你写的每一行代码会对应什么样的物理电路这是从语法入门走向合格数字电路设计者的关键一步。在实际项目中多读好的代码如开源IP核多使用综合工具的RTL视图查看自己代码生成的电路反复对比和思考是提升最快的方法。

相关新闻

Jetson Nano从零配置指南:PyTorch、TensorFlow环境搭建与性能优化

Jetson Nano从零配置指南:PyTorch、TensorFlow环境搭建与性能优化

1. 项目概述:为什么需要一份“从零开始”的配置指南?如果你刚拿到一块Jetson Nano开发板,或者因为系统混乱、环境崩溃而不得不重装,那么恭喜你,你正处在一个最需要清晰指引的十字路口。Jetson Nano作为一款强大的边缘A…

2026/8/7 11:26:43 阅读更多 →
Android DownloadManager 核心机制与实战指南:从原理到避坑

Android DownloadManager 核心机制与实战指南:从原理到避坑

1. 项目概述:为什么我们需要DownloadManager?在Android应用开发中,文件下载是一个高频且基础的需求。无论是新闻应用缓存图片、音乐应用下载歌曲,还是电商应用保存商品详情,都离不开下载功能。很多开发者,尤…

2026/8/7 15:29:41 阅读更多 →
基于Spark高考推荐系统 高考数据分析可视化 院校推荐系统 协同过滤推荐算法 爬虫(源码+文档)✅

基于Spark高考推荐系统 高考数据分析可视化 院校推荐系统 协同过滤推荐算法 爬虫(源码+文档)✅

博主介绍:✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久,选择我们就是选择放心、选择安心毕业✌感兴趣的可以先收藏起来,点赞、关注不迷路✌ 毕业设计:2023-2024年…

2026/8/7 17:25:03 阅读更多 →

最新新闻

04 Collection 与 Parent 的区别

04 Collection 与 Parent 的区别

04 Collection 与 Parent 的区别 一句话记忆:Collection 管“怎么分组和显示”,Parent 管“怎么一起运动”。 一、Collection 是什么 Collection 可以理解成 Blender 场景中的文件夹或资产分组。例如: BOF_ASSET ├─ BOF_LOD0 ├─ BOF_LOD1…

2026/8/8 11:11:45 阅读更多 →
利用 API 实现企业微信消息自动化推送

利用 API 实现企业微信消息自动化推送

许多团队在做内部流程优化或客户服务时,常面临一个痛点:系统产生了关键数据,但相关人员无法第一时间收到通知,导致信息滞后。 其实,通过第三方的自动化集成接口,我们可以非常轻松地将业务数据、系统告警等…

2026/8/8 11:11:44 阅读更多 →
Minecraft世界修复终极指南:免费工具拯救你的游戏存档

Minecraft世界修复终极指南:免费工具拯救你的游戏存档

Minecraft世界修复终极指南:免费工具拯救你的游戏存档 【免费下载链接】Minecraft-Region-Fixer Python script to fix some of the problems of the Minecraft save files (region files, *.mca). 项目地址: https://gitcode.com/gh_mirrors/mi/Minecraft-Region…

2026/8/8 11:11:44 阅读更多 →
隐私保护下的智能视频分析:基于运动推理的异常行为检测技术

隐私保护下的智能视频分析:基于运动推理的异常行为检测技术

如果你正在开发一个智能教室监控系统,或者任何需要从视频流中识别异常行为的应用,那么你很可能正面临一个核心矛盾: 如何在保证识别准确性的同时,严格保护个人隐私? 传统的视频分析方案,无论是基于背景减…

2026/8/8 11:11:44 阅读更多 →
5分钟掌握SD-PPP:如何在Photoshop中集成AI绘图功能

5分钟掌握SD-PPP:如何在Photoshop中集成AI绘图功能

5分钟掌握SD-PPP:如何在Photoshop中集成AI绘图功能 【免费下载链接】sd-ppp A Photoshop AI plugin 项目地址: https://gitcode.com/gh_mirrors/sd/sd-ppp 还在为Photoshop缺少AI绘图功能而烦恼吗?SD-PPP这款免费开源的Photoshop AI插件将彻底改变…

2026/8/8 11:11:44 阅读更多 →
Mac安装Claude Code全指南:解决环境配置三大难题

Mac安装Claude Code全指南:解决环境配置三大难题

1. Claude Code 安装概述:为什么Mac用户需要这份指南在2026年的开发生态中,Claude Code已经成为AI辅助编程的事实标准工具。不同于普通的代码编辑器,它深度融合了新一代AI的上下文理解能力,能够根据开发者习惯动态调整代码建议策略…

2026/8/8 11:10:44 阅读更多 →

日新闻

AI多智能体时代来临,读懂MCP与A2A架构,抢占企业数字化新风口

AI多智能体时代来临,读懂MCP与A2A架构,抢占企业数字化新风口

当下AI应用飞速普及,无数企业下场搭建智能体系统,可落地阶段难题接踵而至:上下文无限堆积频繁爆栈、AI工具调用准确率低下、Token成本居高不下、企业数据权限混乱暗藏安全隐患……很多团队卡在架构搭建环节,空有前沿技术概念&…

2026/8/8 0:00:07 阅读更多 →
PHP二维码生成终极指南:用chillerlan/php-qrcode打造专业级二维码

PHP二维码生成终极指南:用chillerlan/php-qrcode打造专业级二维码

PHP二维码生成终极指南:用chillerlan/php-qrcode打造专业级二维码 【免费下载链接】php-qrcode A PHP QR Code generator and reader with a user-friendly API. 项目地址: https://gitcode.com/gh_mirrors/ph/php-qrcode 在当今数字时代,二维码已…

2026/8/8 0:00:08 阅读更多 →
UniApp微信小程序隐私保护组件开发:从原理到实战

UniApp微信小程序隐私保护组件开发:从原理到实战

1. 项目缘起:为什么我们需要一个隐私保护通用组件?最近在维护一个基于uniapp开发的微信小程序矩阵时,我遇到了一个非常棘手的问题。随着平台对用户隐私保护的要求越来越严格,几乎每一个新版本发布,或者在某些特定机型&…

2026/8/8 0:00:08 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/6 22:02:27 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/8 8:58:26 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/7 23:24:08 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/7 17:02:37 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/7 23:54:54 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/7 17:02:36 阅读更多 →