MPC860 PowerQUICC处理器架构解析与嵌入式通信开发实战
1. MPC860 PowerQUICC处理器架构概览与核心价值在嵌入式通信设备领域尤其是早期的路由器、交换机、工业网关和网络接入设备中飞思卡尔现恩智浦的MPC860 PowerQUICC系列处理器是一个绕不开的里程碑。它不仅仅是一颗CPU更是一个高度集成的“系统级芯片”SoC其设计哲学深刻影响了后续的通信处理器发展。我接触过不少基于MPC860的老设备从固件逆向到驱动移植深感其架构设计的精妙与复杂。对于今天仍在维护或学习这类经典平台的工程师来说理解其“为什么这样设计”比单纯记住寄存器地址更有价值。MPC860的核心价值在于其“双核”思想——一个用于通用计算的PowerPC核心MPC8xx Core与一个专司通信处理的RISC处理器CPM通信处理器模块协同工作。这种架构在当年有效地解决了单一CPU既要处理复杂协议栈如HDLC、以太网、ATM又要运行操作系统如VxWorks、Linux的瓶颈。PowerPC核心负责运行操作系统和应用程序而CPM则像一个高效的“协处理器”独立处理串行数据的收发、DMA传输和协议封装极大减轻了主CPU的负担。这种分工使得MPC860在有限的频率下几十到一百多兆赫兹就能实现多路T1/E1、以太网等接口的线速处理这在当时是相当出色的性能。对于开发者而言MPC860的开发挑战主要来自其复杂性。你需要同时理解PowerPC的编程模型、内存与缓存管理、以及CPM这个“片上外设”的详细工作机制。它的数据手册动辄上千页寄存器多如牛毛初次接触容易让人望而生畏。但一旦理清了其“主核通信协处理器丰富内存控制器与外设”的脉络你就会发现其设计非常模块化逻辑清晰。本文旨在为你拆解这座“大厦”从核心架构到通信模块再到实际开发中的关键配置与避坑指南让你能快速上手并理解其背后的设计逻辑。2. 核心架构深度解析PowerPC核心与系统集成2.1 PowerPC 8xx核心与执行流水线MPC860集成了一个精简版的PowerPC 603e核心通常被称为MPC8xx核心。它采用经典的RISC架构拥有32位整数单元、分支处理单元和加载/存储单元。虽然它不支持浮点运算FPU但对于绝大多数控制平面和轻量级数据平面任务来说整数性能已经足够。其指令流水线是理解性能的关键。它采用四级流水线取指Fetch、译码Decode、执行Execute、写回Writeback。为了提高效率核心支持分支预测静态预测和指令预取。一个容易被忽略但至关重要的细节是它的“完成队列”Completion Queue。当执行单元如加载/存储需要访问较慢的外部内存时指令并不会阻塞整个流水线后续不依赖该结果的指令可以继续执行直到完成队列满为止。这意味着编写代码时合理安排指令顺序避免过多的数据依赖能显著提升性能。实操心得指令调度优化在编写对性能要求苛刻的底层驱动如网络数据包处理循环时可以手动进行指令调度。例如在一条加载指令从内存读数据到寄存器后立即安排几条与该加载结果无关的算术或逻辑指令充分利用流水线和完成队列。编译器如GCC的-O2或-O3优化通常会自动做这件事但在某些关键路径上查看反汇编并进行微调仍是有效的。2.2 内存管理单元MMU与地址翻译MPC860的MMU是实现复杂操作系统如Linux的基石。它包含独立的指令MMUIMMU和数据MMUDMMU各有32个入口的TLBTranslation Lookaside Buffer。MMU支持页面大小的可变性常见的有4KB、16KB、256KB、1MB和8MB这为不同用途的内存区域代码段、数据段、外设寄存器映射提供了灵活的映射策略。地址翻译过程涉及两级页表查询软件实现和TLB缓存硬件加速。当TLB未命中TLB Miss时会触发一个异常操作系统内核的异常处理程序需要负责遍历软件维护的页表找到对应的物理页帧号并将其加载到TLB中。这个过程相对耗时因此优化TLB命中率是提升系统整体性能的关键。注意事项TLB锁定与关键代码在实时性要求极高的场景如中断服务例程、网络协议栈的快速路径频繁的TLB缺失是不可接受的。MPC860的MMU支持TLB条目锁定功能。开发者可以将最关键的代码和数据所在的页表项锁定在TLB中确保它们永远不会被换出。例如在VxWorks中可以通过sysMmuMap函数设置TLB_WRITETHROUGH | TLB_LOCKED属性来实现。/* 示例在VxWorks中锁定关键ISR代码区域到TLB */ STATUS sysMmuMap (void *virtualAddr, void *physicalAddr, size_t length, int flags); // 使用 TLB_LOCKED 标志2.3 缓存Cache子系统配置策略MPC860包含独立的4KB指令缓存和4KB数据缓存均为2路组相联。缓存行大小为16字节。数据缓存支持两种写策略写通Write-Through和写回Write-Back。写通WT数据写入时同时更新缓存和主内存。简单、一致性好但总线流量大。写回WB数据写入时只更新缓存并将该缓存行标记为“脏”Dirty。只有当该行被替换出缓存时才写回主内存。性能高总线占用少但需要维护缓存一致性。配置选择建议对于只读或代码区域毫无疑问使用缓存提升取指速度。对于频繁读写的普通数据区使用写回策略性能最佳。对于设备寄存器映射的内存区域即I/O空间必须设置为缓存禁止Cache Inhibited和写通如果可写。这是因为外设寄存器的值可能被外部事件改变如状态寄存器缓存会导致CPU读到过时的数据同时对寄存器的写操作需要立即生效不能延迟。对于由DMA设备如CPM访问的内存缓冲区这是一个经典难题。如果CPU缓存了该缓冲区而CPM通过DMA直接向物理内存写入数据CPU缓存中的数据就会变成“脏数据”与内存不一致。解决方案有两种使用非缓存Non-cacheable内存区域简单粗暴但损失性能。使用缓存但维护一致性在启动DMA传输前使用dcbf数据缓存块刷新指令将缓存中该缓冲区的脏数据写回内存在DMA传输完成后、CPU读取数据前使用dcbi数据缓存块无效指令使缓存中该缓冲区的数据失效强制从内存重新加载。MPC860的CPM缓冲区描述符BD机制通常与这种软件维护缓存一致性的模式配合使用。避坑指南内存属性配置错误这是新手最容易导致系统崩溃的问题之一。在设置内存控制器如BR/OR寄存器或MMU页表时务必正确配置每个内存区域的缓存属性CI/WT/WB。一个典型的错误是将FlashNOR Flash设置为写回缓存模式这会导致不可预料的写操作和系统崩溃。Flash应配置为缓存禁止CI。2.4 系统接口单元SIU与复位配置SIU是MPC860与外部世界连接的总调度中心。它管理着外部总线接口、时钟、复位、中断控制器、软件看门狗、实时时钟RTC和周期中断定时器PIT。复位配置字Hard Reset Configuration Word是系统启动的第一个关键步骤。在上电或硬复位期间MPC860会采样特定引脚如MODCK1,MODCK2以及数据线D0-D31的部分的状态形成一个32位的配置字。这个字决定了处理器至关重要的初始状态配置位域功能常见设置与影响PLPRCR[MF]系统PLL倍频因子决定核心时钟CCLK与外部输入时钟EXTCLK的倍率。设置错误会导致CPU频率过高不稳定或过低性能差。SCCR[DFBRG]分频器配置决定CPM、串口等模块的时钟来源与分频。SIUMCR[LBPC]数据总线锁相配置影响外部总线访问的时序。Mx_CTR[CID]缓存禁止位决定复位后缓存初始状态是启用还是禁用。通常Bootloader会先禁用缓存初始化后再开启。实操步骤确定并设置配置字硬件设计阶段根据选择的晶振频率和所需的CPU频率计算PLL的MF值。查阅数据手册的“Clocks and Power Control”章节确保MF值在推荐范围内。硬件连接通过上拉/下拉电阻将对应的数据线引脚如D0-D15用于配置字低16位设置为正确的电平以形成你计算出的配置字。软件验证在Bootloader中尽早读取IMMR内部内存映射寄存器基地址然后读取PLPRCR等寄存器确认实际的时钟配置是否符合预期。可以使用一个简单的循环闪烁LED来验证CPU时钟大致正确。常见问题系统“跑飞”或无法启动问题系统上电后毫无反应或运行极不稳定。排查首先检查电源和复位电路是否正常。使用示波器测量核心时钟CCLK和外部总线时钟CLKOUT频率与配置字计算值对比。检查配置字引脚的上拉/下拉电阻是否正确焊接阻值是否合适通常4.7KΩ-10KΩ。确认Boot ROM如Flash的片选时序配置在内存控制器的OR0/BR0中是否与该Flash芯片的读周期参数匹配。时序过紧会导致读数据错误从而无法执行正确的启动代码。3. 通信处理器模块CPM精解与驱动开发3.1 CPM架构独立RISC处理器与双端口RAMCPM是MPC860的灵魂。它本身是一个独立的32位RISC处理器基于RISC架构拥有自己的指令集微码、定时器和中断控制器。它与PowerPC核心通过以下两种主要方式通信双端口RAMDPRAM这是一块共享内存区域是核心与CPM交互的主战场。其结构如下参数RAMParameter RAM每个通信控制器如SCC、SMC、SPI都有自己独占的一块参数RAM区域用于存放当前通道的配置参数、状态字、缓冲区描述符表基地址等。缓冲区描述符表BD Table这是一个由缓冲区描述符Buffer Descriptor组成的环形队列。每个BD描述了一个数据缓冲区在系统内存中的位置地址、长度和状态就绪、满、空、是否中断。CPM和核心通过操作BD来传递数据的所有权。微码Microcode固化的控制程序存储在ROM中负责解析协议、管理BD、控制DMA传输。开发者无需编程。CPM命令寄存器CPCRPowerPC核心通过向CPCR写入特定命令码如STOP_TX,RESTART_TX,INIT_RX_AND_TX来命令CPM执行某个动作。数据流模型以SCC接收数据为例驱动初始化在DPRAM中设置好SCC的参数RAM和Rx BD环。驱动将若干个空的、状态为EEmpty的Rx BD交给CPM通过设置R_Base指针和R_Count。SCC硬件收到数据后CPM的RISC处理器运行微码通过SDMASlave DMA将数据直接搬运到当前E状态的Rx BD所指向的系统缓冲区中。搬运完成后CPM将该BD状态改为RReady并可选地产生一个中断。PowerPC核心的中断服务程序ISR检测到中断遍历Rx BD环找到状态为R的BD处理其中的数据。处理完毕后驱动将该BD状态重新改为E并更新R_Count将其交还给CPM等待下一次接收。3.2 串行通信控制器SCC实战配置SCC是CPM中最强大和最复杂的模块之一一个MPC860最多有4个SCC。每个SCC可以通过软件配置为多种协议模式UART、HDLC、Bisync、Ethernet、Transparent等。以配置SCC2为UART为例详解步骤与原理3.2.1 引脚复用与时钟配置首先SCC的收发引脚SCC2_TXD,SCC2_RXD与通用I/O口复用。必须通过端口引脚分配寄存器如PAPAR,PADIR将其功能设置为SCC而非通用I/O。/* 假设SCC2_TXD使用PA12SCC2_RXD使用PA13 */ *(volatile uint16_t *)(mpc8xx_regs-pio.papar) | 0x3000; // PAPAR[12,13]1, 选择SCC2功能 *(volatile uint16_t *)(mpc8xx_regs-pio.padir) ~0x3000; // PADIR[12,13]0, 方向为输入对于RXD或由SCC控制TXD其次为SCC提供时钟。SCC的时钟可以来自几个BRG波特率发生器之一。需要配置SICRSI Clock Route Register来路由时钟源。/* 配置BRG1为SCC2提供时钟 */ mpc8xx_regs-cpm.sicr (mpc8xx_regs-cpm.sicr ~SICR_SCC2_MASK) | SICR_SCC2_BRG1; /* 配置BRG1的分频比产生所需的波特率时钟 */ uint16_t div (BRG_CLK / (16 * desired_baudrate)) - 1; mpc8xx_regs-cpm.brgc1 BRGC_EN | BRGC_COUNT(div);关键参数计算BRG分频比BRGCLK通常是系统时钟经过分频后的一个固定频率。公式为分频值 (BRG输入时钟频率 / (16 * 目标波特率)) - 1。计算出的分频值必须是整数否则会产生波特率误差。需要根据可用的系统时钟和BRG输入时钟选择一个误差最小的分频值。3.2.2 SCC模式寄存器与缓冲区描述符初始化这是配置的核心涉及两个关键寄存器GSMR通用模式寄存器和PSMR协议特定模式寄存器。/* 1. 停止SCC收发进入复位状态 */ mpc8xx_regs-cpm.cpcr mk_cr_cmd(CPM_CR_CH_SCC2, CPM_CR_STOP_TX); mpc8xx_regs-cpm.cpcr mk_cr_cmd(CPM_CR_CH_SCC2, CPM_CR_STOP_RX); mpc8xx_regs-cpm.cpcr mk_cr_cmd(CPM_CR_CH_SCC2, CPM_CR_INIT_RX_TX); /* 2. 配置GSMR-H和GSMR-L */ /* 例如使能收发器正常模式非Loopback时钟来源为BRG异步UART模式 */ mpc8xx_regs-cpm.scc2p.scc_gsmrl GSMR_ENR | GSMR_ENT | GSMR_MODE_UART; mpc8xx_regs-cpm.scc2p.scc_gsmrh 0; // 高位通常用于更高级的协议模式 /* 3. 配置PSMR (UART模式) */ /* 例如8位数据无校验1位停止位 */ mpc8xx_regs-cpm.scc2p.scc_psmr SCC_PSMR_CLEN(8); // 8位字符长度 /* 4. 初始化DPRAM中的SCC2参数RAM */ scc_uart_t *scc2_param (scc_uart_t *)mpc8xx_regs-cpm.dpmem[SCC2_PARAM_BASE]; scc2_param-rfcr RFCR_MOT; // 接收函数码Motorola总线格式 scc2_param-tfcr TFCR_MOT; // 发送函数码 scc2_param-mrblr RX_BUFFER_SIZE; // 最大接收缓冲区长度 scc2_param-rbase (uint32_t)rx_bd_table - (uint32_t)mpc8xx_regs-cpm.dpmem[0]; // Rx BD表在DPRAM中的偏移地址 scc2_param-tbase (uint32_t)tx_bd_table - (uint32_t)mpc8xx_regs-cpm.dpmem[0]; // Tx BD表偏移地址 /* 5. 初始化缓冲区描述符表 */ /* 接收BD环 */ for (int i 0; i RX_BD_NUM; i) { rx_bd_table[i].cbd_bufaddr (uint32_t)rx_buffers[i][0]; rx_bd_table[i].cbd_sc BD_SC_EMPTY | BD_SC_INTRPT; // 初始为空接收完成后产生中断 } rx_bd_table[RX_BD_NUM - 1].cbd_sc | BD_SC_WRAP; // 最后一个BD设置Wrap位形成环 /* 发送BD环初始化类似状态初始为BD_SC_READY */ /* 6. 设置参数RAM中的当前BD指针和计数 */ scc2_param-rbptr scc2_param-rbase; // 指向第一个Rx BD scc2_param-rbdcount RX_BD_NUM; scc2_param-tbptr scc2_param-tbase; scc2_param-tbdcount TX_BD_NUM; /* 7. 使能SCC中断在CPIC中配置 */ mpc8xx_regs-cpm.cpic.cimr | CIMR_SCC2; /* 8. 发送初始化命令启动收发 */ mpc8xx_regs-cpm.cpcr mk_cr_cmd(CPM_CR_CH_SCC2, CPM_CR_INIT_RX_TX);避坑指南缓冲区描述符对齐与“字”访问DPRAM和BD表都必须位于双端口RAM内并且BD的地址必须是4字节对齐的。cbd_bufaddr指向的数据缓冲区可以位于系统内存的任何地方需注意缓存一致性。对BD16字节结构和参数RAM的访问必须使用32位字访问uint32_t *因为CPM的RISC处理器是32位架构它期望数据以字为单位组织。使用8位或16位访问可能导致数据错位和功能异常。3.3 快速以太网控制器FEC与网络驱动对于MPC860EN等型号集成的FEC其驱动开发模式与SCC类似但更接近现代网络设备控制器如DM9000。FEC有自己的MAC层支持MII/RMII接口连接外部PHY芯片。FEC驱动核心流程PHY初始化通过FEC的MII管理接口MDIO/MDC读写外部PHY芯片的寄存器协商速度10/100M、双工模式并启用自动协商。FEC参数RAM设置设置接收/发送描述符环RD/TD的基地址、缓冲区大小、哈希表用于组播过滤、MAC地址等。描述符环初始化与SCC的BD环概念完全一致形成接收环和发送环。启动FEC设置ECNTRL[ETHER_EN]位。中断处理处理接收完成、发送完成、总线错误等中断。在接收中断中遍历接收描述符环将数据包上传给协议栈如lwIP在发送完成中断中释放已发送的数据缓冲区。经验技巧提升FEC性能增大描述符环大小更多的接收描述符意味着能缓冲更多的突发数据包减少因缓冲区不足导致的丢包。使用更大的接收缓冲区将R_BUFF_SIZE设置为一个合理的值如1536字节容纳标准以太网帧加开销避免帧被分割到多个缓冲区减少处理开销。优化中断合并不要每收到一个包就产生一次中断。可以配置FEC在收到多个包或达到一定时间后再产生中断如果硬件支持或者使用轮询模式Polling在高负载时禁用中断由任务定期检查描述符状态。确保缓存一致性与CPM的SDMA一样FEC的DMA引擎直接访问物理内存。必须确保描述符环和数据缓冲区所在的内存区域是非缓存的或者在DMA操作前后正确执行缓存刷新/无效操作。这是FEC驱动稳定性的生命线。4. 系统集成与调试实战指南4.1 内存控制器UPM/GPCM配置与外部存储器连接MPC860的内存控制器非常灵活支持GPCM通用片选机和UPM用户可编程机两种模式来连接各种存储器。GPCM适用于简单的异步设备如Flash、SRAM。通过配置BRx基址寄存器和ORx选项寄存器来设置地址范围、位宽、以及读/写时序如CS到WE的建立、保持时间。时序参数以总线时钟周期为单位。UPM适用于需要复杂、可编程时序的同步设备如SDRAM、FPGA接口。UPM内部有一个RAM数组可以存储一个由用户编写的“微程序”精确控制每个时钟周期上各控制信号CS,WE,OE,GPLx等的电平。这提供了极高的灵活性。连接一片16位宽、型号为AM29LV160D的NOR FlashGPCM模式示例/* 假设Flash连接到片选0CS0地址范围0xFE000000 - 0xFE1FFFFF (2MB) */ /* 1. 配置选项寄存器 OR0 */ /* AT[0:1]00 (GPCM模式), CSNT1 (片选在访问期间有效), ACS01 (地址在CS前半个周期有效) */ /* SCY4 (读访问建立周期为4个时钟) SETA0 (无额外扩展时序) */ /* TRLX1 (使用宽松时序对慢速Flash很重要) EHTR0, EAD0 */ uint32_t or0_value OR_GPCM_CSNT | OR_GPCM_ACS(1) | OR_GPCM_SCY(4) | OR_GPCM_TRLX; or0_value | OR_GPCM_AM_MSK (~((2*1024*1024) - 1)); // 设置地址掩码2MB空间 mpc8xx_regs-memc.or0 or0_value; /* 2. 配置基址寄存器 BR0 */ /* 基地址为0xFE000000端口大小16位使能 */ uint32_t br0_value BR_BA(0xFE000000) | BR_PS_16 | BR_V; mpc8xx_regs-memc.br0 br0_value;关键点时序计算与信号完整性配置ORx时SCY、BSCY等时序参数必须大于等于存储器件数据手册要求的最小时序。例如Flash的tCE片选到输出有效时间为70ns你的系统总线周期为30ns那么SCY至少需要设置为ceil(70/30) 3个周期。此外对于高速总线还需要考虑板级走线带来的延迟和信号完整性有时需要增加一个额外的等待周期SCY加1来保证稳定。4.2 中断系统SIU CPIC管理与优先级处理MPC860有两级中断控制器系统接口单元SIU处理外部硬中断、定时器中断等CPM中断控制器CPIC处理所有CPM内部外设SCC、SMC、SPI、定时器等产生的中断。中断处理流程中断发生如SCC收到一帧数据。CPM内的中断源置位CIPRCPM中断挂起寄存器对应位。如果CIMRCPM中断屏蔽寄存器对应位使能且该中断优先级在CICR中配置为当前最高则CPIC向SIU发出中断请求。SIU根据其自身的SIMASK和SIPEND决定是否向CPU核心触发外部中断异常IVOR4。CPU跳转到外部中断异常向量执行中断服务程序ISR。ISR首先读取CIVRCPM中断向量寄存器其低8位指示了最高优先级的CPM中断源编号。根据向量号跳转到对应的子ISR如scc2_handler。子ISR读取具体外设的事件寄存器如SCCE判断具体事件接收完成、发送完成、错误并清除事件位。处理数据如从BD中取数据并重新武装BD将状态设为空交还给CPM。中断返回。优先级配置经验在CICR中可以将8个CPM中断优先级组如SCC1、SCC2、SCC3、SCC4、SMC1、SMC2、SPI、I2C等分配到两个优先级级别High/Low和不同的子优先级中。网络接收中断如FEC或高速SCC应设置为高优先级以保证低延迟而调试串口SMC UART可以设置为低优先级。避免在同一个高优先级组内放置太多中断源否则它们会相互阻塞。4.3 低功耗模式应用与注意事项MPC860提供了多种低功耗模式Doze、Sleep、Deep-Sleep、Power-Down。通过配置PLPRCR寄存器进入。Doze模式CPU核心时钟停止但外设CPM、SIU定时器等时钟仍在运行。可由外部中断或RTC闹钟唤醒。适用于需要快速响应外部事件的低功耗待机。Sleep/Deep-Sleep更深的睡眠状态更多时钟域被关闭唤醒时间更长。Power-Down模式功耗最低几乎所有内部逻辑都断电仅保留部分寄存器和RTC如果由KAPWR供电。只能通过外部复位或特定的唤醒引脚如果有唤醒。进入此模式前必须妥善保存所有关键上下文到非易失性存储器如Flash因为芯片内部RAM会丢失数据。重要警告KAPWR引脚KAPWRKeep-Alive Power引脚必须连接到一个独立、不间断的电源上即使在主电源VDD掉电时它也需要保持供电通常为3.3V。这个电源用于维持实时时钟RTC、部分配置寄存器和唤醒逻辑的工作。如果KAPWR在系统掉电时也丢失那么所有依赖于它的功能如定时唤醒、保持配置都将失效并且从Power-Down模式唤醒可能无法正常进行。4.4 开发调试技巧与常见问题排查“锁死”与看门狗在开发初期错误的配置尤其是内存控制器和CPM很容易导致系统锁死。务必启用硬件门狗SYPCR[SWTC]或软件看门狗并设置合理的超时时间。在调试段代码时可以暂时禁用它但在最终产品中必须启用。使用BD状态轮询进行调试在中断驱动不稳定时可以先用简单的轮询方式测试外设。例如在发送UART数据时循环检查Tx BD的状态是否从READY变为TX_BD_READY表示发送完成。这有助于隔离是中断配置问题还是BD操作本身的问题。利用GPIO和示波器将某些GPIO引脚配置为输出在代码关键位置如进入/退出中断、开始/结束DMA翻转其电平。用示波器观察这些引脚可以直观地了解代码执行流程和时间关系是调试时序问题和性能瓶颈的利器。CPM命令执行延迟向CPCR写入命令后需要等待命令完成通过检查CPCR的FLG位或等待若干周期才能进行后续操作。特别是INIT_RX_TX这类命令需要一定时间初始化内部状态。立即读写参数RAM或BD可能会导致未定义行为。一个稳健的做法是在发送命令后插入一个小的延迟循环如读取几次CPCR。数据手册版本与勘误务必使用你所使用的具体MPC860型号如MPC860T vs MPC860EN和硅版本Revision对应的最新数据手册和勘误表Errata。不同型号和版本在功能如是否有FEC/ATM和寄存器细节上可能存在差异早期的硅版本可能存在已知的硬件Bug需要通过软件变通方案解决。最后一点体会MPC860是一个功能极其丰富的平台其复杂性要求开发者必须具备系统性的思维。最好的学习方式是从一个简单、可工作的基础代码框架开始例如一个能点亮LED、打印串口信息的Bootloader然后逐个模块地添加和测试功能每步都确保理解其配置的涵义和对系统其他部分的影响。虽然它已是上一代的经典但其“主处理器通信协处理器”的架构思想以及精细的电源、时钟、内存管理对理解现代复杂SoC的设计仍有很高的参考价值。