从MPC8260ADS板载PLD设计解析嵌入式系统板级控制逻辑实现
1. 项目概述与核心价值
在嵌入式系统,尤其是通信处理器开发板的设计中,如何高效、灵活地管理板上五花八门的控制信号和状态寄存器,一直是个既基础又关键的挑战。十几年前,当我第一次拿到摩托罗拉(后来的飞思卡尔)的MPC8260 PowerQUICC II ADS评估板原理图时,就被其上一片标着“U17”的芯片吸引住了。它不是我们常见的CPU、内存或接口芯片,而是一颗来自Vantis的M4-128/64-7VC可编程逻辑器件。正是这颗PLD,承担了整个板子的“神经中枢”角色,将分散的复位、片选、外设使能、状态指示灯控制等数十个逻辑功能,集成在了一颗芯片里。这份ABEL语言源码,就是这颗“神经中枢”的完整蓝图。
对于硬件工程师和嵌入式开发者而言,直接研读这类厂商提供的PLD设计文件,是深入理解板级硬件工作原理的绝佳途径。它不像阅读芯片手册那样抽象,而是将“地址线A27-A29如何译码出不同的寄存器空间”、“复位按钮的防抖逻辑如何实现”、“JTAG指令如何控制上电复位”这些具体问题,用硬件描述语言直接呈现出来。通过剖析这份MPC8260ADS的ABEL设计,我们不仅能学到如何用PLD实现一个复杂的板级控制与状态寄存器,更能掌握一套应对类似需求的通用设计方法论。无论你是在维护旧有平台,还是设计新的载板,这里面的思路和技巧都极具参考价值。接下来,我将带你逐层拆解这个设计,从顶层框架到每个状态机的细节,并补充大量手册中未曾明说的工程实践考量。
2. 设计框架与PLD选型解析
2.1 系统角色与功能划分
MPC8260ADS板上的这片PLD(U17)被命名为“BCSR & System Control”,顾名思义,它的核心职能分为两大部分:
- 板级控制与状态寄存器:这是一组可通过处理器总线访问的寄存器。处理器通过读写特定的内存地址(由地址线A27-A29译码决定),来查询或控制板上的各种硬件状态。例如,查询SDRAM DIMM的尺寸、控制L2 Cache的使能/刷新/锁定、开关ATM或快速以太网收发器的复位、点亮用户指示灯等。这相当于为软件提供了一个统一的硬件控制面板。
- 系统控制逻辑:这部分是纯组合逻辑或时序逻辑,不直接映射为软件可访问的寄存器,但负责关键的系统级信号生成与处理。主要包括:
- 复位生成与分配:处理硬件复位按钮、软件复位请求,并生成分配到CPU、ATM芯片、以太网芯片等不同设备的复位信号。
- 片选译码与生成:根据地址和配置,生成Flash存储器各bank的片选信号。
- 数据缓冲区控制:在多个总线主设备(如CPU、调试工具)访问共享资源(如Flash)时,管理数据缓冲区的方向使能,防止总线冲突。
- JTAG接口扩展逻辑:在标准JTAG链路上,实现了自定义的指令(如下载、上电复位),用于板级调试和配置。
- 按键防抖与NMI生成:对物理复位和中断按钮进行消抖处理,并据此产生不可屏蔽中断信号。
这种将“可软件配置的寄存器”和“固定的硬件管理逻辑”集成在同一片PLD内的做法,极大地提高了设计的集成度和可维护性。修改一个控制逻辑或增加一个新状态,只需要更新PLD的编程文件,而无需改动PCB布线。
2.2 器件选型:为什么是Vantis M4-128/64-7VC?
原文指出U17使用的是Vantis M4-128/64-7VC。这是一款典型的CPLD。我们分析一下这个型号背后的含义,这有助于理解设计约束:
- M4系列:表明其属于Vantis(后来被AMD收购,其技术融入AMD的CPLD产品线)的中等密度CPLD家族。
- 128/64:通常指宏单元和寄存器的数量。128个宏单元提供了足够的组合逻辑和时序逻辑实现能力;64个寄存器可能指专用的I/O寄存器或触发器资源。对于这个包含多个状态机、译码器和控制逻辑的设计来说,这个规模是合适的。
- 7VC:
7可能代表速度等级(数字越小通常越快),VC可能指封装类型和温度等级。7这个速度等级对于MPC8260(主频可能在一两百MHz)的本地总线操作来说是足够的,因为PLD通常运行在比CPU慢得多的时钟域(如SYSCLK,可能33MHz或66MHz)。
选型背后的工程考量:
- I/O数量:首先看引脚是否够用。从代码中
PIN定义统计,该设计使用了超过90个I/O引脚(包括输入、输出、双向),M4-128的封装必须能提供这么多用户I/O。 - 逻辑容量:设计包含了约10个独立的状态机、大量的组合逻辑译码(地址译码、片选生成)、计数器(数据缓冲区保持计数器)以及一个完整的JTAG状态机。128个宏单元提供了实现这些复杂逻辑的充足资源。
- 时序性能:
7VC的速度等级需要满足最严苛的时序路径。例如,从SYSCLK到寄存器输出(如DataBufEn_B)的延迟,必须满足总线访问的建立/保持时间要求。设计中使用SYSCLK同步所有关键寄存器,就是为了获得确定的时序。 - 功耗与封装:作为板上的“胶合逻辑”,功耗通常不是首要问题,但7VC这类工业级器件能保证稳定的运行。封装形式(如PLCC、TQFP)则决定了焊接和维修的难度。
实操心得:PLD/CPLD选型 checklist当你需要为一款新的处理器平台设计类似“板级控制PLD”时,可以按以下步骤评估:
- 统计信号清单:列出所有需要连接的控制信号、状态信号、中断线、复位线、片选线。区分输入、输出、双向。
- 估算逻辑规模:每个独立的控制位(如一个LED开关)至少需要一个寄存器;每个简单的译码器(如3-8译码器)需要数个宏单元;每个状态机(即使是简单的2状态机)也需要寄存器和组合逻辑。将设计草图中的模块进行资源预估。
- 确定时钟频率:PLD的时钟通常来自处理器的外设时钟或固定的振荡器。明确这个频率,并以此选择能满足该频率下逻辑延时的器件速度等级。
- 预留余量:资源使用率最好不超过80%,为后期调试和功能增加留出空间。I/O引脚数也应预留10%-20%的余量。
- 考虑工具链:ABEL语言虽然经典,但现代开发更多使用VHDL或Verilog。需要确认目标器件是否被当前主流的EDA工具(如Vivado、Quartus、Diamond)所支持,或者是否有可用的ABEL编译器(如早期的Synario、ispLEVER)。
3. ABEL语言设计核心解析
ABEL-HDL是一种早期但非常直观的硬件描述语言,特别适合描述组合逻辑、状态机和简单的时序逻辑。MPC8260ADS的这份设计是ABEL应用的典范。
3.1 模块结构与信号声明
代码以MODULE vbcsr12开始,定义了一个模块。其主体结构非常清晰:
- 引脚声明:使用
PIN关键字定义所有连接到PLD物理引脚的外部信号。例如SYSCLK PIN 11;表示系统时钟连接到第11脚。声明中还使用了istype属性来指定信号类型,如:‘com’:组合逻辑输出。‘reg’:寄存器输出(即有时钟触发)。‘buffer’:输出带反馈(可用于内部逻辑再输入)。‘invert’:输出反向。例如DataBufEn_B PIN 9 istype ‘com,invert’;表示该引脚输出低电平有效(_B后缀也常表示低有效),且内部逻辑生成的是高有效信号,通过invert属性在输出时反相。
- 节点声明:使用
NODE定义内部信号,这些信号不对外引出,仅用于内部逻辑连接。如AtmRst_B NODE istype ‘reg,buffer’;,AtmRst_B是一个内部寄存器,其值会驱动到输出引脚AtmRstOut_B。 - 常量与集合定义:使用
H, L, X, Z = 1, 0, .X., .Z.;定义常量。更重要的是使用集合来简化逻辑描述,例如:
这样,在方程中可以用Add = [A27..A29] ; // 地址线集合 Data = [D0..D7] ; // 数据线集合 ContReg = [PBI, DimmSize, L2Inh_B, ...]; // 控制寄存器位集合ContReg指代整个寄存器,方便进行统一操作。
3.2 地址译码与寄存器访问机制
这是BCSR功能的核心。处理器通过访问特定的内存地址来读写PLD内部的寄存器。PLD通过监听总线事务(地址A27-A29、片选BrdContRegCs_B、数据有效DVal_B、读写R_B_W)来做出响应。
代码中定义了一系列地址译码信号:
VGR_WRITE_BCSR_0 = (!BrdContRegCs_B & !DVal_B & R_B_W & !A27 & !A28 & !A29) ; VGR_READ_BCSR_0 = (!BrdContRegCs_B & !R_B_W & !A27 & !A28 & !A29) ;VGR_WRITE_BCSR_0:当BrdContRegCs_B和DVal_B有效(低电平),R_B_W为高(表示写操作),且地址线A27,A28,A29都为0时,该信号有效。这意味着处理器正在向BCSR0寄存器执行写操作。- 同理,
VGR_READ_BCSR_0对应读BCSR0的操作。
通过A27-A29这三根地址线,该设计定义了8个(2^3)寄存器空间(BCSR0-BCSR7)。其中BCSR0、BCSR1、BCSR6(JTAG相关)是软件可读写的控制寄存器;BCSR2被外部读取(可能连接其他状态输入);BCSR3-BCSR5未在本PLD中实现;BCSR7用于JTAG数据读取。
关键设计技巧:双向数据总线处理数据总线D0..D7被声明为istype ‘com’,这意味着它们是组合逻辑输出。但在读操作时,它们需要驱动数据到总线上;在写操作或空闲时,必须处于高阻态。这是通过.oe(输出使能)方程实现的:
Data.oe = DataOe.fb ; // DataOe有效时,数据总线输出使能 when (VGR_READ_BCSR_0) then Data = ReadBcsr0 ; // 将BCSR0寄存器的值放到数据总线上 else when ...DataOe信号综合了所有可能的读操作条件(读各个BCSR、读JTAG数据、读硬件配置字节),确保在任何时刻只有一个源驱动数据总线,避免冲突。
3.3 状态机设计:控制寄存器的实现
控制寄存器(如PBI,L2Inh_B,AtmEn_B等)的每个位都是一个独立的状态机。这是本设计最精彩的部分。以PBI(Page Base Interleaving,页基址交错)位为例:
state_diagram PBI state PBI_IN_ACTIVE: if (VGR_WRITE_BCSR_0 & (PBI_DATA_BIT.pin == !PBI_IN_ACTIVE) & (!PON_RESET # (PBI_PON_DEFAULT != PBI_IN_ACTIVE)) # (PON_RESET & (PBI_PON_DEFAULT == !PBI_IN_ACTIVE)) ) then !PBI_IN_ACTIVE else PBI_IN_ACTIVE ;这个状态机描述了一个带异步复位和同步写操作的双稳态触发器。
- 状态:
PBI_IN_ACTIVE和!PBI_IN_ACTIVE。 - 状态转换条件:
- 发生对BCSR0的写操作(
VGR_WRITE_BCSR_0)。 - 写入的数据位(
PBI_DATA_BIT.pin,即数据总线D0的当前输入值)等于目标状态的反相。 - 并且,系统不处于上电复位状态(
!PON_RESET),或者上电默认值PBI_PON_DEFAULT不等于当前状态。 - 或者,系统正处于上电复位状态(
PON_RESET),并且上电默认值等于目标状态的反相。
- 发生对BCSR0的写操作(
- 状态保持:如果上述条件不满足,则保持在当前状态。
深入解读设计意图:
- 同步写:状态转换发生在
SYSCLK的驱动下(通过ClockedContReg.clk = SYSCLK ;统一指定),确保了寄存器写入与系统时钟同步,避免了亚稳态。 - 上电复位处理:
PON_RESET信号有效时,状态机被强制恢复到PBI_PON_DEFAULT定义的状态。这是一个非常重要的安全机制,确保板卡上电后处于一个确定的、安全的初始状态(例如,所有外设默认禁用)。 - 条件写保护:逻辑
(PBI_PON_DEFAULT != PBI_IN_ACTIVE)是一个巧妙的设计。它意味着,如果软件试图写入的值与上电默认值相同,而当前状态已经是该默认值,则不会发生状态转换。这可以防止不必要的寄存器翻转,在某些对毛刺敏感的控制线上可能很重要。但更常见的做法是,只要写使能有效,就无条件更新为数据总线上的值。这里的逻辑略显复杂,可能是为了满足特定的功耗或噪声要求。
所有控制寄存器的状态机都遵循此模式,只是对应的数据位和寄存器地址不同。这种模块化、一致的设计极大地减少了错误,也方便了代码的自动生成或脚本化编写。
3.4 复位与中断逻辑详解
复位逻辑是系统稳定性的基石。该设计处理了多种复位源:
- 上电复位:
PORIn_B输入信号,经过同步器S_PORIn_B同步到SYSCLK域,产生内部的PON_RESET信号。此信号用于初始化所有控制寄存器到默认状态。 - 硬件复位按钮:
Rst0和Rst1连接到一个双刀双掷复位按钮的常开和常闭触点。通过一个简单的RS触发器逻辑实现消抖:
这个方程描述了一个防抖电路:只有当RstDeb1 = !( Rst1 & (!( RstDeb1.fb & Rst0) ) ) ;Rst1按下且Rst0释放(或反之)并保持一段时间(通过反馈环路形成延迟),RstDeb1才会稳定变化。AbrDeb1同理用于Abort按钮。 - 复位信号生成:
HardResetEn = RstDeb1.fb & AbrDeb1.fb ;:两个按钮同时按下,使能硬件复位。SoftResetEn = RstDeb1.fb & !AbrDeb1.fb ;:仅复位按钮按下,使能软件复位。NMIEn = !RstDeb1.fb & AbrDeb1.fb ;:仅Abort按钮按下,使能不可屏蔽中断。- 最终的复位输出
HardReset_B和SoftReset_B是开漏输出(.oe使能,输出方程赋值为0),这意味着PLD只能将其拉低,释放后由上拉电阻拉高,这是一种标准的复位驱动方式。
- 复位分配:像
AtmRstOut_B这样的外设复位信号,是内部寄存器AtmRst_B和全局硬件复位HardReset_B的“或”逻辑。这意味着无论软件通过寄存器控制复位,还是按下硬件复位按钮,都能复位外设。
注意事项:复位同步的重要性注意代码中对HardReset_B输入的处理:
SyncHardReset_B := HardReset_B ; DSyncHardReset_B := SyncHardReset_B.fb ;这里用了两级触发器进行同步,将异步的复位输入信号同步到SYSCLK时钟域,产生DSyncHardReset_B。这是防止亚稳态的标准做法,至关重要。后续许多逻辑(如数据缓冲区使能控制DataBufEn_B)都使用同步后的DSyncHardReset_B.fb作为条件,确保在复位撤离过程中,内部逻辑能有一个稳定、无毛刺的参考信号。
3.5 数据缓冲区使能与防冲突机制
这是设计中一个非常精妙且实用的部分,解决了多主设备总线访问的冲突问题。在MPC8260ADS板上,处理器(MPC8260)和外部调试工具(通过ToolCs1_B,ToolCs2_B)都可能访问Flash、BCSR等资源。它们共享数据总线,因此需要数据缓冲区来隔离。
核心逻辑:
!DataBufEn_B = ( !FlashCs_B # !BrdContRegCs_B # !AtmUniCsOut_B # !ToolCs1_B # !ToolCs2_B) & (!BUFFER_HOLD_OFF) ;这个方程的意思是:当任何一个片选信号有效时(!FlashCs_B等为真),就使能数据缓冲区(!DataBufEn_B输出低,因为invert属性)。但是,有一个附加条件:!BUFFER_HOLD_OFF。
为什么需要BUFFER_HOLD_OFF?考虑这个场景:CPU刚结束一个Flash读周期,FlashCs_B变高,DataBufEn_B本应立刻关闭缓冲区。但如果关闭得太快,而Flash芯片的数据还停留在总线上(总线保持时间),就可能与下一个即将访问总线的设备(比如调试工具)发生短暂冲突。为了避免这个“总线争夺窗口”,设计了一个保持计数器HoldOffCnt。
保持计数器工作原理:
when ( ((END_OF_FLASH_READ # END_OF_ATM_READ ) & (HoldOffCnt.fb == 0)) # (HoldOffCnt.fb != 0)) & !HoldOffTc.fb & DSyncHardReset_B.fb ) then HoldOffCnt := HoldOffCnt.fb + 1 ; else HoldOffCnt := 0 ;END_OF_FLASH_READ:定义为一个Flash读周期结束的时刻。- 当一次Flash或ATM读周期结束,或者计数器已经在计数(
HoldOffCnt.fb != 0)时,计数器开始递增。 - 计数器计到3(
HoldOffTc = (HoldOffCnt.fb == 3))时停止。 - 在计数器非零期间(
BUFFER_HOLD_OFF为真),DataBufEn_B保持有效,从而将数据缓冲区多使能几个时钟周期,覆盖掉总线冲突的风险期。 - 一旦计数器达到终值或没有读周期结束,计数器归零,
BUFFER_HOLD_OFF解除,DataBufEn_B可以随片选信号正常关闭。
这个简单的计数器实现了一个精确的“总线保持”时序,是硬件设计中解决时序竞争问题的经典案例。
3.6 Flash片选译码与硬件配置读取
MPC8260ADS板支持不同容量的Flash存储器(8MB, 16MB, 32MB),通过F_PD[4:1]引脚(可能是硬件跳线)来配置。PLD需要根据这个配置和访问的地址(A7, A8),译码出正确的Flash bank片选。
SM73228XU1 = (F_PD == 2) ; // 1 X 8 MByte bank SM73248XU2 = (F_PD == 1) ; // 2 X 8 MByte banks SM73288XU4 = (F_PD == 0) ; // 4 X 8 MByte banks FLASH_BANK1 = ( SM73228XU1 # (SM73248XU2 & !A8) # (SM73288XU4 & !A7 & !A8) ) ;这段组合逻辑定义了Flash bank1的片选条件。例如,当配置为4x8MB(SM73288XU4)时,FLASH_BANK1在地址A7=0, A8=0时有效。其他bank的片选逻辑类似。
硬件配置字节读取: 这是一个隐藏的高级功能。在系统硬复位期间(HRESET_B有效),MPC8260处理器会从Flash的特定地址读取配置字(CfgByte0-CfgByte3),用于设置自身的时钟模式、总线选项等。PLD需要在此特殊时期,将正确的配置数据放到数据总线上。
FIRST_CFG_BYTE_READ = (!FlashCs_B & !DSyncHardReset_B.fb & (ConfAdd == 0) & !HRESET_CFG_IN_FLASH & !R_B_W); ... when (FIRST_CFG_BYTE_READ) then Data = CfgByte0;ConfAdd是[A27, A28],在硬件复位配置周期,处理器会按顺序访问地址0x0, 0x1, 0x2, 0x3(相对于某个基址)。PLD检测到这个特殊的访问(!FlashCs_B, 复位期间!DSyncHardReset_B.fb, 读操作!R_B_W),并根据ConfAdd的值,将预定义的CfgByte0-3驱动到数据总线上。CfgByte的内容(如是否启用L2 Cache)通过@ifdef L2CACHE预处理指令进行条件编译,从而为带L2 Cache和不带L2 Cache的板卡版本生成不同的配置文件。
3.7 自定义JTAG指令实现
标准的JTAG接口用于芯片边界扫描测试。但此设计在PLD内部实现了一个扩展的JTAG状态机,支持自定义指令,这为板级调试和制造测试提供了强大工具。
JTAG状态机:代码实现了一个完整的、符合IEEE 1149.1标准的TAP(测试访问端口)状态机。状态转移由TMS信号在TCK上升沿控制。这个状态机是固定的,与具体功能无关。
自定义指令:在JTAG_SHIFT_IR(移位指令寄存器)状态,PLD接收3位的指令码。设计定义了:
INST_CODE_BYPASS (7):旁路指令,数据直接移位通过。INST_CODE_EXTEST (0):边界扫描测试(可能未完全实现)。INST_CODE_DOWNLOAD (1):下载指令。这是关键。当此指令被锁存到JtagIR寄存器后,在JTAG_SHIFT_DR状态,通过TDI移入的数据会被存入一个8位的移位寄存器JtagShiftDR。当移位完成退出JTAG_EXIT1_DR状态时,会置位JtagReceiveFull标志。INST_CODE_PON_RESET (6):上电复位指令。当此指令有效时,会驱动PonResetOut引脚为高,可以触发一个板上电复位序列。
与处理器总线的交互:最巧妙的地方在于,JTAG移位寄存器JtagShiftDR被映射到了处理器的内存空间(通过READ_JTAG_DOWNLOAD_DATA,即读BCSR7寄存器)。这意味着:
- 调试主机可以通过JTAG接口,向PLD的移位寄存器写入一个字节的数据。
- 运行在MPC8260上的软件,可以通过读取
BCSR7寄存器,来获取这个字节。 - 这实现了一条从外部JTAG调试器到目标系统软件的通信通道。可以用于预引导加载、传递加密密钥、设置调试标志等,无需占用传统的串口或网络接口。
安全与使能控制:JTAG扩展功能由一个控制位JtagEn管理。只有当JtagEn寄存器被软件使能后,自定义的JTAG指令(如DOWNLOAD, PON_RESET)才会被执行。这防止了未经授权的JTAG访问对系统造成干扰。
4. 从ABEL到实现:设计流程与验证要点
4.1 典型ABEL设计流程
- 需求分析与逻辑设计:根据硬件原理图和数据手册,列出所有需要PLD实现的信号和逻辑功能,绘制出状态转移图和逻辑框图。MPC8260ADS的这份ABEL代码本身就是这个阶段的输出。
- ABEL编码:使用模块化方法编写代码。先进行引脚和节点声明,再定义常量和集合,最后编写方程和状态机。良好的注释(如原代码中的
Ò)至关重要。 - 功能仿真:使用ABEL开发工具(如早期的ISP Synario System)中的仿真器。需要编写测试向量文件(
.abv),模拟各种场景:上电复位、寄存器读写、JTAG指令操作、复位按钮按下等,验证输出是否符合预期。 - 编译与适配:编译器将ABEL代码转换为针对目标器件(M4-128/64)的熔丝图或JEDEC文件。这个过程会进行逻辑优化、引脚分配、时序分析。
- 时序仿真:使用适配后生成的时序模型进行仿真,考虑实际的布线延迟。确保建立/保持时间满足要求,特别是像
DataBufEn_B这样的关键控制信号。 - 编程与测试:将JEDEC文件烧录到PLD中。将芯片焊接到板上,进行实际硬件测试。通常需要结合逻辑分析仪和处理器调试器,观察关键信号波形。
4.2 关键验证场景与测试向量构思
对于这样一个复杂的设计,全面的测试向量是成功的保证。以下是一些必须测试的场景:
场景一:上电复位与默认状态
// 测试向量示例 (伪代码) test_vectors ([PORIn_B, SYSCLK, ...] -> [PBI, L2Inh_B, HardReset_B, ...]) // 初始状态,上电复位有效 [0, .C., ...] -> [PBI_PON_DEFAULT, L2CACHE_INH_PON_DEFAULT, 0, ...]; // 释放上电复位,时钟跳变 [1, .C., ...] -> [PBI_PON_DEFAULT, L2CACHE_INH_PON_DEFAULT, 1, ...];验证所有寄存器位是否被正确初始化为*_PON_DEFAULT定义的值,复位信号是否在适当时候释放。
场景二:BCSR寄存器读写模拟处理器写BCSR0地址,数据总线为0x55,再读回。
// 设置地址、片选、写信号 [A27=0,A28=0,A29=0, BrdContRegCs_B=0, DVal_B=0, R_B_W=1, D=0x55] -> [Data.oe=0]; // 写周期,PLD采样数据 // 释放写信号 [... R_B_W=X, DVal_B=1 ...] -> [PBI, DimmSize, ... 应根据0x55更新]; // 发起读操作 [R_B_W=0, DVal_B=0] -> [Data.oe=1, Data=ReadBcsr0]; // 应输出0x55场景三:复位按钮防抖与NMI生成模拟Rst1和Abr1按键的抖动序列,验证HardResetEn,SoftResetEn,NMIEn只在按键稳定按下后产生,且NMI_B输出符合预期。
场景四:Flash访问与数据缓冲区保持模拟一个Flash读周期,在DVal_B撤销后,用逻辑分析仪或仿真检查DataBufEn_B信号是否保持了额外的几个SYSCLK周期(由HoldOffCnt控制)。
场景五:JTAG自定义指令编写JTAG测试序列:
- 进入
SHIFT-IR状态,移入INST_CODE_DOWNLOAD (001)。 - 进入
UPDATE-IR状态,更新指令寄存器。 - 进入
SHIFT-DR状态,移入8位数据(如0xAA)。 - 退出
SHIFT-DR,检查JtagReceiveFull是否置位。 - 通过仿真处理器读
BCSR7,验证数据是否为0xAA。
4.3 常见问题与调试实录
在实际将此类设计部署到硬件时,会遇到一些典型问题:
问题1:上电后系统无法启动,处理器读不到配置字。
- 排查思路:
- 检查
PORIn_B信号是否正常产生并输入到PLD。 - 用示波器测量
HardReset_B输出,看复位时序是否正确(应有足够低电平时间)。 - 在复位期间,测量
FlashCs_B和地址线A27, A28,看处理器是否发出了配置读周期。 - 测量PLD的
Data总线在配置读周期是否有输出。如果没有,检查FIRST_CFG_BYTE_READ等逻辑条件是否满足。重点检查HRESET_CFG_IN_FLASH信号(来自外部开关FlashConfEn_B),它决定了是从PLD还是从Flash本身读取配置。
- 检查
- 可能原因:
DSyncHardReset_B同步信号不正常,导致配置读条件永远不成立;CfgByte定义错误;Flash片选译码逻辑FLASH_BANK1等与实际的Flash型号不匹配。
问题2:通过JTAG下载数据后,软件读到的值不正确。
- 排查思路:
- 确认
JtagEn寄存器已被软件正确写入使能。 - 使用逻辑分析仪抓取
TCK,TMS,TDI,TDO波形,对照JTAG状态机图,确认自定义指令INST_CODE_DOWNLOAD被正确加载。 - 检查在
JTAG_SHIFT_DR状态下,TDI上的数据是否被正确移入JtagShiftDR寄存器。注意JTAG通常是MSB先移。 - 检查
READ_JTAG_DOWNLOAD_DATA译码逻辑是否正确,确保软件读BCSR7时,PLD确实驱动了JtagShiftDR的值到Data总线。
- 确认
- 可能原因:JTAG状态机实现有误;移位方向弄反;
JtagReceiveFull标志置位/清除逻辑与读操作不同步。
问题3:同时访问Flash和调试工具时,系统挂起或数据错误。
- 排查思路:
- 重点检查
DataBufEn_B和ToolDataBufEn_B的时序。用双通道示波器同时测量FlashCs_B(或ToolCs1_B)和DataBufEn_B。 - 观察
DataBufEn_B在片选无效后,是否有一个短暂的“保持”阶段(对应HoldOffCnt计数)。如果没有,说明保持计数器逻辑未工作,可能导致总线冲突。 - 检查
HoldOffCnt的计数逻辑,确认END_OF_FLASH_READ等信号定义是否正确捕捉到了读周期结束边沿。
- 重点检查
- 可能原因:
SYSCLK频率较高,而HoldOffCnt的计数值(3)对应的保持时间不足;多个片选同时有效(理论上不应发生)导致DataBufEn_B行为异常。
问题4:修改ABEL代码后重新编程,个别功能失效。
- 排查思路:
- 首先进行完整的时序仿真。检查编译器报告中的时序摘要,看是否有路径不满足要求。增加
SYSCLK的周期约束后重新编译。 - 检查编译器是否进行了过度优化。对于关键的控制信号(如
HardReset_B),可以尝试在方程中使用keep属性(如原代码中RstDeb1 NODE istype ‘keep,com’;)阻止优化器将其优化掉。 - 回顾引脚分配。有时编译器为了布线方便会改变引脚分配,如果某个关键输入信号被分配到了器件边缘有较大延迟的引脚,可能导致时序问题。可以手动锁定关键信号的引脚。
- 首先进行完整的时序仿真。检查编译器报告中的时序摘要,看是否有路径不满足要求。增加
- 经验之谈:对于CPLD设计,在资源允许的情况下,适当增加流水线或寄存器打拍,是解决时序问题的有效手段。例如,将某些复杂的组合逻辑输出用寄存器暂存一个周期。
5. 设计演进与现代实现思考
这份基于ABEL和M4 CPLD的设计是早期嵌入式系统设计的典型代表。今天,我们有了更多选择:
- 语言演进:VHDL和Verilog已成为工业标准,它们支持更复杂的行为描述、层次化设计和可综合的子集。现代工具链(如Xilinx ISE/Vivado, Intel Quartus)对它们有更好的支持。
- 器件演进:CPLD逐渐被更大容量、更低功耗的FPGA所取代,甚至很多简单的“胶合逻辑”功能可以被集成到CPU本身的CPLD模块中(如一些SoC的“系统控制单元”),或者用低成本的微控制器(MCU)通过GPIO模拟逻辑来实现,灵活性更高。
- 实现方式:
- 纯FPGA/CPLD:对于高性能、高实时性要求,仍是首选。可以用Verilog重写本设计,利用现代仿真工具进行更彻底的验证。
- CPLD + 软件:将一些不要求纳秒级响应的控制功能(如LED灯、部分复位控制)移到软件中,通过CPU的GPIO控制,简化PLD逻辑。
- 专用电源管理IC:对于复杂的上电时序、复位分配,现在有专门的电源管理芯片可以处理,比用通用逻辑更可靠。
然而,无论技术如何变迁,这份ABEL代码所体现的设计思想——清晰的模块划分、严谨的同步设计、对总线冲突和时序余量的充分考虑、为调试留出后门——始终是硬件工程师的宝贵财富。当你下次面对一个需要集成多种控制功能的载板时,不妨在画原理图之前,先像这样写一份“硬件控制清单”,思考哪些用离散逻辑,哪些用可编程逻辑,哪些交给软件。这份MPC8260ADS的PLD设计,就是一个近乎完美的范本。
