韩东
(华北计算机系统工程研究所 北京 100083)
在工业应用中,同一系统中常会连接许多不同类型的设备,但因设备的接口不同,嵌入式系统中会涉及到不同接口间的数据透传,比如串口485/232的数据透明传输到以太网接口等。这样的系统中需要建立接口间的数据缓存FIFO,来实现接口的数据接收和发送。
为了通用性,不具体指定接口,而是概念化为实现接口A、B、C、D、W、X、Y、Z间的数据透传处理的数据缓存 FIFO模型。
在缓存建模前先定义几个名词的概念。
考虑透传时接口的分配,即一个接口接收到的数据需要从哪个接口发送出去。为每个接口设定一个发送到接口属性,接口PORT(T)(T指任一接口)的发送到属性值记为DATA_TO(T)。当有 DATA_TO(T)=PORT(V)时,意味着 PORT(T)接收到的数据将由PORT(V)发送,这称为DATA_TO接口映射,简称接口映射。
图1 接口映射Fig.1 Interface mapping
若对于任意 T和任意 V,当 PORT(T)≠PORT(V)时,有DATA_TO(T)≠DATA_TO(V),则称该接口映射为接口单射[3]。
若对于任意 T和任意 V,当 PORT(T)≠PORT(V)时,可DATA_TO(T)≠DATA_TO(V)有,则称该接口映射为接口多射。
若两个接口 T和 V,当 PORT(T)≠PORT(V)时,有DATA_TO(T)=PORT(V)同时 DATA_TO(V)=PORT(T),则称该接口映射为接口T和V对射,称PORT(T)和PORT(V)为一组对射对。
若所有2N个接口既满足单射又满足两两对射[1],则称2N个接口映射为接口一一映射。
如有一个数据序列Q,按序列顺序分为n个序列组Q(n)(n=0,1,...N),当将 Q(n)按 n 的字典顺序(Q(0),Q(1),...Q(N))排列成序列Q’时,满足Q′=Q,称Q(n)为Q的有序序列组。
如果一个数据序列Q在从一个接口PORT(T)接收并按序列组Q(n)写入缓存后,缓存中的存放的序列组Q(n)为Q的有序序列组,则称数据有序接收。
如果缓存中的Q序列组被一个接口PORT(V)发送时,发送出的数据序列组Q(n)为Q的有序序列组,则称数据有序发送。
如果一个数据序列Q在从接口PORT(T)接收后在接口PORT(V)发送出,发送出的数据序列组Q(n)与为Q的有序序列组,则称数据有序收发,简称有序。
如果每次写入或读出操作的缓存对象是直接数据,则称之为无分块缓存;而如果操作对象是一个缓存区的地址,则称之为分块缓存,且该地址指明的是一个缓存块的首地址[2]。
如果一个缓存块,在其使用过程中涉及建立一个新的缓存块。若缓存允许此操作,则称之为可嵌套分块缓存;若缓存不允许此操作,则称之为无嵌套分块缓存。
如果一个分块缓存,每个缓存块的大小固定相等,则称之定长分块缓存;而若每个缓存块的大小可变,则称之可变长分块缓存。
如果一个缓存区只有一个特定接口PORT(T)可以访问和得到使用权,则称之为PORT(T)的私有缓存区,否则如果所有端口都能访问及得到使用权,则称之为公用缓存。
首先构建最精简的FIFO缓存模型,接口单射私有无分块缓存,它仅须实现单字节数据序列的写入和读出操作,无其它特殊要求。
为每个接口PORT(T)建立一个私有的数据FIFO缓存区BUF(T),缓存区大小为SIZE_BUF(T),以辅助 T接口数据的接收和发送操作[4]。
缓存模型建立如下:
1)选定一个连续的RAM地址空间,在此空间上开辟一段大小为SIZE_BUF(T)的连续空间,将此块空间初始化为环形FIFO区作为T接口的缓存区,记作BUF(T)。
2)设置辅助指针T_PUT_POINTER和T_GET_POINTER,及变量 T_BUF_LENGTH。 其中,T_PUT_POINTER指向BUF(T)中下一个可写入数据的地址;T_GET_POINTER指向BUF(T)中下一个可读出的数据的地址;T_BUF_LENGTH为BUF(T)中有效字节数据的数量[6]。
①写入操作
字节数据写入BUF(T)缓存时执行写入操作,首先判断缓存区是否已经写满。缓存区已经写满的标志是T_BUF_LENGTH大小为 SIZE_BUF(T),此时 T_PUT_POINTER与T_GET_POINTER指相同一空间。如缓存已满,则该数据被丢弃。否则,将其写入T_PUT_POINTER指向的空间。同时,T_PUT_POINTER增加一个字节空间,如果增加后超过了BUT(T)的底地址,则T_PUT_POINTER指向其首地址。最后更新T_BUF_LENGTH增加一字节长度[5]。
②读出操作
读出BUF(T)缓存中数据时执行读出操作,首先判断缓存区是否已空。缓存区空的标志是T_BUF_LENGTH大小为0,此时T_PUT_POINTER与T_GET_POINTER指相同一空间。如果缓存已空,则读出无效标志。否则读出T_GET_POINTER指向的空间。同时T_GET_POINTER增加一个字节空间,如果增加后超过了BUF(T)的底地址,则T_GET_POINTER指向其首地址。最后更新T_BUF_LENGTH减少一字节长度[7]。
图2 单字节FIFOFig.2 Single byte FIFO
3)建立好以上缓存区后,为T接口增添数据接收和发送操作函数,其中接收操作映射为缓存区BUF(T)的写入操作,发送操作映射为T的对应接口X的缓存区BUF(X)的读出操作。
考虑接口接收到的字节序列为帧格式报文块,实现其收发有序。
假设一个数据块的接收或发送过程中,没有其它接口数据插入,仍为接口单射私有缓存。这样,在上个模型的基础上建立可分块的缓存组,称作缓存块。
假设各报文块的大小不会超过缓存块的数据容量,且接收报文到一个数据块或发送一个数据块的报文到接口的过程中,没有其它数据块的借出,即缓存块无嵌套。
如此,只需在上节模型基础上将单字节FIFO缓存,替换成缓存块地址的FIFO缓存,实现缓存块的地址取出和存入处理即可。以下将缓存块的取出称为缓存块借出,将缓存块的存入称为缓存块归还。
模型改进如下:
1)将上节缓存中接口PORT(T)的缓存BUF(T)分为N个固定字节长度为BUF_DIV_SIZE(T)的缓存块BUF_DIV(T)。
2)为每个分块添加固定字节长度为HEAD_SIZE(T)的信息头。其中,信息头位于BUF_DIV(T)的起始位的BUF_DIV_HEAD_SIZE(T)个字节的地址空间。信息头依次固定包含分块状态、分块数据长度及下一个分块起始地址。分块数据长度最大为BUF_DIV_SIZE(T)-BUF_DIV_HEAD_SIZE(T),标记为 BUF_DIV_BODY_SIZE(T)。
3)建立两个如上节模型所述的FIFO,将其操作对角由单字节替换成对32位的4字节,辅助缓存块的写入借出、写入归还和读出借出、读出归还操作。设置其中一个FIFO存放还未写入数据的缓存块地址,称为T_FREE_TABLE,另一个存放已经写入数据的缓存块地址,称为T_USED_TABLE。
4)为T_FREE_TABLE添加辅助指针T_FREE_TABLE_P UT_POINTER和T_FREE_TABLE_GET_POINTER,及变T_FR EE_TABLE_LENGTH。T_FREE_TABLE_PUT_POINTER指向下一个可存入要归还的分块地址的FIFO地T_FREE_TABLE_GET_POINTER指向下一个存储着可借出的FREE分块地址的FIFO地址。T_FREE_TABLE_LENGTH指示FIFO中存储的可用FREE空分块地址数据的数量。其借出和归还操作,类同于上节所述的读出和写入操作,不同的是操作的对象现在是FREE分块地址数据,而上节中是单字节数据。现在指针增加或减小1,是指一个缓存块大小。对于整个分块模型来说,T_FREE_TABLE中的借出是指报文的写入前借出,即借出的FREE分块地址用来写入接收来的报文数据分组,以下简称写入借出;T_FREE_TABLE中的归还是指报文的读出后归还,即归还的分块地址是已经完成了其中报文数据分组的读空操作的FREE分块地址,以下简称读出归还。
5)为T_USED_TABLE添加辅助指针T_USED_TABLE_PUT_POINTER和T_USED_TABLE_GET_POINTER,及变量T_USED_TABLE_LENGTH。T_USED_TABLE_PUT_POINTER指向下一个可存入要归还的USED分块地址数据的FIFO地址T_USED_TABLE_GET_POINTER指向下一个存储着可借出的USED分块地址数据的FIFO地址。T_USED_TABLE_L ENGTH指示FIFO中存储的可用USED分块地址数据的数量。对于整个模型来说,T_USED_TABLE中的借出是指报文的读空前借出,即借出的USED分块地址用来读出发送其中的报文数据分组,以下简称读出借出;T_USED_TABLE中的归还是指报文的写入后归还,即归还的分块地址是已经完成了其中报文数据分组的写入操作的USED分块地址,以下简称写入归还。
6)假设完成接口对射组PORT(T)与PORT(X)之间的数据透传。设定接口PORT(T)的接收操作映射到T的缓存区BUF(T),PORT(T)的发送操作映射到接口X的缓存区BUF(X);当接口PORT(T)有数据需要接收时,首先执行写入借出操作,T_FRE E_TABLE中借出一个可供数据写入的FREE缓存块地址,使用该分块地址再执行PORT(T)接收数据的写入操作;写入完成后,执行写入归还操作,将已写入数据的FREE缓存块标志成USED缓存块,并将其地址归还到在T_USED_TABLE中。而需要X接口发送数据时,首先要执行读出借出操作,在T_USED_TABLE中借出一个已经写入了数据的USED缓存块的地址,使用该分块地址去执行PORT(X)的数据读出发送操作,读出完成后,执行读出归还操作,将已经读空了的USED缓存块标志成FREE缓存块,并将其地址归还到T_FREE_TABLE中。
图3 无嵌套传输过程Fig.3 No nested transmitting procedure
现在在上节的基础上设计接口单射有序定长可嵌套分块缓存。可嵌套的意思是在写入借出一个FREE分块后,记作FREE_BUF_0,写入数据过程仍在进行中且还未标志成USED分块,尚未执行写入归还操作前,又需要一个新的写入借出FREE分块,记作FREE_BUF_1。同时后借出的分块FREE_BUF_1会先于FREE_BUF_0执行写入归还操作。归还后FREE_BUF_0标记为USED_BUF_0,而FREE_BUF_1标记为 USED_BUF_1。
这样在相应USED_TABLE表中USED_BUF_1排列在USED_BUF_0前,即执行读出借出时会先借出分块USED_BUF_1,但是要求 USED_BUF_0会先于USED_BUF_1读出借出。在写入数据时因为数据量超过一个分块最大数据长度而会在出现嵌套分块情况。
模型改进如下:
1)在上节模型中为接口PORT(T)的缓存块BUF_DIV(T)的信息头添加上一个新的 32位信息标志USED_LINK_NEXT_DIVBUF,用来存放嵌套时的下一个借出分块地址。
2)嵌套接收操作过程为:接收开始,执行写入借出操作借出第一个FREE_BUF_0,根据需求执行写入借出操作借出第 二 个 FREE_BUF_1并 将 FREE_BUF_0的USED_LINK_NEXT_DIVBUF置为 FREE_BUF_1的地址,如需要第三个 FREE_BUF_2则将 FREE_BUF_1的USED_LINK_NEXT_DIVBUF置为 FREE_BUF_2的地址,以此类推直到最后一个的FREE_BUF_LAST,此时将FREE_BUF_LAST的 USED_LINK_NEXT_DIVBUF置为NULL。当写入数据完成后需要执行写入归还操作时,除了FREE_BUF_0须要执行写入归还之外,嵌套中其它FREE_BUF则不执行写入归还操作。
3)无嵌套接收过程为:接收开始,执行写入借出操作借出个FREE_BUF_0,根据需求不用嵌套分块,这时将FREE_BUF_0的USED_LINK_NEXT_DIVBUF置为NULL。当写入数据完成后执行写入归还操作。
4)发送分块操作过程为:
①发送开始,执行读出借出操作借出第一个USE_BUF_0;
②然后读空其中的数据,并在读出归还操作前读出USE_BUF_0中的USED_LINK_NEXT_DIVBUF值;
③最后执行在读出归还操作。如果USED_LINK_NEXT_DIVBUF值不为空,则利用该值作为下一个USE_BUF,转回到②。如果为空,则结束。
图4 嵌套缓存块Fig.4 Nested cache block
为了节省及更有效率的利用缓存块,可将所有接口的各自私有缓存块公用化。
模型改进如下:
1)取消各自的私用缓存区和FREE_TALBE表,建立公用缓存区和公用FREE_TABLE表[9],指示公用缓存中的空缓存块信息。保留各接口的USED_TABLE表。
2)将各接口的写入借出和读出归还操作合并为对公用FREE_TABLE的写入和读出操作。而写入归还和读出归还操作保留。
3)PORT(T)接收操作变为:执行写入借出操作从公用FREE_TABLE中借出公用FREE__BUF,写入数据后,执行写入归还操作将其放入PORT(T)的私有T_USED_TABLE中。
4)PORT(T)的对射方发送操作变为:执行读出借出操作从公用T_USED_TABLE中借出私有USED__BUF,读空数据后,执行读出归还操作将其放入公用FREE_TABLE中。
多接口间的数据透传如果采用单字节的一收一发,效率不如分块收发。尤其是当所用的接口芯片中自带有硬件缓存时,更是如此,因此分块缓存很有必要。但是在缓存分了块后,还存在着分块容量大小的限制,如果要存下的数据大于一个分块或更多,则可嵌套的分块可以保证接收数据序列间的连续性,特别是在接口多射或是接口还有其它任务时。
[1]沈建华.ARM嵌入式系统开发-软件设计与优化[M].北京:北京航空航天大学出版社,2005.
[2]Reek K A.C和指针[M].北京:人民邮电出版社,2008.
[3]赵亮,候国锐.单片机C语言编程与实例[M].北京:人民邮电出版社,2003.
[4]谭浩强.C程序设计[M].北京:清华大学出版社,1991.
[5]周立功.ARM嵌入式系统基础教程[M].北京:北京航空航天大学出版社,2005.
[6]Labrosse J J.嵌入式实时操作系统μC/OS-II[[M].2版.邵贝贝,等译.北京:北京航空航天大学出版社,2005.
[7]沈建华.ARM处理器与嵌入式系统[J].单片机与嵌入式系统应用,2010(11):5-7.SHEN Jian-hua.ARM processors and embedded systems[J].Microcontroller and Embedded Systems,2010(11):5-7.
[8]Linden P V D.C专家编程[M].北京:人民邮电出版社,2008.
[9]施先旺,王鹏武.发动机工况实时调节软件设计[J].火箭推进,2012(5):70-76.SHI Xian-wang,WANG Peng-wu.Design of real-time regulation software for engine power[J].Journal of Rocket Propulsion,2012(5):70-76.