ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

数字IC手撕代码:三分频电路设计与Verilog实现详解

数字IC手撕代码:三分频电路设计与Verilog实现详解 1. 从“手撕代码”到“三分频”数字IC面试的硬核敲门砖最近几年数字IC设计岗位的面试里“手撕代码”已经从一个加分项变成了必考题。面试官递过来一张白纸或者打开一个在线编辑器让你现场实现一个功能模块这种场景让不少候选人手心冒汗。而“三分频”电路正是这个“手撕代码”题库里的经典明星出场率极高。它考察的绝不仅仅是写几行Verilog那么简单背后是对数字电路基础、时序逻辑设计、时钟域处理乃至代码风格的综合检验。很多朋友包括我当年第一次看到这个题目时可能会觉得“不就是个计数器吗”但真动起手来才发现从功能正确、到波形干净、再到面积和功耗优化每一步都藏着细节。“芯源”这个词在IC圈里通常指代芯片设计的源头也就是RTL寄存器传输级设计。所以“数字IC手撕代码--芯源三分频”这个标题精准地指向了数字IC设计工程师的核心技能用Verilog这样的硬件描述语言从源头构建一个可靠、高效的电路模块。三分频器作为一个中等复杂度的时序电路完美地承载了这个考察目标。它不像一个简单的计数器那样直白也不像复杂的状态机或协议接口那样庞大它恰到好处地卡在中间让你必须清晰地理解时钟边沿、状态跳变和占空比这些概念。这篇文章我就结合自己多次面试和被面试的经验以及在实际项目中设计时钟电路的体会来彻底拆解这个“三分频”电路。我不会只给你一个“标准答案”而是会带你走一遍完整的思考、设计、实现和优化的过程。我们会从最基础的需求分析开始探讨几种不同的实现方案比较它们的优缺点然后深入到代码实现、仿真验证最后还会聊聊在面试中如何应对可能的追问以及在实际芯片设计中需要注意的陷阱。无论你是正在准备数字IC岗位面试的学生还是希望巩固基础的初级工程师相信这篇长文都能给你带来实实在在的收获。2. 三分频电路的需求分析与设计目标拆解在动笔写第一行代码之前我们必须把需求彻底搞清楚。面试官说“实现一个三分频电路”这其实是一个模糊的需求就像客户说“我要一个好看的界面”一样。一个合格的工程师第一步就是澄清需求定义清晰的设计目标。2.1 明确输入与输出首先最基本的接口输入一个原时钟信号我们通常命名为clk_in。我们需要知道它的频率吗对于纯粹的分频功能来说不需要我们只关心它的周期和边沿。还需要复位信号rst_n吗在真实的芯片设计中几乎百分之百需要这是一个好习惯。所以输入至少包括clk_in和rst_n。输出一个三分频后的时钟信号命名为clk_out。这里的关键问题是输出时钟的占空比是多少2. 2 占空比第一个设计抉择点“三分频”意味着输出时钟的周期是输入时钟的三倍。但一个周期内高电平和低电平的占比就是占空比并没有被定义。这是面试官留给你的第一个发挥空间也是考察你对电路理解深度的地方。50%占空比这是最理想、也是最常见的要求。因为占空比为50%的时钟信号在后续电路中驱动能力均衡对时序分析友好。但实现一个精确的50%占空比的三分频需要一点技巧因为3是奇数无法用简单的计数器直接二分得到。1/3占空比或2/3占空比这种实现起来最简单一个模3计数器当计数器为某个值时输出高其余为低即可。但占空比不是50%在某些对时钟质量要求高的场景如作为某些模拟模块的时钟源可能不适用。未指定占空比如果面试官没有明确要求你应该主动询问“您对输出时钟的占空比有要求吗” 这体现了你的严谨和专业。通常如果对方说“都可以”或“你实现一个看看”那么优先实现50%占空比的方案因为它更能体现你的能力。2.3 其他关键设计目标除了功能正确我们还需要考虑同步设计所有触发器都应使用同一个clk_in驱动避免使用门控时钟或行波计数器等异步设计以保证良好的可综合性、可测试性和静态时序分析STA友好性。毛刺消除输出时钟clk_out必须是一个干净、无毛刺的信号。任何组合逻辑产生的毛刺如果被当作时钟使用将导致电路功能错误。这意味着clk_out最好直接来自触发器的输出端Q端而不是经过组合逻辑。面积与功耗在满足功能的前提下使用最少的触发器Flip-Flop和逻辑门。这对于低功耗设计尤为重要。代码风格代码应清晰、可读、可维护。良好的命名、合理的注释、规范的 always 块使用都是面试的加分项。明确了这些我们就可以开始构思电路方案了。我们的核心目标是在同步设计的前提下产生一个周期为3倍clk_in、占空比为50%、无毛刺的clk_out信号。3. 方案对比从简单计数器到双边沿触发实现三分频至少有三种主流的思路。我们逐一分析理解其原理和适用场景。3.1 方案一模3计数器与1/3占空比最简方案这是最直观的思路。用一个2位宽的计数器在clk_in的上升沿从0计数到2然后归零循环往复。状态cnt可以为 0, 1, 2。输出逻辑例如我们定义当cnt 0时clk_out 1当cnt 1或cnt 2时clk_out 0。这样clk_out在一个周期3个clk_in周期中只有一个clk_in周期为高占空比为 1/3。module clk_div3_simple( input wire clk_in, input wire rst_n, output reg clk_out ); reg [1:0] cnt; // 模3计数器0-1-2-0... always (posedge clk_in or negedge rst_n) begin if (!rst_n) begin cnt 2b00; clk_out 1b0; end else begin if (cnt 2b10) // 当计数到2时下一个周期回到0 cnt 2b00; else cnt cnt 1b1; // 输出逻辑仅在cnt为0时输出高电平 clk_out (cnt 2b00); end end endmodule注意在这个实现中clk_out是寄存器直接输出的没有毛刺这是优点。但占空比不是50%是其主要局限。如果面试官可以接受非50%占空比这个方案简洁高效。3.2 方案二错相叠加法实现50%占空比经典方案这是实现奇数分频如3、5、7分频且要求50%占空比的经典方法。核心思想是用两个占空比非50%的时钟信号进行逻辑运算合成一个50%占空比的时钟。具体到三分频我们产生两个时钟信号clk_p和clk_n。它们的频率都是clk_in的1/3但相位相差180度即半个clk_out周期或者说1.5个clk_in周期。clk_p在clk_in上升沿触发和控制clk_n在clk_in下降沿触发和控制。这就是“错相”。将clk_p和clk_n进行“或”运算OR得到的就是占空比为50%的clk_out。为什么我们可以画个波形图来理解。假设clk_p在计数器为0时拉高持续一个clk_in周期。由于clk_n使用下降沿且相位差半个周期它会在clk_p拉高结束后的半个周期下降沿处拉高。这样两个信号的高电平脉冲在时间上刚好错开但合并后高电平的持续时间就变成了两个clk_in周期低电平为一个clk_in周期整体占空比就是 (2/3) / 3不对让我们重新计算clk_out周期是3个clk_in高电平持续了2个clk_in所以占空比是 2/3等等这还不是50%。这里有个关键点对于三分频50%占空比意味着高电平持续1.5个clk_in周期。单纯靠两个信号的“或”是得不到1.5的。实际上更通用的操作是“异或”运算XOR。clk_p和clk_n的异或当两者电平不同时输出高相同时输出低。通过精心设计clk_p和clk_n的跳变沿就可以合成出精确的50%占空比波形。3.3 方案三状态机与双边沿触发思维拓展方案这个方案更能体现你对时序逻辑的深入理解。我们设计一个状态机有3个状态 S0, S1, S2。状态转移发生在clk_in的每个上升沿。但输出clk_out的翻转不仅发生在上升沿也可能发生在下降沿。具体实现时我们使用clk_in作为状态机的时钟。在状态 S0我们让clk_out在下一个clk_in的上升沿翻转例如从0变1。在状态 S1我们保持。在状态 S2我们让clk_out在下一个clk_in的下降沿翻转从1变0。这样高电平持续时间就是 S0的上升沿到 S2的下降沿刚好是1.5个周期。这种方案的代码实现需要引入一个在下降沿采样的信号来控制部分逻辑或者使用双边沿触发的触发器这在ASIC中不常见且不推荐。因此它更多是一种理论上的思路用于展示你对时钟边沿和状态机的掌控力在实际工程中不如方案二可靠和通用。综合来看方案二错相叠加法是实现50%占空比三分频的最优选择它结构清晰完全同步且易于扩展到其他奇数分频。接下来我们就重点实现这个方案。4. 手撕代码50%占空比三分频器的Verilog实现与仿真现在我们进入核心环节用Verilog实现方案二。我会给出完整的代码并逐行解释其设计意图和注意事项。4.1 模块定义与信号声明module clk_div3_50percent( input wire clk_in, // 原时钟输入 input wire rst_n, // 低电平异步复位 output wire clk_out // 三分频50%占空比时钟输出 ); // 内部寄存器声明 reg [1:0] cnt_p; // 用于上升沿分频的计数器 reg [1:0] cnt_n; // 用于下降沿分频的计数器 reg clk_p_reg; // 上升沿产生的分频时钟寄存器 reg clk_n_reg; // 下降沿产生的分频时钟寄存器 wire clk_p, clk_n; // 对应的wire型信号便于连接 // 将寄存器输出赋值给wire这是良好的代码风格 assign clk_p clk_p_reg; assign clk_n clk_n_reg;首先定义模块接口。使用wire和reg类型要清晰。clk_out将是组合逻辑异或的输出所以定义为wire。内部我们声明了两组计数器和寄存器分别对应上升沿和下降沿的电路。4.2 上升沿电路产生clk_p这部分电路在clk_in的上升沿工作。// 上升沿进程生成cnt_p和clk_p_reg always (posedge clk_in or negedge rst_n) begin if (!rst_n) begin cnt_p 2b00; clk_p_reg 1b0; end else begin // 模3计数器 if (cnt_p 2b10) // 计数到2后归零 cnt_p 2b00; else cnt_p cnt_p 1b1; // 生成clk_p_reg在cnt_p为0和1时拉高为2时拉低 // 这样clk_p的占空比是2/3周期是3个clk_in case (cnt_p) 2b00: clk_p_reg 1b1; 2b01: clk_p_reg 1b1; 2b10: clk_p_reg 1b0; default: clk_p_reg 1b0; // 避免锁存器 endcase end end这里的关键是clk_p_reg的生成逻辑。我们让它在计数器为0和1时输出高电平为2时输出低电平。这样clk_p是一个占空比为 2/3、周期为3倍clk_in的时钟。default语句是良好的编码习惯确保在所有未列出的情况下虽然理论上不会出现也有确定值防止综合出锁存器。4.3 下降沿电路产生clk_n这部分电路在clk_in的下降沿工作其逻辑与上升沿电路类似但计数器cnt_n的初态或相位需要与cnt_p错开半个周期才能实现180度相位差。// 下降沿进程生成cnt_n和clk_n_reg always (negedge clk_in or negedge rst_n) begin if (!rst_n) begin cnt_n 2b00; // 注意这里初值设为0但通过逻辑实现错相 clk_n_reg 1b0; end else begin // 模3计数器逻辑与上升沿一致 if (cnt_n 2b10) cnt_n 2b00; else cnt_n cnt_n 1b1; // 生成clk_n_reg为了实现与clk_p的180度相位差 // 我们让clk_n在cnt_n为1和2时拉高为0时拉低。 // 这样clk_n的占空比也是2/3但跳变沿与clk_p错开。 case (cnt_n) 2b00: clk_n_reg 1b0; 2b01: clk_n_reg 1b1; 2b10: clk_n_reg 1b1; default: clk_n_reg 1b0; endcase end end注意clk_n_reg的生成逻辑与clk_p_reg不同。clk_n在cnt_n为1和2时为高。通过仿真我们可以验证这样设计的clk_n的上升沿大致对应着clk_p高电平的中间点从而形成了所需的相位关系。4.4 合成最终输出最后将两个相位错开的时钟进行异或操作得到50%占空比的最终时钟。// 通过异或运算合成50%占空比的时钟 assign clk_out clk_p ^ clk_n; endmodule异或运算的特性是“相异为1相同为0”。clk_p和clk_n两个占空比2/3、相位差半拍的信号异或后高电平的宽度恰好等于它们电平不同的时间宽度通过精心设计的跳变沿这个时间被调整为1.5个clk_in周期。4.5 测试平台与仿真验证设计完成必须用测试平台Testbench进行仿真。这是“手撕代码”后不可或缺的一步体现了你的验证意识。timescale 1ns/1ps module tb_clk_div3_50percent(); reg clk_in; reg rst_n; wire clk_out; // 实例化被测试模块 clk_div3_50percent uut ( .clk_in(clk_in), .rst_n(rst_n), .clk_out(clk_out) ); // 生成时钟信号周期10ns100MHz initial begin clk_in 0; forever #5 clk_in ~clk_in; // 每5ns翻转一次周期10ns end // 生成复位信号 initial begin rst_n 0; // 初始复位 #20; // 复位保持20ns rst_n 1; // 释放复位 #200; // 仿真运行200ns $finish; // 结束仿真 end // 将信号变化记录到VCD文件便于查看波形 initial begin $dumpfile(wave.vcd); $dumpvars(0, tb_clk_div3_50percent); end endmodule在仿真波形中你应该关注复位期间所有信号是否为确定值0。释放复位后cnt_p和cnt_n是否从0开始正确计数0-1-2-0...。clk_p和clk_n的波形是否符合设计占空比2/3相位错开。最关键测量clk_out的周期是否为30ns3倍于clk_in的10ns高电平持续时间是否为15ns占空比50%。如果波形符合预期那么恭喜你一个稳健的50%占空比三分频器就设计成功了。5. 深入探讨关键细节、常见陷阱与面试应对代码能跑通波形只成功了80%。剩下的20%在于理解背后的细节以及应对实际工程和面试中的挑战。5.1 为什么使用“异或”而不是“或”这是理解这个方案的核心。我们可以用真值表来分析 假设clk_p和clk_n的跳变沿完美对齐实际有微小延迟在一个clk_out周期内第1阶段clk_p1,clk_n0-clk_out 1^0 1第2阶段clk_p1,clk_n1-clk_out 1^1 0第3阶段clk_p0,clk_n1-clk_out 0^1 1第4阶段clk_p0,clk_n0-clk_out 0^0 0(这实际上是下一个周期的开始) 但实际上由于我们的设计clk_p和clk_n不会同时为1持续整个阶段。通过精确控制它们跳变的时刻cnt_p和cnt_n的状态变化点clk_p和clk_n同时为1的时间极短理论上是一个clk_in周期中的一部分而同时为0的时间也极短。异或操作恰好能利用这种短暂的“相异”状态合成出一个高、低电平各占1.5个clk_in周期的时钟。如果使用“或”运算高电平时间会过长无法得到精确的50%占空比。你可以尝试在仿真中修改代码将^换成|观察波形变化理解会非常直观。5.2 时钟偏移与毛刺风险这是我们方案的一个潜在弱点。clk_out是由组合逻辑异或门产生的。虽然clk_p_reg和clk_n_reg是寄存器输出无毛刺但经过异或门后如果两个输入信号到达异或门的时间有微小差异由于布线延迟不同就可能产生毛刺。clk_p来自上升沿触发器clk_n来自下降沿触发器。它们物理上到达异或门的路径延迟很可能不同。当两者状态本应同时变化时一个快一点一个慢一点在变化的瞬间异或门的输入端就会短暂地出现“0和0”或“1和1”之外的非预期状态导致输出端产生一个非常窄的脉冲即毛刺。重要提示在真实的ASIC或FPGA设计中绝对不建议将组合逻辑产生的信号直接用作其他时序电路的时钟这个clk_out如果直接驱动其他触发器毛刺可能导致严重的功能错误。那么怎么办呢5.3 解决方案寄存器输出整形标准的做法是对clk_out进行“再采样”或“整形”用一个触发器来过滤掉毛刺。我们可以用原时钟clk_in的上升沿或下降沿来采样这个组合逻辑产生的clk_out_pre我们重命名一下得到一个干净的、寄存器输出的clk_out_final。wire clk_out_pre; // 组合逻辑产生的、可能有毛刺的时钟 reg clk_out_reg; // 寄存器整形后的干净时钟 assign clk_out_pre clk_p ^ clk_n; always (posedge clk_in or negedge rst_n) begin if (!rst_n) clk_out_reg 1b0; else clk_out_reg clk_out_pre; // 用clk_in采样 end assign clk_out clk_out_reg; // 输出整形后的时钟这样clk_out的跳变将只发生在clk_in的上升沿其稳定性由触发器的建立保持时间保证彻底消除了毛刺。代价是clk_out相对于clk_out_pre会有最多一个clk_in周期的延迟并且其占空比可能不再是精确的50%因为采样可能发生在跳变沿附近但仍然是接近50%的、非常稳定的时钟。在绝大多数应用中这种微小的偏差是可以接受的。5.4 面试中可能被追问的问题“除了这种方法还能怎么实现50%占空比的奇数分频”可以提到状态机结合双边沿控制的思想方案三并指出其在实际综合中的潜在问题。还可以提到使用更高频的时钟进行计数然后内插但这需要PLL或更高频时钟源不属于纯数字分频范畴。“你的输出时钟clk_out能直接用作时钟吗有什么风险”这正是展示你工程经验的地方。明确指出组合逻辑产生时钟有毛刺风险并提出寄存器整形的解决方案。这会让面试官觉得你考虑问题很周全。“如果要求输出时钟与输入时钟同相位即第一个上升沿对齐该怎么修改”这需要调整计数器cnt_n的初始值或clk_n的产生逻辑。你可以通过分析波形让clk_p和clk_n的初始相位满足对齐要求。这考验的是对波形和状态关系的调试能力。“如何将这个设计扩展到任意奇数分频比如5分频、7分频”原理相同分别用上升沿和下降沿产生两个占空比为 (N-1)/N 的分频时钟N为分频系数并使它们相位差半个输出周期最后异或。计数器的位宽需要调整状态控制逻辑也需要相应修改。6. 从三分频看数字IC设计素养通过这个具体的“三分频”项目我们可以提炼出数字IC设计工程师必备的几种核心素养这些也是面试官通过“手撕代码”真正想考察的东西。6.1 从需求到规格的转化能力面试官给出一个模糊的“三分频”你能主动识别出“占空比”、“同步/异步复位”、“有无毛刺”等关键规格缺口。在实际工作中客户或系统工程师的需求文档Spec也常常是不完整的需要设计者主动沟通、澄清、定义边界条件。这种“把模糊想法变成清晰电路指标”的能力是资深工程师和新手的显著区别。6.2 方案权衡与折中的意识我们分析了三种方案。方案一简单但占空比不理想方案二错相叠加功能完美但结构稍复杂且有毛刺风险方案三思路巧妙但实现别扭。没有绝对的最优解只有最适合当前场景的解。面试中清晰地阐述不同方案的优缺点并根据假设的“场景”如“对面积极其敏感”、“对时钟质量要求极高”做出选择能体现你的工程判断力。在实际项目中这种权衡无处不在性能 vs 面积 vs 功耗 vs 交付时间。6.3 对“时钟”的敬畏之心时钟是数字电路的脉搏。通过这个设计我们深刻体会到时钟质量至关重要毛刺是时钟的毒药。任何可能产生时钟的组合逻辑都必须慎之又慎最好通过寄存器输出。时钟域我们这个设计其实产生了一个新的时钟域clk_out。如果后续有信号要从clk_in域传到clk_out域就涉及到跨时钟域CDC处理这是一个更复杂的话题。在面试中如果你能主动提到“这个三分频模块的输出是一个新的时钟域在实际系统集成时需要考虑CDC问题”绝对是巨大的加分项。时钟偏移与抖动即使我们用了寄存器整形clk_out相对于clk_in的延迟Latency和偏移Skew也需要在系统级时序分析中考虑。6.4 代码即电路的思想写Verilog不是写软件。每一行代码都对应着综合后的实际电路元件触发器、与门、或门、选择器等和它们之间的连接。always (posedge clk)对应一个由时钟上升沿触发的触发器组。always (negedge clk)对应下降沿触发的触发器组。在同一个模块中混合使用上升沿和下降沿敏感的逻辑需要格外小心时序。assign语句对应连续赋值是组合逻辑。if-else和case语句会被综合成多路选择器MUX。 在写代码时脑子里要同步想象出大致的电路结构。这能帮你避免写出无法综合或综合结果很差的代码。7. 举一反三从三分频到通用奇数分频模块设计掌握了三分频我们可以很容易地将设计推广到一个参数化的通用奇数分频模块。这不仅体现了代码的复用性也展示了你的系统思维。7.1 参数化设计我们可以使用Verilog的parameter来定义分频系数N要求N为大于1的奇数。module clk_div_odd_50percent #( parameter ODD_N 3 // 分频系数必须为奇数 )( input wire clk_in, input wire rst_n, output wire clk_out ); // 检查参数合法性仿真时有用 initial begin if (ODD_N 1 || ODD_N[0] 1b0) begin $error(Error: ODD_N must be an odd number greater than 1. Current value is %0d, ODD_N); end end // 计算计数器位宽 localparam CNT_WIDTH $clog2(ODD_N); reg [CNT_WIDTH-1:0] cnt_p, cnt_n; reg clk_p_reg, clk_n_reg; wire clk_p, clk_n; wire clk_out_pre; reg clk_out_reg; assign clk_p clk_p_reg; assign clk_n clk_n_reg; // 上升沿计数器与clk_p生成 always (posedge clk_in or negedge rst_n) begin if (!rst_n) begin cnt_p {CNT_WIDTH{1b0}}; clk_p_reg 1b0; end else begin if (cnt_p (ODD_N - 1)) cnt_p {CNT_WIDTH{1b0}}; else cnt_p cnt_p 1b1; // 生成占空比为 (ODD_N-1)/ODD_N 的 clk_p // 高电平持续 (ODD_N-1) 个 clk_in 周期 if (cnt_p (ODD_N - 1)) clk_p_reg 1b1; else clk_p_reg 1b0; end end // 下降沿计数器与clk_n生成 // clk_n需要与clk_p错开 (ODD_N/2) 个计数周期取整 // 对于N3, (3/2)1.5取整后相位差1或2这里需要精确计算。 // 更通用的方法是让clk_n在cnt_n为 (ODD_N1) 到 (ODD_N-1) 时为高。 // 即高电平从中间点开始。 always (negedge clk_in or negedge rst_n) begin if (!rst_n) begin cnt_n {CNT_WIDTH{1b0}}; clk_n_reg 1b0; end else begin if (cnt_n (ODD_N - 1)) cnt_n {CNT_WIDTH{1b0}}; else cnt_n cnt_n 1b1; // 生成clk_n高电平从计数中点开始 if (cnt_n (ODD_N1)) // (ODD_N1) 是整数除法例如311 clk_n_reg 1b1; else clk_n_reg 1b0; end end // 组合逻辑异或与寄存器整形 assign clk_out_pre clk_p ^ clk_n; always (posedge clk_in or negedge rst_n) begin if (!rst_n) clk_out_reg 1b0; else clk_out_reg clk_out_pre; end assign clk_out clk_out_reg; endmodule这个通用模块的关键在于clk_n生成逻辑的通用化。我们让clk_n在计数器值大于等于ODD_N1即ODD_N除以2取整时为高。对于 N3ODD_N1等于1所以clk_n在cnt_n为1和2时为高这与我们之前手写的三分频代码一致。对于 N5ODD_N1等于2clk_n在cnt_n为2,3,4时为高。通过这种对称的设计clk_p和clk_n的异或就能产生接近50%占空比的输出。需要注意的是由于取整操作当N不是2的幂次减一时占空比可能不是精确的50%但会非常接近对于大多数应用已足够。7.2 测试与验证对于参数化模块我们需要用不同的参数进行实例化测试。module tb_clk_div_odd(); reg clk, rst_n; wire clk_out_3, clk_out_5, clk_out_7; clk_div_odd_50percent #(.ODD_N(3)) uut3 (.clk_in(clk), .rst_n(rst_n), .clk_out(clk_out_3)); clk_div_odd_50percent #(.ODD_N(5)) uut5 (.clk_in(clk), .rst_n(rst_n), .clk_out(clk_out_5)); clk_div_odd_50percent #(.ODD_N(7)) uut7 (.clk_in(clk), .rst_n(rst_n), .clk_out(clk_out_7)); initial begin clk 0; forever #5 clk ~clk; end initial begin rst_n 0; #100 rst_n 1; #500 $finish; end initial begin $dumpfile(wave_odd.vcd); $dumpvars(0, tb_clk_div_odd); end endmodule在仿真中观察clk_out_3、clk_out_5、clk_out_7的波形验证其周期和占空比是否符合预期。这种举一反三的能力是面试官非常看重的。
返回列表