DC综合之CDC篇

本文围绕FPGA设计中CDC路径的约束展开。介绍了简单同步器、用FIFO隔离CDC等处理跨时钟域路径的方法及对应XDC约束。还对比了全部忽略、使用datapath_only、逐条进行时序例外等约束方案的优劣,并给出top level设置set_max_delay的建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单的同步器:使用set_clock_groups命令就可以了,或者设置成set_flase_path,

但是对于格雷码的同步不行,false_path的优先级最高,很显然这么做会导致所有跨读写时钟域的路径全部不做时序分析,读写指针和相关控制逻辑也就失去了存在的意义。

 

 

之前组内讨论时发现,每回PT工具报出来的STA报告都会有很多异步时钟的path出现violation,这些path都做过CDC同步,因此在function上没有问题,有问题的是对于报出的violation该怎么样设置STA约束。

以前的做法是,对于报出来的path设置multicycle 2,因为既然是异步时钟域,那么就无法确定源寄存器Q端何时有效,designer自然就不能指望目的寄存器一个T内完成采样,设置multicycle必然是合理的但是有时即使multicycle 2也解决不了violation,又得设置得更大,比如multicycle 3。如此迭代,浪费不少时间。于是引发了一个讨论:能不能直接设置false path,一举屏蔽掉这种path的violation。

以下图异步fifo为例:

方框表示寄存器,A域时钟为clka。周期为Ta;B域时钟为clkb,周期为Tb。A域有pointer和data两个信息,B域需要根据A域的pointer(与B域的pointer相比较)来判断fifo中是否有了data,并将data采集到b域。由于A域中的pointer和data共域,所以必然在同一个Ta内ready。但是如果设置flase path,那么STA工具将不对AB域间的组合逻辑时序做任何限制,有可能布线非常长,时序很差,就会带来这样一种可能性:图中的控制path和数据path完全有可能不在同一个Tb内到达B域的寄存器,这样就会出错,比如控制path先到,B域认为fifo有了数据,但是因为数据path非常长,B域采到的是旧的data,而非新写进去的data。

 

CDC的设计与约束
CDC路径在FPGA设计中普遍存在,在设置相应的约束前,必须了解设计中采取了怎样的方法来处理跨时钟域路径。

简单同步器
对于单根跨时钟域路径,一般采用简单同步器(Simple Synchronizer),就是由至少两级CE端和Reset/Clear端接死的寄存器序列来处理。

 

这种情况下,为了更长的平均无故障时间MTBF(Mean Time Between Failures),需要配合一个ASYNC_REG的约束,把用作简单同步器的多个寄存器放入同一个SLICE,以降低走线延时的不一致和不确定性。

set_property ASYNC_REG TRUE [get_cells [list sync0_reg sync1_reg]]

在XDC中,对于此类设计的CDC路径,可以采用set_clock_groups来约束。

 


set_clock_groups -asynchronous -group [get_clocks -include_generated_clocks clk_oxo ] \
-group [get_clocks -include_generated_clocks clk_core ]

用FIFO隔离CDC
在总线跨时钟域的设计中,通常会使用异步FIFO来隔离。根据FIFO的实现方式不同,需要加入不同的XDC约束。

Build-in硬核FIFO
这种FIFO实际上就是用FPGA内部的BRAM来搭建,所有控制逻辑都在BRAM内部,是推荐的FIFO实现方式。其所需的XDC也相对简单,只要像上述简单同步器的时钟关系约束一样用set_clock_groups将读写时钟约束为异步即可。

带有格雷码控制的FIFO
为了在亚稳态下做读写指针抽样也能正确判断空满状态,设计中也常用一种带有格雷码控制的FIFO来实现异步时钟域的隔离。计数器和读写指针等需要用 BRAM外部的逻辑搭建,这样的结构就不能简单约束set_clock_groups,还要考虑这些外部逻辑如何约束。

如下图所示FIFO,在存储器外部有一些用FPGA逻辑搭建的写指针和读指针控制,分属不同的时钟域,存在跨时钟域的时序路径。

 

此时如果仅将读写时钟用set_clock_groups约束为异步时钟,相当于设置从A到B和从B到A的路径全部为false path。根据《XDC约束技巧之时钟篇》所列,false path的优先级最高,很显然这么做会导致所有跨读写时钟域的路径全部不做时序分析,读写指针和相关控制逻辑也就失去了存在的意义。

 

所以建议的做法是不设set_clock_groups约束,转而采用set_max_delay来约束这些跨时钟域路径。以写入侧举例,一个基本的原则 就是约束从cell1到cell2的路径之间的延时等于或略小于cell2的驱动时钟一个周期的值。读出侧的约束同理。

set_max_delay $delay –from [get_cells cell1] –to [get_cells cell2] –datapath_only

如果用户使用Vivado的IP Catalog来产生此类FIFO,这样的XDC会随IP的源代码一起输出(如下所示),使用者仅需注意确保这个FIFO的读写时钟域没有被用户自己的 XDC约束为false path或是异步clock groups 。


set_max_delay -from [get_cells …../rd_pntr_gc_reg[*]] -to [get_cells …../Q_reg_reg[*]] \
-datapath_only [get_property PERIOD $rd_clock]
set_max_delay -from [get_cells …../wr_pntr_gc_reg[*]] -to [get_cells …../Q_reg_reg[*]] \
-datapath_only [get_property PERIOD $wr_clock]

自2013.4开始,Vivado中还提供一个称作methodology_checks的DRC检查,其中包含有对此类异步FIFO的max delay约束与时钟域clock groups约束的冲突检查。

CDC约束方案的对比
CDC路径在FPGA设计中普遍存在,不少公司和研发人员都有自己偏爱的约束方式,这些方式通常有各自适用的环境,当然也各有利弊。

全部忽略的约束
最大化全部忽略CDC路径的约束,即采用set_clock_groups 或是set_false_path对时钟关系进行约束,从而对跨时钟域的路径全部忽略。
示例:set_clock_groups -asynchronous -group clkA -group clkB
优势:简单、快速、执行效率高。
劣势:会掩盖时序报告中所有的跨时钟域路径,容易误伤,不利于时序分析。

使用datapath_only约束
datapath_only是从ISE时代的UCF中继承过来的约束,在XDC中必须作为一个选项跟set_max_delay配合使用,可以约束在时钟之间,也可以对具体路径进行约束。

示例:set_max_delay 10 -datapath_only -from clkA -to clkB

优势:简便、执行效率较高。

劣势:1) 需要特别留意是否设置了过于严格的约束,因为使用者经常会使用较快的时钟周期来约束跨时钟域路径 。2) 注意约束优先级的关系,是否跟设计中其它的约束有冲突。3) set_max_delay而没有配套设置set_min_delay的情况下,同一路径只做setup分析而不做hold分析。

逐条进行时序例外约束
对设计中的CDC路径分组或逐条分析,采用不同的时序例外约束,如set_false_path,set_max_delay和set_multicycle_path等来约束。
示例:set_false_path -from [get_cells a/b/c/*_meta*] -to [get_cells a/b/c/*_sync*]
优势:灵活、针对性好、便于时序分析和调试。

劣势:1) 逐条约束会占用大量时间来调试和分析,效率低下。2) 时序例外的优先级比较复杂,多种时序例外约束共存的情况下,很容易产生意想不到的冲突,进一步增加调试时间,降低效率。3) 这么做极容易产生臃肿的XDC约束文件,而且时序例外的执行更耗内存,直接导致工具运行时间变长。

 

 

 

我觉得如果是top level的话直接设一个set_max_delay就可以了,set_min_delay一般是后端中实现的时候出现的,可以暂时不考虑。具体要怎么设置set_max_delay要看你的specification,如果没有specification,就是想让他尽量快的话可以大致看一下你的关键路径里都有多少东西,根据这个选择一个合适的值。

 

<think>我们遇到了执行ALTER TABLE ... MODIFY 直接修改字段类型为CLOB失败的情况。在达梦数据库中,这种错误通常由以下原因引起: 1. **字段包含约束**:如果原字段存在约束(如主键、唯一约束、外键、检查约束等),直接修改类型会失败。 2. **字段有索引**:如果该字段上建有索引(包括主键索引、唯一索引等),需要先删除索引再修改。 3. **字段被视图或存储过程依赖**:如果该字段被其他数据库对象(如视图、存储过程、函数等)引用,则不能直接修改。 4. **数据不兼容**:如果原字段类型(如VARCHAR)包含的数据长度超过CLOB支持的范围(虽然CLOB很大,但转换规则可能限制)?但通常VARCHAR转CLOB不会出现数据不兼容,除非达梦有特殊限制。 5. **表被锁定**:表正在被其他会话使用。 因此,我们采用更安全的分步操作(即添加新字段->迁移数据->删除旧字段->重命名)来避免上述问题。 具体步骤(考虑约束和索引): 1. 检查原字段上的约束和索引,并记录。 2. 创建临时CLOB字段。 3. 迁移数据(注意:如果原字段有非空约束,新字段也要置为非空,但可以先迁移数据再置)。 4. 删除原字段上的约束和索引(如果存在)。 5. 删除原字段。 6. 重命名新字段为原字段名。 7. 在新字段上重新创建约束和索引。 详细SQL示例: ```sql -- 1. 查询原字段的约束和索引(假字段名为check_result_describe,表名为ipark_job_special_job) -- 查询约束(非空约束、检查约束等) -- 查询索引(包括主键、唯一索引等) -- 2. 添加临时CLOB字段 ALTER TABLE ipark_job_special_job ADD temp_describe CLOB; -- 3. 迁移数据(注意:如果原字段有非空约束,这里需要保证迁移后新字段非空) UPDATE ipark_job_special_job SET temp_describe = check_result_describe; -- 4. 删除原字段上的约束(这里以非空约束为例,其他约束如检查约束需要根据具体名称删除) -- 假原字段有非空约束,我们需要先删除(注意:达梦删除非空约束使用MODIFY COLUMN) ALTER TABLE ipark_job_special_job MODIFY check_result_describe NULL; -- 取消非空约束 -- 5. 删除原字段上的索引(如果有,需要先删除) -- 假该字段有一个索引名为idx_describe -- DROP INDEX idx_describe; -- 6. 删除原字段 ALTER TABLE ipark_job_special_job DROP COLUMN check_result_describe; -- 7. 重命名新字段 ALTER TABLE ipark_job_special_job RENAME COLUMN temp_describe TO check_result_describe; -- 8. 重新添加约束(例如非空约束) ALTER TABLE ipark_job_special_job MODIFY check_result_describe NOT NULL; -- 9. 重建索引(如果有必要) -- CREATE INDEX idx_describe ON ipark_job_special_job(check_result_describe); ``` 注意:在执行之前,务必备份数据,并在测试环境验证。 如果原字段有默认值,还需要在添加新字段时置默认值,或者在重命名后置默认值。 另外,达梦数据库可能对直接修改数据类型有更多限制,分步操作是最稳妥的。 §§相关问题§§ 1. 如何查询达蒙数据库表中某字段的所有约束信息? 2. 达蒙数据库删除字段时是否会自动删除相关索引? 3. 在达蒙数据库中,如何给CLOB类型的字段添加索引? 4. 修改表结构时如何避免长时间锁表导致业务中断? 5. 达蒙数据库是否支持在修改字段类型的同时保留字段注释?</think>### 达蒙数据库修改字段类型失败原因及解决方案 当执行 `ALTER TABLE ipark_job_special_job MODIFY check_result_describe CLOB` 提示"数据类型变更无效"时,常见原因及解决方案如下: **主要原因**: 1. **字段存在依赖对象**(最常见): - 索引:字段上建有普通索引或全文索引 - 约束:字段参与主键/外键/唯一约束 - 计算列:其他字段通过该字段生成计算列 2. **数据不兼容**: - 原字段包含超过32KB数据(VARCHAR默认上限) - 字段包含二进制数据(如文件内容) 3. **表锁定或会话冲突**: - 表正在被其他进程使用 - 未提交的事务持有表锁 **解决方案**: ```sql -- 1. 检查并移除依赖对象(示例) DROP INDEX idx_check_result ON ipark_job_special_job; -- 删除索引 ALTER TABLE child_table DROP CONSTRAINT fk_name; -- 删除外键 -- 2. 安全修改流程 ALTER TABLE ipark_job_special_job ADD temp_col CLOB; UPDATE ipark_job_special_job SET temp_col = check_result_describe; ALTER TABLE ipark_job_special_job DROP COLUMN check_result_describe; ALTER TABLE ipark_job_special_job RENAME COLUMN temp_col TO check_result_describe; -- 3. 重建依赖对象(如有需要) CREATE INDEX idx_new ON ipark_job_special_job(check_result_describe); ``` **关键检查步骤**: 1. 查询依赖关系: ```sql SELECT * FROM ALL_DEPENDENCIES WHERE REFERENCED_NAME = 'IPARK_JOB_SPECIAL_JOB' AND REFERENCED_TYPE = 'TABLE'; ``` 2. 检查字段状态: ```sql SELECT COLUMN_NAME, DATA_TYPE, DATA_LENGTH FROM USER_TAB_COLUMNS WHERE TABLE_NAME = 'IPARK_JOB_SPECIAL_JOB'; ``` 3. 验证会话锁: ```sql SELECT * FROM V$LOCK WHERE TABLE_NAME = 'IPARK_JOB_SPECIAL_JOB'; ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值