背景介绍
UCF,User Constraints File,是Xilinx公司用于方便用户指定应用于特定目标器件的数字逻辑设计约束的文本文件。
听起来很复杂?其实定义细想起来不是很复杂,但由于UCF是Xilinx公司提供给用户用来指定如何用FPGA/CPLD实现数字逻辑电路的通用方法,Xilinx公司把好多应用于不同阶段,不同方面的用户约束都统一了进来,其繁杂可想而知。
本身FPGA的实现流程就分为综合,映射,布局,布线,时序优化等等阶段,每个阶段的约束种类又有很多,试想,随着时间的推移,Xilinx公司的用户又会提出更多的需求,需要更多的用户约束类型来支持。
设计难点
明显,UCF解析器的系统架构要考虑到很强的可扩展性。本身我是从零开始,现有的UCF约束就多达上百个,以后还会继续增加。
由于我不仅是把UCF读入系统,还要做相应的检查和映射到内部网表的工作,加上UCF涉及到FPGA实现的方方面面,内部有关约束的存储就不能简单的使用一种类型。
加上UCF系统与整个FPGA实现系统的交互性,就使得UCF解析器的系统架构设计就没有看上去的那么简单。
一成不变的东西比较容易设计成代码,而有可能变化的东西就不会像初看时那么简单。当你把变化的东西当成一成不变的东西实现,刚开始一定又快又好,但随着时间推移,需求变化,噩梦就会到来。
——Gadoop
设计目标
如上文所述,可扩展性是我设计的首要目标,其次,可以和内部系统更好的交互也是我主要考虑的事情。
具体的设计目标如下:
- 当每次要加入新的约束时,新加代码不应很多;
- 大多部分工作应该由架构代码完成,这样新添加的Bug不会过多;
- 抽象层次要分明,高级抽象建立在低级抽象基础上;
- 新加代码只应考虑新加功能,旧有的功能不应重复添加;
- 设计交互方法,使得系统其它模块可以统一快速的访问UCF的约束信息;
- 使得系统其它模块对于UCF系统所知尽量少,耦合度尽量低;
架构设计
UCF系统架构主要分成两个主要的部分:
- 从UCF文件得到有关约束的文本信息,UCFParser;
- 从约束的文本信息构造约束内部存储形式,并映射到内部网表上,ConstraintManager。
这两个部分相对独立,他们之间靠存有UCF文本格式信息的UCFConstraint类沟通。
一般是UCFParser调用ConstraintManager::createConstraintFromUCF(const UCFConstraint& ucf)来构造相应的Constraint类。
数据结构
UCF系统的主要数据结构分为两类:
- 表示原始文本信息的UCFConstraint类,所有UCF约束公用同一个类型,原因是UCF约束格式类似;
- 表示约束内部存储形式的Constraint类及其子类,由于约束类型繁杂,涉及内部网表信息不同,需要存储的数据各异,但又要保持UCF系统对系统内部用户的交互统一,故而采取父类为抽象类,子类依需求扩展的架构。
接口设计
UCF系统的主要接口可以分为两种:
1. 用户接口,提供给用户调用UCF相关命令的接口,如ReadUCF,WriteUCF,CheckUCF等等;
2. 内部接口,提供给内部用户访问相关约束的统一接口,本系统采用的是两类API:一,迭代器,可以遍历特定内部对象的所有约束;二,带类型的特定查询函数,可以快速访问内部用户关心的约束。