有关UCF解析器系统架构的设计

来源:互联网 发布:b站语梨 知乎 编辑:程序博客网 时间:2024/06/03 16:31

背景介绍

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系统架构主要分成两个主要的部分:

  1. 从UCF文件得到有关约束的文本信息,UCFParser;
  2. 从约束的文本信息构造约束内部存储形式,并映射到内部网表上,ConstraintManager。

这两个部分相对独立,他们之间靠存有UCF文本格式信息的UCFConstraint类沟通。

一般是UCFParser调用ConstraintManager::createConstraintFromUCF(const UCFConstraint& ucf)来构造相应的Constraint类。

数据结构

UCF系统的主要数据结构分为两类:

  1. 表示原始文本信息的UCFConstraint类,所有UCF约束公用同一个类型,原因是UCF约束格式类似;
  2. 表示约束内部存储形式的Constraint类及其子类,由于约束类型繁杂,涉及内部网表信息不同,需要存储的数据各异,但又要保持UCF系统对系统内部用户的交互统一,故而采取父类为抽象类,子类依需求扩展的架构。

接口设计

UCF系统的主要接口可以分为两种:
1. 用户接口,提供给用户调用UCF相关命令的接口,如ReadUCF,WriteUCF,CheckUCF等等;
2. 内部接口,提供给内部用户访问相关约束的统一接口,本系统采用的是两类API:一,迭代器,可以遍历特定内部对象的所有约束;二,带类型的特定查询函数,可以快速访问内部用户关心的约束。

流程设计

Created with Raphaël 2.1.0filename.ucfReadUCF parseStatement()UCFConstraint ucfcreateConstraintFromUCF(ucf)Constraint constraintdone?Endyesno

上图为ReadUCF主要的流程图,其中createConstraintFromUCF(ucf)涉及UCF解析器系统架构中最复杂,最核心的设计。下面慢慢道来。

ConstraintManager核心设计

本系统架构的可扩展性和系统层次分明的抽象设计都是有关这个部分的。

抽象封装

Created with Raphaël 2.1.0ConstraintManagerConstraintCreatorConstraintGeneratorConstraintParserTokenizer

上图中上层的类以下层的类为概念基础,一层一层建立起抽象封装。

Tokenizer

Tokenizer其实就是一个有限状态机,在解析字符串之前把各个有效字符的类型(如Word,Separator,WhiteSpace,Invalid等等)设置好,当有限状态机遇到相应字符时,查询得知它的类型并决定状态机的下一个状态。
输入:字符串
输出:有效的字符串(Token)

ConstraintParser

在Tokenizer的基础上我们可以建立用于解析不同字符串的ConstraintParser,如IntegerParser,EnumParser,LocationParser,RangeParser等等。

ConstraintGenerator

在ConstraintParser的基础上,继承自ConstraintGenerator的不同的Generator可以很方便的创建相应的Constraint了。它们知道创建相应Constraint的细节(这里把ConstraintGenerator实现成函数对象,function object,virtual Constraint* operator()(const UCFConstraint&);)。

ConstraintCreator

ConstraintCreator利用UCFConstraint对象中的信息可以准确的知道应该用哪个ConstraintGenerator来实例化一个正确的Constraint出来。这里应用了Observer模式,每个ConstraintGenerator都会事先在ConstraintCreator这里注册,当有相应的UCFConstraint到来时,ConstraintCreator就知道调用哪个ConstraintGenerator了。ConstraintCreator还提供创建Constraint时所需的网表信息。

ConstraintManager

ConstraintManager仅仅作为一个对外的统一访问路径,使用了Singleton模式。ConstraintManager还有Keeper类用于存储创建出来的Constraint对象,并提供查询功能等等。

新约束添加

每当添加新的约束时,只需添加相应的ConstraintParser和ConstraintGenerator,其他的都由UCF解析器系统统一完成。新加入的代码少,相应的Bug也不会很多。

0 0
原创粉丝点击