摘要

网络编码改变了传统网络节点上路由器交换和交换机对信息流“存储—转发”的模式,提出网络路由交换节点对输入的信息流编码后再发送,并在接收器上进行解码,从而还原信息。随着网络编码理论的日益发展和完善,其应用的研究也越来越受到重视。

 

本文首先介绍网络编码理论的基本概念,回顾了近年来网络编码的研究动态。接着指出研究多信源网络编码组播通信的重要性,在使用NetFPGA开发平台的基础上,提出网络编码组播通信系统及其整体设计方案。在方案中重点介绍了硬件系统中采用的编码策略—随机线性编码,解码策略、算法以及通信协议,同时介绍了系统的软硬件接口和软件作用。最后,给出了编码路由器、转发路由器以及解码路由器三个系统的详细设计方案,方案中主要包括单元模块图,每个模块的主要功能与结构,数据处理流程及算法说明,输入输出信号及说明、关键时序或状态。

 

由于本系统的主要功能是由硬件实现,所以和传统组播通信网络相比,具有时延小,没有了调度和排队时间,使得网络中链路负载更均衡,体现出了网络编码的优势。

 

1 网络编码理论及相关研究应用背景

1.1网络编码理论产生背景和基本概念

60年前C.E.Shannon发表“通信数学原理“解决了信道容量极限问题。2000年诞生的网络编码(Network Coding:NC)是继此后的一个全新突破,它解决了网络通信中单/多源对多接收点组/广播如何达到网络容量极限的问题。传统网络通信节点上的路由交换机只完成存储转发功能。NC指出如果允许路由交换机对输入信息流进行编码再发送,使得网络节点既实现路由功能又实现编码功能。在这种全新的体系结构下,网络性能可以达到最大流传输的理论极限[1][2]。


2000年,以香港中文大学信息工程系为主的研究人员针对通讯网络的瓶颈问题,提出了一种看似疯狂的想法,这种具有革命潜力的方法名为网络编码,以网络编码器取代路由器;原本只是单纯的传送信息的路由器,换成编码器之后,传送的却是有关信息的证据,而不是信息本身;当接收器收到证据时,即可结合各项线索,推导出原始信息。[3]


《科学美国人》杂志(Scientific American Magazine)2007年6月,以“Breaking Network Logjams”(打破网络僵局)为题刊登了MIT科学家详细介绍了7年前诞生于香港中文大学的网络编码理论[4]。其中指出,网络编码是继60年前C.E.Shannon发表“通信的数学原理”后,网络通信理论的一个全新突破。C.E.Shannon解决了点对点信道的容量极限问题,而NC解决了如何达到单源对多点及多源对多点的网络通信容量极限的问题[4]。传统网络通信理论把信息流当成管道中流动的水,是不可压缩的;故传统网络节点上的路由交换机只是完成存储转发功能。NC理论的划时代意义在于:提出网络路由交换节点对输入的信息流进行编码再发送,可进一步提升网络吞吐量!从而改变了比特不能再被压缩的经典结论,指出网络信息流可以被压缩。


网络编码最简单的概念来自‘蝴蝶网’,如图1.1-1所示:

图1.1-1 网络编码的基本原理

图1.1-1 网络编码的基本原理              

          

上图所示的网络中,源节点S1想把信息流ai传送给R1和R2。另一方面,源节点S2也希望在相同时间、以相同速度,把信息流bi传送给同样的接收节点R1和R2。假设每个路径每秒可携带一个位元,而且只能顺着箭号所指的方向前进。如果路由器只传输其所接收到的信息,那么中间链路将是个瓶颈,因为每秒总共接收到二位元的资料,但其容量只有一位元,路由器每秒只能传送一位元资料给中间链路,这种瓶颈会造成可怕的塞车。相反,如果把一般的路由器换成编码器,它可以把两个信息通过异或或者线性组合运算成单一位元输送给中间链路,并且发送ai+bi (或者ai和bi的任意线性组合),这样就轻而易举地解决了塞车问题[3][5]。

 

网络编码另一个与路由系统不同之处在于,充分利用网络资源。图1中,S1透过路径S1R1把ai传给R1,S2透过路径S2R2把bi传给R2,这在路由系统中是不会使用到的。节点R1接收到ai,并且根据每次编码器运算结果,输入到与编码器使用的相同函数(异或或者线性组合)内,推导出bi。节点R2解出ai也是同样的道理。重复对每个位元字串进行相同的流程,最后就能得出两个原始信息。

 

可见,有了网络编码,网络的运作可望变得更有效率(不需要增加硬件设备或频宽,就可以提高网络吞吐量),可以改善网络的负载均衡,节省网络带宽消耗,节省无线网络的能量消耗,提高了网络的鲁棒性,同时对于具有链路时延的网络,相对于路由方式,通过网络编码进行多播传输时可以获得较小的传播时延[6][7]。


随后,李硕彦等在证明了在足够大的有限域内,通过节点内进行线性网络编码(Linear Network Coding: LNC)就可以达到网络组播,广播等的理论上限[8]。在线性范围内解决达到理论上界的问题为NC进入实际应用奠定了坚实的基础。随后,Yueng,李硕彦[9]等出版了国际上第一本网络编码理论专著“Network Coding Theory”。


 Koetter等[10]于2003年提出将NC问题与多项式方程建立数学联系,使得讨论NC问题又多了一种有力的数学工具代数理论;LNC针对于已经了解整个网络拓扑状况的情况下,经过网络路由设定,通过确定的矩阵计算公式对报文进行编解码,实现简单,但适应性和容错性较差。论文[11]中提出随机网络编码概念(Random Network Coding:RNC),与线性编码结合在一起,使得分布式的、简单实用的网络编码体系形成。随机线性网络编码是一种分布式算法,编码在有限域上进行,系数随机选取,其灵活性远大于LNC。


下面给出一个不仅NC提高多播网络吞吐量,而且显著改善网络负载均衡的例子。图1.1-2(a)显示了网络的容量,所有的边的容量都是2。在这个例子中,最大流是4。图2(b), (c)和(d)分别显示了单会话IP组播,多会话IP组播和基于网络编码的组播的分配树。在图2(b)中,发送端通过一个组播分配树同时向接收端R1, R2和R3发送了两个比特a,b。在图2(c)中,组播会话1,2和3分别向接收者发送了比特a,b和c。需要指出的是多会话IP组播所有的会话不是拥有同一个分配树。在图2(d)中,发送端同时向接收端R1, R2和R3发送了四个比特a,b,c和d[12]。

所有的组播技术中网络编码可以达到最高的吞吐量,因为它可以最大流发送信息。我们看到在图2(b), (c)和(d)中在单位时间内接收端分别接收到2,3和4比特。因此在这个例子中,基于网络编码的组播的吞吐量是单会话IP组播的2倍,多会话IP组播的1.3倍。

 

通过比较基于网络编码的组播和现在的组播来研究负载均衡的影响。假定基于网络编码的组播使用图2(d)例子中的容量的一半。在这种情况下,单会话IP组播和网络编码都在单位时间内向所有的接收端发送了2比特。在图2(b)中,通过了网络中9条链路(总共发送10比特)中的5条来传输2比特,另外4条没有使用。另一方面,当网络编码使用时,2( d) 通过了9条链路(总共发送9比特)来传输2比特。于是通过应用网络编码,流量负载可以分散在整个网络上。

 

               (a)链接容量               b)单会话的IP组播

     (a)链接容量                         (b)单会话的IP组播

                 (c)多会话的IP组播             (d)网络编码组播

(c)多会话的IP组播                           (d)网络编码组播

图1.1-2 网络编码提高网络容量,同时均衡了网络流量

 

1.2国内外研究动态与现状

网络编码自诞生以来,普及性的急速增长就连其奠基者也始料未及。从2005年开始每年一次的NetCod workshop 得到了Microsoft, Qualcomm等机构的资助。短短几年,发表了几百篇学术论文。这个崭新的领域对许多相关学科产生了深远的影响,NC的理论研究范围包括信息论及通信的几乎每个领域,如线性编码,非线性编码,随机编码,静态码,卷积码,群码,Alphabet码,码构建,算法协议,有环网络,无向网络,链路失效及其网络管理,分离理论,错误检测和纠错码,密码学,多信源编码,多-单播编码, Cost Criteria, 非均匀需求,关联信源编码,最大流/刮集界,叠加编码,网络互连,路由寻找,无线及卫星网络,Ad hoc网络,传感网络,数据存储及分布,矩阵理论,复杂性理论,图论,随机图论,树装箱(Tree Packing),多种物流(Multicommodity flow),游戏理论,矩阵胚理论(Matriod theory),信息论不等式,排队论分析,率失真(rate-distortion)可逆网络,多用户信道,联合网络信道编码,P2P网络等[13]。


国外多所著名大学如普林斯顿大学、麻省理工、瑞士EPFL 学院等和多家IT 公司的研究中心,包括微软研究院、贝尔实验室、AT &T 的香农信息实验室等都在积极开展对网络编码理论和应用的研究。与此同时,网络编码的实际应用问题被提到技术研究的前线。从2005年第一届Net Cod国际会议上就明确将NC在现实通信中的应用作为研究的重点。微软公司是最早开展网络编码应用研究的公司[14],Microsoft公司已经采用网络编码作为其下一代网络内容发布平台Avalanche的核心技术。


不仅国外,近两年来国内学者也开始研究网络编码。清华大学[15],西安电子科大、及电子科技大学[16],北京邮电大学[17]均投入了NC与无线网络方面的研究。NC在P2P网络传输,流媒体广播及内容分发方面的应用方面,上海大学[18]、湖南大学[19]和并行与分布处理国家重点实验室[20],中国科学技术大学[21]等都进行了研究。最近几年中,网络编码在组播通信方面的应用成为了研究的热点,复旦大学研究了单信源组播并提出了一项关于在目前internet路由器上实现网络编码的专利[23],西安电子科技大学提出了一种基于网络编码的组播路由算法,能够大大降低网络资源消耗,同时能改善负载均衡[24]。

 

以上网络编码在通信中的应用研究基本上都是处于理论和计算机软件仿真阶段,在用硬件平台搭建实际的组播网络,并在真实的网络环境中应用网络编码,进行其实现的复杂度和网络性能的评估等方面的研究尚处于起步阶段。

2 多信源组播系统结构及整体设计方案

2.1项目研究需求、目标和内容

网络编码能够提高网络吞吐量,提升鲁棒性、安全性等网络性能。具有网络编码功能的路由器是未来网络发展的趋势。组播通信在网络通信中有重要的作用,事实上,任何一个网络都可以认为是组播网的一个特例。然而,目前在世界上研究网络编码在组播上的应用大多集中在单信源组播方面,例如,单信源多信宿网络如何达到最大传输速率问题[25],基于网络编码的组播路由算法和性能评估[26], 基于网络编码的组播通信网络的拓扑设计[27], 多信源随机线性网络编码在组播通信的研究[28]以及单信源组播网中编码节点的研究[29],以上研究都是以软件仿真为主,没有形成实际的硬件平台和系统。

 

多信源组播的应用非常广泛,如P2P内容分发网络等。事实上,任何一个网络都可以作为多信源组播的一个特例,因此研究多信源组播是有意义且必要的。

 

本项目的主要研究目标是基于网络编码的多信源组播系统的实现。在基于国内外网络编码理论在组播通信中的最新研究成果和技术,对网络编码理论进行深入学习和探讨,提出一种基于网络编码的多信源组播系统和网络,然后依据此系统设计出可实现组播的通信协议和相关算法,再利用开放式的网络设计硬件平台NetFPGA[30],使提出的协议和算法在硬件上实现,最后在实际的环境中用若干电脑和NetFPGA组成一个小型组播通信网络进行系统测试和性能评估。

 

2.2  NetFPGA——新一代开放式网络研究平台简介

由斯坦福大学开发的NetFPGA是一个基于Linux操作系统的可重用开放性硬件平台,允许用户在实验室内搭建高性能的网络模型进行仿真和研究。它具有以下特点[31]:

 

(1)很好地支持模块化设计,它可以使研究人员在硬件上搭建Gb/s高性能网络系统模型。(2)NetFPGA是一个基于Linux系统的开放性平台,可以利用平台上现有的资源,在前人开发的基础上添加自己的模块和修改现有的系统,而不需要重复地搭建外围模块、开发驱动和GUI等,大大减轻了网络研究的任务。

 

NetFPGA的硬件主要包含了4个1Gb/s的以太网接口(GigE),一个用户可编程的FPGA,以及两片SRAM和一片DRAM。NetFPGA开发板通过标准的PCI总线接口连接到PC机或服务器,模块框图如图2.2-1所示。

 

图 2.2-1:NetFPGA平台的组成框图

 

在外部硬件接口方面,除了连接PC主机的PCI总线插口,一个Broadcom公司的物理层收发器(PHY)包含了四个千兆位以太网接口,板子上的两个SATA连接口使得系统内部的多个NetFPGA可以通过SATA数据线连接起来,互相之间直接以很高的速度交换数据,而不必再通过PCI总线。NetFPGA通过PCI总线与主机CPU连接,提供了硬件加速的数据通道,分担CPU的处理任务。主机CPU按照DMA方式读写NetFPGA上的寄存器和存储器来配置NetFPGA的工作模式,并对NetFPGA的工作状态进行监控。

 

NetFPGA平台的软件系统包括操作系统、作为软件接口的驱动程序、实现各种硬件功能的逻辑代码、执行控制功能的软件程序、系统测试的脚本程序,以及计算机辅助设计软件工具。

 

2.3 利用NetFPGA实现本设计的总体构想

基于网络编码的组播通信系统将充分运用NetFPGA上面的各种硬件和软件资源,实现系统的设计目标,具体是:(1)根据项目的需求,合理且充分利用NetFPGA卡上面的各种硬件资源,如FPGA、存储芯片和输入输出接口;(2)由于基于NetFPGA实现的IPv4原理性路由器是一个开源的系统,因此我们可以运用其提供的部分代码和已经设计好的底层硬件平台,来帮助我们实现设计目标。例如,我们的系统的编码、解码工作主要在网络层完成,因此我们可以利用NetFPGA中已有的物理层、MAC层硬件逻辑来实现数据的接收和发送;(3)在软件方面,由于NetFPGA平台选择了CentOS操作系统,并且开发了软硬件接口的驱动程序,基于Linux内核的设备驱动程序和Java程序开发的图形用户界面(Java GUI)等,因此我们可以对其应用、改进,使我们的系统更加完善,方便调试和后续的进一步研究。

 

2.4系统实现的整体设计方案说明

2.4.1 系统拓扑图及说明

如图2.4-1所示,是拟采用的组播通信网络的拓扑图:

 

图2.4-1基于网络编码组播的网络拓扑图

图2.4-1基于网络编码组播的网络拓扑图

 

说明:为了易于在工程上实现,将网络编码路由器分为编码路由器EC(Encoding router)和解码路由器DC(Decoding router),分别专门负责编码和解码。具体讲,如图1所示,信源S1,S2,S3发送数据包,编码路由器EC0和EC1负责将接收到的数据包以随机的系数进行线性编码后发送给组播路由器R,注意,这里的组播路由器更准确地说是转发路由器,因为它的功能只是将收到的数据包转发到其三个输出端口,而没有IGMP(组播管理)和相应的组播路由功能。当然,我们也可以直接在EC上实现转发的功能,增加R的原因是考虑到NetFPGA端口数量的限制(每块NetFPGA只有4个端口)。解码路由器DC接收编码的数据并解码,并将它发送给下游的信宿主机,在这里,由于PC数量的限制,我们使用双口网卡可以将解码路由器和信宿放到同一台主机上,这对网络性能的测试和实现没有任何影响。 

2.4.2编码策略与方案

作为一种编码结构的提出,我们将编码只限于不同信源数据包之间,暂不考虑信源包内部编码。相同信源的数据包之间分“代”,以便在解码时区分信息先后顺序[32]。不同信源的包之间不区分代的概念。

 

定义:为了讨论的方便性和简洁性,我们将信源S1的第1代记为S(1,1),信源S2的第3代记为S(2,3),……依此类推。依据包头和缓存,每个信源的代的编号从0开始,至1023结束,即信源n的最大的代编号为S(n,1023)

 

在编码路由器EC上对不同信源的IP数据包进行编码,编码系数矢量随机选择,编码方法是线性编码。例如,在上图中的编码路由器EC0,设两个链路的输入的全局编码向量为:in(e)= ,

由于只有两个信源之间的编码有且只有一条边输出,则本地编码向量为(α β),依据文章[33]的公式:

则输出out(e)=(α β)=αS(1,x)+βS(2,y)。编码后的数据以NCP(network coding protocol)包头封装,然后再封装在IP数据报中,如图2.4-2所示:

图2.4-2:编码后数据的封装格式

图2.4-2:编码后数据的封装格式

 

为减小相应的编码负担和提高编码效率,我们只对网络中的IP数据报中的有效载荷进行编码(已经编码过的数据包可以再进行编码),不对ARP等其他数据包编码。在编码路由器中,我们为不同的输入通道开辟不同的FIFO以进行顺序存取和编码,编码流程如图2.4-3所示:

 

 
   

 图2.4-3:数据包的编码流程
 

 

2.4.3随机系数的选择

根据相关资料可知,随即编码系数矢量的选择可以从Galois Field中进行选择,依据论文[33][34],我们选择域为GF256,即,此时可以解码的概率为1-=0.996,这个概率可以满足大多数的应用需求。

 

2.4.4 NCP数据包头的格式

为了能够在解码路由器上进行解码,我们需要在被编码的有效载荷前增加NCP数据包头[35],根据我们的方案,其包头格式如图2.4-4:

 

版本

4位

首部长度

4位

总长度

16位)

标志

2位

保留

6位

第1个包信源号

第2个包信源号

……

……

 

 

 

第8个包信源号

第1个包的填充长度(10位)

编码系数矢量1

(8位)

代的编号(10位)

编码次数

(4位)

第2个包的填充长度

编码系数矢量2

代的编号

编码次数

………………

……

……

 

第n个包的填充长度

编码系数n

代的编号

编码次数

编码后的有效载荷

                           

0       3         7                                       23       25        31

图2.4-4:NCP数据包的包头格式

 

先将包头各个字段的含义说明如下:

①版本:NCP数据包格式的版本,为了后续开发研究和以前版本的区分,第一个版本为0001.

②首部长度和总长度:首部长度是指除了有效数据载荷以外的部分,共4位,单位是4字节,其最小值为2。当首部长度为3时,意味着该包的载荷没有被编码,只是加了包头。当其值大于3时,其值减去3为被编码的信源数。

 

总长度是之首部长度和有效载荷之和的长度,16位,单位为字节。

③标志:若进入编码路由器的只是一个没有编码过的IP数据包时,不进行编码,直接将包头前2行加在原IP数据包的有效载荷的前面即可。当仅有一个NCP数据包进入编码路由器时,我们不进行编码,直接进行转发,如图2.4-5所示:

 

有效载荷的数据包类型

标志位

没有编码的IP数据包

01

编码后的NCP数据包

10

保留

00

保留

11

                           图2.4-5:标志位的含义

 

④编码次数:即从原始数据包算起,被编码的次数,因为在一个实际的网络中,数据的编码可以是递归的,即可以多次被编码。有时,只有一个数据源时,直接在其前面加上NCP包头而不进行编码。增加编码次数是为了能够在多次编码后进行解码。若编码前数据包为IP数据包,其编码次数为0,若为NCP数据包,则次数≥1.当一个IP数据包和一个已编码的数据包编码时,利用编码次数,可以避免解码路由器将NCP数据包误以为IP数据包而交给主机。

 

⑤第一个包的填充长度:因为不同数据源的数据包的长度可能不一样,为了便于编码计算,将它们前位补0使得长度一致。由于一个典型的以太网数据包的长度在500~1500字节之间,所以填充长度不超过1000字节。另外,我们还要考虑MAC层的最大传送单元(MTU)的限制,即编码后的MAC帧的长度不能超过1518字节。由此可以计算出,被编码的数据包的最大长度是1499字节

 

⑥编码系数:即随机选择的编码矢量的系数,是在一个GF256的有限域中随机选择。

 

⑦代的编号:即被编码的数据包的代的编号,是按照顺序产生的编号,目的是方便解码。

 

⑧包的信源号:4位,对进入编码路由器的数据包的信源进行编号,其目的是为了方便解码,在我们目前的体系中,最多允许8个数据包同时被编码。注意:当信源数少于8个时,例如有3个,则分别将对应的数据包的信源号分别填为0000,0001,0010,其余的都填写为1111。

2.4.5 转发(组播)路由器R工作流程

在实际的应用中,R应该是具有组播功能的路由器,即可以运行网际组播管理协议IGMP和多播路由选择协议DVMRP等,从而它可以知道网络的局部的拓扑和满足组播成员的要求。为了初期容易实现,我们将其功能简化为转发功能(即广播功能)。

                         

2.4.6数据包的解码

(1) 高速缓存和CAM的使用

数据包的解码由DC解码路由器完成。每个解码路由器DC有三个输入通道,分别连接到R0,R1,R2其解码的策略是:我们先在DC中开辟三块不同的高速缓存(DRAM)和与之分别对应的3个CAM,它们分别对应于R0、R1、R2,缓存和CAM的大小为代的编号的大小,即=1024,在这三个缓存中存放按照顺序接收到的数据。根据前面的数据处理过程,显然,对应于每个缓存中的数据,虽然有的是真正编码后的数据包,有的只是在IP数据包前增加了一个包头,但我们都可以认为是NCP数据包。在将数据存入高速缓存的同时,提取NCP数据包头中的信源号和代的编号,将它们存入到内容可寻址存储器CAM(content addressable memory),则CAM的输出即为对应数据在高速缓存的地址。

 

使用CAM的原因是:由于经过编码,以及网络环境非理想,解码路由器收到的encoded packet可能是乱序的。因此考虑使用CAM做检索链接,以便快速寻址当前解码所需要的packet。

 

(2) 解码顺序

根据实际情况的考虑,目前有两种解码的顺序,一种情况是按照信源号和代的编号的顺序进行解码,第二种情况是按照缓存及其缓存地址的顺序来解码。

已知网络拓扑的情况下,我们按照信源号和代的编号的顺序来进行解码,即对于信源采用轮询策略,对于内部代的编号采用小数优先策略。例如,在我们的拓扑图中,解码顺序是:S(1,1),S(2,1),S(3,1)→S(1,2),S(2,2),S(3,2)→……S(1,n),S(2,n),S(3,n)……。

 

未知网络拓扑的情况下,我们按照高速缓存的地址顺序来进行解码,即先对高速缓存采用轮询策略,对每个缓存中,采用地址由小到大的顺序进行解码,如图2.4-7所示,进行解码的顺序是PZ1

→PX1→ PY1→ PZ2→ PX2→PY2→PZ3……

 

 高速缓存1                高速缓存2              高速缓存3

地址   数据包           地址    数据包         地址    数据

01     PZ1              01      PX1             01      PY1

02     PZ2              02      PX2             02      PY2

03     PZ3              03      PX3             03      PY3

04     ……             04     ……            04       ……

……

图2.4-7 按照高速缓存的地址顺序来进行解码

 

上面的两种解码方式各有优点:在一般情况下,按照信源号和代的编号的顺序来进行解码可获得较高的解码速率,但在网络环境恶化的情况下,其丢包率(无法解码的概率)会比第2中方案高一些。由于在我们已有的网络环境一般较好,为了体现网络编码的传输的高效性,我们按照第1种顺序进行解码。

 

(3) 解码流程

为了避免高速缓存的写数据溢出,我们将设置二级缓存,二级缓存也有3个,可用SRAM构造,将SRAM分为3块地址上独立的区域,每个SRAM 大小为256×1800bytes,分别对应不同的信源,我们将解码后的数据,根据其代的编号,分别暂存在对应SRAM的对应地址上。例如,将S(1,1)存储在SRAM1的第1个地址空间,S(2,4)则存储在SRAM2的第4个地址空间。每个RAM各有1个读、写指针,可以同时按顺序读写数据,按照地址由小到大的顺序读出的数据被发送到输出队列中。

 

如图2.4-8所示为数据包的解码过程,每个告诉缓存各有1个读、写指针,在解码过程中,读取缓存是按照解码的顺序进行的,而在写缓存是按地址顺序写的。

 

图2.4-8:数据包解码流程

图2.4-8:数据包解码流程

 

(4) 解码策略与方法

我们按照信源号和代的编号的顺序来进行解码,即对于信源采用轮询策略,对于内部代的编号采用小数优先策略。例如,在我们的拓扑图中,解码顺序是:S(1,1),S(2,1),S(3,1)→S(1,2),S(2,2),S(3,2)→……S(1,n), S(2,n), S(3,n)……

假定我们按照上述顺序准备解码S(1,x),解码程序如图9:

 

 

图2.4-9 数据包S(1,x)的解码过程

图2.4-9 数据包S(1,x)的解码过程

 

无法求解一个数据包的原因可能是:该数据包由于延迟或者丢失,在CAM中搜寻不到,再有就是线性相关,无法解出来。在我们的系统中,由于其拓扑的特殊性,没有线性相关的情况,因此无法解码的情况只发生在解码因子丢失的情况下。

 

解码子任务:解码子任务的输入是包头信息,由调用它的程序给出,输出有两个变量:解码后的数据包和解码标志,解码标志告诉调用它的程序是否可以解码,我们假定现在要对S(i,j)解码,子任务流程如图2.4-10:              

 

图2.4-10:解码子任务流程

图2.4-10:解码子任务流程

(5) 解码后数据包暂存SRAM的读写策略

我们将解码后的数据包暂存在SRAM中等待发送,每个信源对应一个SRAM区域,同一个信源的解码后的人数据包存储在同一个RAM中,存储地址为该包的代的编号。每个RAM各有一个读指针,写数据按照RAM的地址大小顺序写入。读数据时按照信源编号和代的大小读取。由于发送速率一般会高于解码速率,因此RAM不用很大,暂定为256×1800。

 

每读取一个数据后,指针加1,若读取某个SRAM时无数据(可能是延迟或丢失造成),则不用等待,直接进行下一个SRAM的读取,3次轮询之后还没有到达,则强行加读指针加1,读取下一个数据包。如图2.4-11所示为SRAM的读写操作。

 

    图2.4-11 二级缓存SRAM的读写操作

图2.4-11 二级缓存SRAM的读写操作

 

(6)举例说明

为了更清楚地显示整个解码的操作过程,我们以DC3为例,图2.4-12显示的是DC3的3个高速缓存和CAM,解码过程如下

 

图2.4-12 数据包S(1,x)解码过程

图2.4-12 数据包S(1,x)解码过程

 

数据包S(1,x)解码过程如下:

先将S(1,x)的包头3个CAM中搜索,在CAM1中得到索引为00,我们利用该索引得到S(1,x)在高速缓存1的地址为00,从高速缓存1读取数据,得到a S(1,x)+b S(2,y),为了求解S(1,x)我们调用解码子任务先求解S(2,y),为了防止出现死循环,解码子任务只在CAM2和CAM3中搜寻S(2,y),在CAM2中得到地址为02,于是读取高速缓存2的02地址数据,得到eS(2,y)+f S(3,z),于是再调用子任务求解S(3,z),在CAM3中搜索S(3,z)后解出S(3,z), 于是可以解出S(2,y),最后再解出S(1,x),同时,分别将S(3,z)、 S(2,y) 、S(1,x)存入SRAM3,SRAM2,SRAM1相应的地址中。

 

2.5 系统软硬件接口及相关软件功能

在系统中,并非只有硬件逻辑在不同的模块之间处理数据包,而且还有相应的软件和控制程序。如图2.5-1所示,是数据包在系统中的通道与处理流程。数据在系统中的通道分为data bus和register bus,data bus主要进行数据的硬件处理,register bus则是软硬件的接口。在数据传输的每个阶段对软件应该是可控的、透明的,这些软件在更高层次上执行更复杂的算法和协议,或者处理一些异常情况,同时,对于系统开发人员,也应该是可控的,因为开发人员往往需要配置和调试硬件。使用通用的寄存器接口就可以使数据处理对软件透明化,这是靠映射内部的硬件寄存器来完成的,即所谓的存储映射技术。对于软件来讲,映射寄存器相当于一个I/O接口,它可以由软件访问和修改。

 

图2.5-1:系统中的register bus 和data bus

图2.5-1:系统中的register bus 和data bus

 

Register bus中每个模块的register连接在一起,组成一个信息环路。这些register块中存储了数据处理在每个模块中的状态和阶段,任何一个模块都可以响应来自PCI总线寄存器的访问和控制要求,而PCI总线寄存器可以通过软件来控制。也就是说,硬件和软件的通信是通过PCI总线完成的。

 

数据以及控信息在硬件和主机系统之间是通过PCI总线传输的,以Linux网络存储栈作为接口的。NetFPGA向主机发送分组数据的过程如图2.5-2a所示:

 

  1. 分组到达,发往CPU队列;
  2. 中断程序通知驱动程序有分组到达;
  3. 驱动程序设置和初始化DMA传送器;
  4. NetFPGA通过DMA总线发送分组;
  5. 中断程序发送DMA结束信号;
  6. 驱动程序把分组传递到网络存储栈;

图2.5-2a:NetFPGA向主机发送数据                         图2.5-2b:主机向NetFPGA发送数据

图2.5-2a:NetFPGA向主机发送数据             图2.5-2b:主机向NetFPGA发送数据

 

主机向NetFPGA发送分组数据的过程如图2.5-2b所示:

  1. 控制软件通过网络socket发送分组,分组被递交给驱动程序;
  2. 驱动程序设置和初始化DMA传送器;
  3. 中断程序发送DMA结束信号;

 

主机访问寄存器是通过系统调用系统内核的ioctl( )函数作为接口的。读写寄存器的操作函数如下,这两个函数内部调用了ioctl( )函数。

readReg(nf2device *dev, int address, unsigned *rd_data)

 writeReg(nf2device *dev, int address, unsigned *wr_data)

例如:          readReg(&nf2, OQ_NUM_PKTS_STORED_0, &val);

 

主机访问NetFPGA寄存器的过程如下:

(1)控制软件调用ioctl( )函数操作网络socket,由函数ioctl传递给驱动程序;

(2)驱动程序完成PCI寄存器的读写;

 

3 系统的详细设计方案

3.1 概述

在组播网络的拓扑图中,编码路由器、转发路由器和解码路由器是三个独立的系统,各自完成编码、转发和解码的任务。前面讲过,分组的编码、解码主要在网络层完成。在网络层中数据通道中,data bus和ctrl bus是同步传输的,二者之间的关系和格式如图3.1-1所示:

 

ctrl bus(8位)

Data bus(64位)

ff

module header

00

Pkt data1

00

……

xy(xy≠00)

Last pkt data

图3.1-1 数据通道中的data bus和ctrl bus

 

    Ctrl为ff时,表明为一个数据包的包头,xy为非零数据,指明最后一个有效的字节所在的位置,如01000000指明是第7个,即data[63:48]为有效数据。模块之间数据传输的过程是:若上一个模块已经处理完毕,想把数据传输到下一个模块,首先判断输入信号rdy是否有效,当rdy = 1时,将数据和控制信号同步发送出去,同时wr_vld信号有效,时序如图3.1-2所示:

 

图3.1-2 有效的数据传输时序

图3.1-2 有效的数据传输时序

 

3.2 编码路由器详细设计方案

3.2.1编码系统整体模块如图3.2-1所示

图3.2-1:编码系统整体模块图

图3.2-1:编码系统整体模块图

 

3.2.2系统中各单元模块的功能与时序

(1)Input arbiter

① Input arbiter内部结构如图3.2-2所示:

图3.2-2 Input arbiter内部结构图

图3.2-2 Input arbiter内部结构图

② 本模块输入输出信号列表及说明

Signal name

Bit width

Input or output

description

Input_fifo_data_1

64

input

Input data bus from “input FIFO 1”

Input_fifo_ctrl_1

8

input

Input ctrl bus from “input FIFO 1”

Input_fifo_empty_1

1

input

1=input FIFO is empty,0=otherwise

Input_fifo_rd_en_1

1

output

Read enable

Input_fifo_data_2

64

input

Input data bus from “input FIFO 2”

Input_fifo_ctrl_2

8

input

Input ctrl bus from “input FIFO 2”

Input_fifo_empty_2

1

input

1=input FIFO is empty,0=otherwise

Input_fifo_rd_en_2

1

output

Read enable

Data_arbiter_ctrl_1

64

output

Output data bus to “control module”

Ctrl_arbiter_ctrl_1

8

Output

Output ctrl bus to “control module”

Val_arbitrer_ctrl_1

1

Output

1=data from input arbiter 1 to head splitter 1 is valid, 0=otherwise

Rdy_arbiter_ctrl_1

1

Input

1=module “head splitter 1” is ready to receive

Data_arbiter_ctrl_2

64

output

Output data bus to “control module”

Ctrl_arbiter_ctrl_2

8

Output

Output ctrl bus to “control module”

Val_arbitrer_ctrl_2

1

Output

1=data from input arbiter 2 to head splitter 2 is valid, 0=otherwise

Rdy_arbiter_ctrl_2

1

Input

1=module “head splitter 2” is ready to receive, 0=otherwise

Data_arbiter_out_1

64

output

Output data bus to “output arbiter module”

Ctrl_arbiter_out_1

8

Output

Output ctrl bus to “output arbiter module”

Val_arbiter_out_1

1

Output

1=data from input arbiter 1 to output arbiter is valid, 0=otherwise

Rdy_arbiter_out_1

1

Input

1=module “output arbiter” is ready to receive from input arbiter 1, 0=otherwise

Data_arbiter_out_2

64

output

Output data bus to “output arbiter module”

Ctrl_arbiter_out_2

8

Output

Output ctrl bus to “output arbiter module”

Val_arbiter_out_2

1

Output

1=data from input arbiter 2 to output arbiter is valid, 0=otherwise

Rdy_arbiter_out_2

1

Input

1=module “output arbiter” is ready to receive from input arbiter 2, 0=otherwise

clk

1

Input

System clock, running at 125MHz

Rst_n

1

input

System asynchronous reset signal

 

 

③ 功能描述及数据流

本模块执行输入仲裁功能。两个独立的input arbiter模块分别从两个输入FIFO读出数据包,判断数据包类型,决定输出端口(非IP包直接送往output arbiter,IP包送往control),输出数据。

 

为了判断数据包类型,需要获取16-bit Ether Type信息,该信息位于每个数据包第二个double word中的31:16位,若Ether Type为0x0080,则说明此数据包为IP数据包,若Ether Type值不是0x0080,则说明此数据包不是IP数据包,将被直接送往output arbiter模块。

 

④ 关键时序及状态机

本模块的状态机的状态转化如图3.2-3所示

图3.2-3:input arbiter状态转换图

图3.2-3:input arbiter状态转换图

 

2、Control

       ① 子模块列表

Sub module name

quantity

description

Head_spliter

2

Split head and payload, send head to “head info extractor”, send payload to “FIFO ctrl payload”

Head_info_extractor

2

Receive head from “head splitter”, extract “source number”, generate “generation number”. Store legacy head and packing info head respectively in “FIFO ctrl legacy” and “FIFO ctrl packinginfo”

Control_arbiter

1

Detect ctrl bus to determine whether should process both channels synchronously or hold one channel and process the other.

FIFO ctrl payload

2

Standard FIFO generated by CoreGen, store payload

FIFO ctrl legacy

2

Standard FIFO generated by CoreGen, store legacy head

FIFO ctrl packinginfo

2

Standard FIFO generated by CoreGen, store packing info head

       ② 内部结构如图3.2-4

图3.2-4:control模块内部结构

图3.2-4:control模块内部结构

 

③ 本模块输入输出信号列表及说明

Signal name

Bit width

Input or output

description

Data_arbiter_ctrl_1

64

Input

Input data bus from “input arbiter 1”

Ctrl_arbiter_ctrl_1

8

Input

Input ctrl bus from “input arbiter 1”

Val_arbiter_ctrl_1

1

Input

1=data from input arbiter 1 to head splitter 1 is valid, 0=otherwise

Rdy_arbiter_ctrl_1

1

output

1=module “head splitter 1” is ready to receive from input arbiter 1, 0=otherwise

Data_arbiter_ctrl_2

64

Input

Input data bus from “input arbiter 2”

Ctrl_arbiter_ctrl_2

8

Input

Input ctrl bus from “input arbiter 2”

Val_arbiter_ctrl_2

1

Input

1=data from input arbiter 2 to head splitter 2 is valid, 0=otherwise

Rdy_arbiter_ctrl_2

1

output

1=module “head splitter 2” is ready to receive from input arbiter 2, 0=otherwise

Data_payloadfifo_router_1

64

output

output data bus to “payload router”

Ctrl_payloadfifo_router_1

8

output

Output ctrl bus to “payload router”

Rd_en_payloadfifo_router_1

1

Input

Read enable

Empty_payloadfifo_router_1

1

output

1=FIFO ctil payload 1 is empty,0=otherwise

Data_payloadfifo_router_2

64

output

output data bus to “payload router”

Ctrl_payloadfifo_router_2

8

output

Output ctrl bus to “payload router”

Rd_en_payloadfifo_router_2

1

Input

Read enable

Empty_payloadfifo_router_2

1

output

1=FIFO ctrl payload 2 is empty,0=otherwise

Data_center_legacyfifo_1

64

Output

Output data bus to “packing center”

Rd_en_center_legacyfifo_1

1

Input

Read enable

Data_center_packingfifo_1

14

Output

Output data bus to “packing center”

Rd_en_center_packingfifo_1

1

input

Read enable

Data_center_legacyfifo_2

64

Output

Output data bus to “packing center”

Rd_en_center_legacyfifo_2

1

Input

Read enable

Data_center_packingfifo_2

14

Output

Output data bus to “packing center”

Rd_en_center_packingfifo_2

1

input

Read enable

clk

1

input

System clock, running at 125MHz

Rst_n

1

input

System asynchronous reset signal

 

 

④ 功能描述及数据流

本模块为主控制模块。子模块control arbiter通过监控两条输入通道的ctrl bus,控制子模块head_spliter的两个独立的例化。具体控制操作如下:

 

若两条输入通道同时进来新的IP包,则同时处理两条通道。

 

若输入通道1进来新IP包时,通道2中IP包已经在处理中,则阻塞通道1,直至通道2处理完毕再重新判决。

 

若同时处理两条通道时,两条通道中的数据包深度相同,则无需“PADDING”操作。若通道1中数据包发送完毕时(ctrl bus用one-hot-code标明结尾字节),通道2中数据包尚未发送完毕,则需对通道1中数据包补零,并在ctrl bus中用0b11110000标明此为padding数据。

 

子模块head_spliter分离包头和负载,并分别发往head_info_extractor提取封装信息和FIFO_ctrl_payload暂存负载。

 

子模块head_info_extractor提取包头中的源IP地址,并由此生成4-bit信源编号(source number)和10-bit代编号(generation number),将生成的封装信息存入FIFO_ctrl_packinginfo,将原始包头存入FIFO_ctrl_legacy。

 

⑤ 关键时序及状态机

  • Head_spliter状态机如图3.2-5

图3.2-5:Head_spliter状态机

图3.2-5:Head_spliter状态机

 

  • Control arbiter时序图

  • Head spliter时序图

3、Coding

① 子模块列表

Submodule name

quantity

description

Payload router

1

Determine by the arrival of packets from both channels, whether should process coding or transport directly to packing module

M64×8 multiplier

2

Multiply 64-bit data from “payload router” by 8-bit random number from “prng tap16”

Prng tap16

1

8-bit random number generator

M72×72 adder

1

72-bit by 72-bit full adder

M72to64 converter

1

Convert data bus width from 72-bit to 64-bit

 

② Coding模块的内部结构如图3.2-6

图3.2-6:coding模块内部结构

图3.2-6:coding模块内部结构

      

③ 本模块输入输出信号列表及说明

 

 

Signal name  

Bit width

I/O

description

Data_payloadfifo_router_1

64

Input

Input data bus from “FIFO ctrl payload 1”

Ctrl_payloadfifo_router_1

8

Input

Input ctrl bus from “FIFO ctrl payload 1”

empty_payloadfifo_router_1

1

Input

1=FIFO ctrl payload 1 is empty,0=otherwise

Rd_en_payloadfifo_rouer_1

1

output

Read enable

Data_payloadfifo_router_2

64

Input

Input data bus from “FIFO ctrl payload 2”

Ctrl_payloadfifo_router_2

8

Input

Input ctrl bus from “FIFO ctrl payload 2”

empty_payloadfifo_router_2

1

Input

1=FIFO ctrl payload 2 is empty,0=otherwise

Rd_en_payloadfifo_rouer_2

1

output

Read enable

Router status

3

output

Output FSM state signal to “packing FIFO” and “packing center”, coordinate with the control of packing procedure

Data_router_packingfifo

73

output

Output data bus to “packing FIFO”. Bit 64 is set to “0” to indicate this is an uncoded packet

Wr_en_router_packingfifo

1

output

Write enable

Rdy_router_packingfifo

1

input

1=module “packing FIFO” is ready to receive from payload router, 0=otherwise

Empty_packingfifo

1

input

1=FIFO packing is empty,0=otherwise

Data_converter_packingfifo

73

output

Output data bus to “packing FIFO”. Bit 64 is set to “1” to indicate this is a coded packet

Wr_en_converter_packingfifo

1

Output

Write enable

Rdy_converter_packingfifo

1

output

1=module “packing FIFO” is ready to receive from m72to64 converter, 0=otherwise

Empty_converterfifo

1

output

1=FIFO converter is empty,0=otherwise

Rand_num_1

8

output

Output random number 1 to “packing center”

Rand_num_2

8

output

Output random number 2 to “packing center”

clk

1

input

System clock running at 125MHz

Rst_n

1

input

System asynchronous reset signal

 

④ 功能描述及数据流

本模块为主运算模块。子模块paylaod router构建与上游模块control的接口,从control的子模块FIFO ctrl payload中读取数据。若两FIFO都非空,则说明control模块同时处理了两条通道,也即需要进行编码操作。Paylpad router同时读取两个FIFO中的数据,送往由m64×8 multiplier、m72×72 adder以及m72to64 converter组成的“编码流水线”进行编码运算,并向下游packing模块发送编码过的数据包。

 

子模块prng tap16是8位伪随机数产生器。使能信号rand_num_en有效时,产生一个8位伪随机数。子模块m64×8 multiplier是64乘8位乘法器,该模块将负载与随即系数相乘,得到72位结果。m72×72 adder是72位全加器,将两个乘法器得到的结果相加得到编码输出。m72to64 converter是位宽转换器,由于coding模块输出的数据总线仍需保持64位,所以需要该转换器将72位编码输出转换为64为编码数据。由于是同步电路,采用同一时钟,该位宽转换将产生一定的数据囤积,需要较大缓存。

 

⑤ 关键时序与状态机

  • Payload router状态机

图3.2-7 Payload router状态机

图3.2-7 Payload router状态机

4、Packing

① 子模块列表

Sub module name 

quantity

Description

Packing FIFO

1

Receive and store processed packets before being packed in “packing center”

Packing center

1

Packing payload with all sorts of heads

 

② 内部结构图

图3.2-8 Packing内部结构图

图3.2-8 Packing内部结构图

 

③ 本模块输入输出信号列表及说明

Signal name

Bit width

I/O

Description

Data_router_packingfifo

73

input

Input data bus from “payload router”. Bit 64 is set to “0” to indicate this is an uncoded packet

Wr_en_router_packingfifo

1

Input

Write enable

Rdy_router_packingfifo

1

Output

1=module “packing FIFO” is ready to receive from payload router, 0=otherwise

Router_status

3

input

Input FSM state signal to coordinate with the control of  “packing FIFO”

Empty_packingfifo

1

output

1=FIFO packing is empty,0=otherwise

Data_converter_packingfifo

73

input

Input data bus from “m72to64 converter”. Bit 64 is set to “1” to indicate this is a coded packet

Wr_en_converter_packingfifo

1

Input

Write enable

Rdy_converter_packingfifo

1

Output

1=module “packing FIFO” is ready to receive from m72to64 converter, 0=otherwise

Empty_converterfifo

1

Input

1=FIFO converter is empty,0=otherwise

Data_center_legacyfifo_1

64

Input

Input data bus from “FIFO ctrl legacy 1”

Rd_en_center_legacyfifo_1

1

output

Read enable

Data_center_packinginfo_1

14

Input

Input data bus from “FIFO ctrl packinginfo 1”

Rd_en_center_packinginfo_1

1

output

Read enable

Data_center_legacyfifo_2

64

Input

Input data bus from “FIFO ctrl legacy 2”

Rd_en_center_legacyfifo_2

1

output

Read enable

Data_center_packinginfo_2

14

Input

Input data bus from “FIFO ctrl packinginfo 2”

Rd_en_center_packinginfo_2

1

output

Read enable

Rand_num_center_1

8

input

Input random number from “m64×64 multiplier 1”

Rand_num_center_2

8

input

Input random number from “m64×64 multiplier 2”

Out_data_out_0

64

output

Output data bus to “output arbiter”

Out_ctrl_out_0

8

Output

Output ctrl bus to “output arbiter”

Data_val_out_0

1

Output

1=data from packing center to output arbiter is valid, 0=otherwise

Rdy_out_0

1

Input

1=output arbiter is ready to receive from packing center, 0=otherwise

clk

1

Input

System clock running at 125 MHz

Rst_n

1

input

System asynchronous reset signal

 

④ 功能描述及数据流

本模块为封装模块。子模块packing FIFO构建与coding模块的数据接口,将接收并缓存编码数据包以及未编码数据包(使用额外第64位数据标志该包是否编码,该位为“1”说明编码,该位为“0”说明未编码)。

 

子模块packing center是主封装模块。它根据packing FIFO中读出的数据判断需要哪些包头信息,然后向control模块中相应FIFO读取需要的包头信息,并依次封装成NCP数据包,发送到output arbiter。

 

⑤ 关键时序及状态机

  • Packing center状态机

第一层状态机:packing_center_status

 

图3 .2-9 packing_center_status状态机

图3 .2-9 packing_center_status状态机

 

第二层状态机:

  1. coded_process

图3 .2-10coded_process状态机      uncoded_process

图3 .2-10coded_process状态机

 

  1. uncoded_process

图3.2-11 uncoded_process 状态机

图3.2-11 uncoded_process 状态机

 

5、Output arbiter

① 本模块输入输出信号列表及说明

Signal name

Bit width

Input or output

Description

Out_data_out_0

64

input

input data bus from “packing center”

Out_ctrl_out_0

8

Input

input ctrl bus from “packing center”

Data_val_out_0

1

Input

1=data from packing center to output arbiter is valid, 0=otherwise

Rdy_out_0

1

output

1=output arbiter is ready to receive from packing center, 0=otherwise

Out_data_out_1

64

input

input data bus from “input arbiter 1”

Out_ctrl_out_1

8

Input

input ctrl bus from “input arbiter 1”

Data_val_out_1

1

Input

1=data from input arbiter 1 to output arbiter is valid, 0=otherwise

Rdy_out_1

1

output

1=output arbiter is ready to receive from input arbiter 1, 0=otherwise

Out_data_out_2

64

input

input data bus from “input arbiter 2”

Out_ctrl_out_2

8

Input

input ctrl bus from “input arbiter 2”

Data_val_out_2

1

Input

1=data from input arbiter 2 to output arbiter is valid, 0=otherwise

Rdy_out_2

1

output

1=output arbiter is ready to receive from input arbiter 2, 0=otherwise

Out_data_mac

64

output

output data bus to “MAC Layer”

Out_ctrl_mac

8

Output

output ctrl bus to “MAC Layer”

Data_val_mac

1

Output

1=data from output arbiter to MAC layer is valid, 0=otherwise

Rdy_mac

1

Input

1=MAC layer is ready to receive from output arbiter, 0=otherwise

clk

1

Input

System clock running at 125MHz

Rst_n

1

input

System asynchronous reset signal

 

 

② 功能描述及数据流

本模块为输出仲裁模块。为协调多路输出通道,避免冲突而设计。入端构建与input arbiter通信的两路端口和与packing通信的一路端口,出端构建与MAC层通信的输出端口。将选通并维护唯一一条输入通道直至该数据包全部发送完毕。采用轮询方式检查三路输入通道以避免冲突。

 

③ 关键时序及状态机

图3.2-12  Output arbiter状态机

图3.2-12  Output arbiter状态机

 

3.3 转发路由器详细设计方案

3.3.1转发路由器系统整体模块图

图3.3-1总体模块图

图3.3-1总体模块图

 

系统模块功能说明:该模块有两个子模块input_arbiter模块和forward模块构成,其中前者为标准模块;后者为自定义模块,接受来自MAC层的数据包,经过相关处理输出数据包,实现将未编码的IP数据包封装成NCP数据包并进行转发以及将其它非IP数据包或NCP数据包进行直接转发的功能。

 

3.3.2系统中各单元模块的功能与时序

  1. Input_arbiter模块

① Input_arbiter模块的内部结构图如图3.3-2

图3.3-2  input_arbiter模块

图3.3-2  input_arbiter模块

 

② 本模块的输入输出信号列表及说明(如下例)

信号名称

位宽 bits

I/O

描述

in_data_n(n:0、1、2、3)

64

input

从MAC层输入的data数据

in_ctrl_n(n:0、1、2、3)

8

input

从MAC层输入的ctrlbus数据

in_wr_n(n:0、1、2、3)

1

input

从MAC层输入的数据写使能信号(1为有效)

in_rdy_n(n:0、1、2、3)

1

output

输出至MAC层的准备信号(1为准备完毕,可以写入)

out_data

64

output

输出至forward模块的data数据

out_ctrl

8

output

输出至froward模块的ctrl数据

out_wr

1

output

输出至forward模块的写使能信号(1为写使能有效)

out_rdy

1

input

从forward模块输入的准备信号(1为准备好,可以写入)

 

 

  • 本模块的功能描述以及内部数据处理的过程

功能描述:从MAC层的接口传来的数据信号写入到receivefifo中,每个接口接一个fifo,通过本模块的仲裁,循环查询每个fifo,如果每个fifo不为空则输出该fifo的数据到forward 模块。本次实验只用到接口1,其他接口实际上是没有数据输入,然而为了以后的可拓展设计,采取循环查询每个fifo,这样可以从每个接口进行数据读入数据,更合理。

 

④ 关键时序和状态机转化图

图3.3-3 input_arbiter时序图

图3.3-3 input_arbiter时序图

 

2、forward模块

① forward模块的内部结构图如图3.3-4

图3.3-4

图3.3-4

 

②本模块的输入输出信号列表及说明(如下例)

信号名称

位宽 bits

I/O

描述

out_data

64

input

从input_arbiter模块输出的data数据

out_ctrl

8

input

从input_arbiter模块输出的ctrl数据

out_wr

1

input

从input_arbiter模块输出的写使能信号(1为写使能有效)

out_rdy

1

input

输出至input_arbiter模块的准备使能信号(1为准备使能有效)

out_data_n(n:0、1、2、3)

64

output

输出至MAC层的data数据

out_ctrl_n(n:0、1、2、3)

8

output

输出至MAC层的ctrlbus数据

out_wr_n(n:0、1、2、3)

1

output

输出至MAC层的数据写使能信号(1为有效)

out_rdy_n(n:0、1、2、3)

1

intput

从MAC层输入的准备信号(1为准备完毕,可以写入)

 

 

③ 本模块的功能描述以及内部数据处理的过程

(1)Forward模块下子模块Ip_Packet_Arbiter 定义6个寄存器变量分别为:Reg_0—Reg_5 宽度为64bit, 6个寄存器变量:Ctrl_0—Ctrl_5宽度为8bit.分别存储数据包的前48个字节数据和CtrlBus信息。以便对包头进行解析,并进行判断所属的类型。

 

(2)判断属于哪一类型的数据包,如果是非IP数据包则从Ip_packet_Arbiter模块发送一个信号Ip_Packet_Check的信号到Transmit模块,通过data信号线和ctrl信号线将数据传送到Transmit模块并转发到各个接口;

 

(3)如果属于iP数据包则进一步判断是属于编码后的数据包还是未编码的数据包,如果是编码后的数据包则和①做同样处理,如果是未编码的数据包,则进行相应的处理(更改modulheader、MAC的目标地址、Ip包头、添加NCP包头操作),然后将组合好的数据包头和Ctrlbus 和Ip_Packet_Check信号一起送到Transmit模块。在Transmit模块通过收到的Ip_Packet_Check信号进行判断是否需要对存放数据进行重新的封装并进行相应处理,然后进行转发操作。整个过程的流程图如图3.3-5

 

图3.3-5

图3.3-5

 

④关键时序和状态机转化图

图3.3-6

图3.3-6

 

⑤ froward模块下子模块Transmit的状态机以及描述如图3.3-7

图3.3-7

图3.3-7

 

对整个状态机工作条件进行详细的描述如下:

  1. 当满足满足计数器counter=0的条件时,进入IDLE状态;counter计数器不改变并且不是包头的起始信号时则保持在该状态;如果counter=1,发现包头起始信号则保存该字段的值,并设置counter=2;
  2. 当满足计数器counter=2时,并且是包的中间值信号时则跳转到READ状态;根据counter计数器的值有条件的保存在该状态;counter自加;
  3. 当满足计数器counter=3时,判断MAC字段中上层协议的类型标志,如果为IP数据包继续保持在READ状态,counter+1;当counter=4时 进行判断数据包中协议字段的如果为未编码的IP数据包则保存在该状态,counter+1;
  4. 当满足counter=3时判断上层协议类型标志为非IP数据包,则直接跳转到SEND状态;如果为已经编码的IP数据包既NCP数据包,则调整到SEND状态;
  5. 当counter=7的时候,跳转到ADDNCPHEADER状态;数据处理完毕后state=SEND;
  6. 当暂存的数据包没有发送完之前则保持在该状态;
  7. 当state=SEND时,跳转到SEND状态;
  8. 当暂存的数据包的字段发送完毕后,跳转到CONSENCTIVEPASS(持续发包)状态时;
  9. 判断包尾的结束标志,如果不是包尾的结束标志则保持在该状态;
  10. 判断包尾的结束标志,如果是包尾的结束标志,则发最后一个字段,并跳转到IDLE(起始状态);

 

3.4 解码路由器详细设计方案

3.4.1 解码路由器系统整体模块图

如下图3.4-1所示,为解码路由器的整体模块图

 

3.4-1 解码路由器系统整体模块图

3.4-1 解码路由器系统整体模块图

 

3.4.2系统中各单元模块的功能与时序

1、Input_arbiter:采用轮询策略,当fifo非空时从fifo接收数据,根据mac header判断数据是否为IP数据包,若是,则将数据发送到DRAM读写控制模块,同时将信源号、代编号发送到CAM读写控制模块。

 

可用一个两状态的状态机实现:即轮询判断输入和数据输出:在FIFO非空时读数据,并根据数据包的类型发送到DRAM读写控制器或output fifo中,若是IP数据包,同时将信源号、代编号发送给CAM读写控制。

 

主要信号列表:

信号名称

位宽 bit

I/O

描述

Wr_vld_arb

1

 

写DRAM控制器有效

Out_data_0

64

 

输出至DRAM的data

Out_ctrl_0

8

 

输出至DRAM德ctrl

Src_gen_seq

24

 

信源号、代的编号

Cam_vld

1

 

写CAM控制器有效

Port_num_dram

2

 

数据的接收端口号

Out_data_1

64

 

输出至output arbiter的data

Out_ctrl_1

8

 

输出至output arbiter的ctrl

Wr_vld_1

1

 

输出至output arbiter信号有效

2、output_arbiter

图3.4-2 output_arbiter结构图

图3.4-2 output_arbiter结构图

 

本模块的结构如图3.4-2所示,由两个输入fifo和一个输出仲裁器组成,两个fifo缓存来自SRAM和input_arbiter的数据包,Output_arbiter的作用是将解码后的数据发送到MAC层。由于对于非IP数据包我们并没有对其进行编码,所以在解码路由器中由input_arbiter判断后直接输出output_arbiter;对于编码后的IP数据包,在解码后先暂存到SRAM中,再发送出去。本模块就是轮流判断并接收来自SRAM和input_arbiter的数据,并将数据包发送到MAC层。

 

输入输出信号列表:

信号名称

位宽bits

I/O

描述

out_data_3

64

O

输出至MAC层的数据总线

out_ctrl_3

8

O

输出至MAC层的控制总线

out_wr_3

1

O

输出有效

out_rdy_3

1

I

MAC层空闲标志

dcod_data_0

64

I

已经解码的IP数据包的数据总线

dcod_ctrl_0

8

I

已经解码的IP数据包的控制总线

wr_vld_0

1

I

写有效

wr_rdy_0

1

O

接收数据空闲标志

non_ip_data

64

I

非IP数据包数据总线

non_ip_ctrl

8

I

非IP数据包控制总线

wr_vld_1

1

I

写有效

wr_rdy_1

1

O

接收数据空闲标志

 

3、decoded_reg_grp

本模块分别与decode_control_panel,decoder和SRAM_contrl相连接,主要作用是记录信源的某代数据包是否已经解码,并将相应的解码信息输出给其他模块,模块结构如图3.4-3:

图3.4-3:decoded_reg_grp模块图

图3.4-3:decoded_reg_grp模块图

端口列表:

信号名称

位宽bits

I/O

描述

rd_dcod_reg_req_0

1

I

读取解码标志位请求

rd_dcod_src_gen_0

12

I

要读取的数据包的信源号和代编号

req_ack_vld_0

1

O

输出有效

alredy_decod_0

1

O

解码标志(“1”代表已经解码,“0”代表未解码)

rd_dcod_reg_req_1

1

I

读取解码标志位请求

rd_dcod_src_gen_1

12

I

要读取的数据包的信源号和代编号

req_ack_vld_1

1

O

输出有效

alredy_decod_1

1

O

解码标志(为1时代表已经解码,为0时未解码)

set_req

1

I

置位请求

set_src_gen

12

I

需要置位的数据包(表示已经解码完毕)

set_info_vld

1

I

置位信息有效

set_ack

1

O

置位请求响应

reset_req

1

I

复位请求

reset_src_gen

12

I

需要复位的数据包(表示解码后已发送完毕)

reset_info_vld

1

I

复位信息有效

reset_ack

1

O

复位请求响应

 

① 读解码标志

当decoder模块或decode_control_panel读取解码标志时,将查询结果输出,alredy_decod_0和alredy_decod_1为“1”时表示本次查询的数据包已经解码,为“0”时表示未被解码,以与decoder接口为例,读取解码标志的时序如图3.4-4:

 

图3.4-4:读解码标志位时序图

图3.4-4:读解码标志位时序图

 

② 写解码标志位

   当decoder把一个数据包解码成功后,就把相应的解码标志位置1,当SRAM_control将一个数据包发送出去后,再将相应的解码标志位置0,以置位为例,解码标志位的写时序如图3.4-5:

图3.4-5:置位解码标志寄存器

图3.4-5:置位解码标志寄存器

 

4、DRAM控制器:接收数据,并顺序存储到DRAM中去。

注意:我们将DRAM分为三块,分别对应于数据接收的三个信道,即第0个信道的数据存储到DRAM的第0块,第1个信道的数据存储到DRAM的第1块……信道号由port_num给出。由于DRAM是按照block读写的,因此每个block大小为2034字节,位宽为144位。

 

图3.4-6:DRAM控制器模块图

图3.4-6:DRAM控制器模块图

 

① DRAM控制器与DRAM的接口与读写时序:

Signal Group

Signal Name

Direction

Bits

Description

Request Negotiation

p_wr_req

from user logic to block-of-data rd/wr module

1

1=request for write transfer (data are from user logic to DRAM), 0=otherwise

Request Negotiation

p_wr_ptr

from user logic to block-of-data rd/wr module

PKT_MEM_PTR_WIDTH

the start address of DRAM for transfer. Each unit is 16-byte piece

Request Negotiation

p_wr_ack

from block-of-data rd/wr module to user logic

1

1=the arbiter acknowledges that the write requester can proceed, 0=otherwise

Data Transfer

p_wr_data_vld

from user logic to block-of-data rd/wr module

1

1=the write data is valid, 0=otherwise

Data Transfer

p_wr_data

from user logic to block-of-data rd/wr module

PKT_DATA_WIDTH

the data transferred from user logic to DRAM

Data Transfer

p_wr_full

from block-of-data rd/wr module to user logic

1

1=notify the user logic to pause transfer the next clock cycle until this signal is deasserted, 0=otherwise

Data Transfer

p_wr_done

from block-of-data rd/wr module to user logic

1

1=this is the last write and no more write will be accepted for this block-of-data, 0=otherwise

写DRAM时序如图3.4-7:

图3.4-7 写DRAM时序图

图3.4-7 写DRAM时序图

 

读端口:

Signal Group

Signal Name

Direction

Bits

Description

Request Negotiation

p_rd_req

from user logic to block-of-data rd/wr module

1

1=request for read transfer (data are from DRAM to user logic), 0=otherwise

Request Negotiation

p_rd_ptr

from user logic to block-of-data rd/wr module

PKT_MEM_PTR_WIDTH

the start address of DRAM for transfer. Each unit is 16-byte piece

Request Negotiation

p_rd_ack

from block-of-data rd/wr module to user logic

1

1=the arbiter acknowledges that the read requester can proceed, 0=otherwise

Data Transfer

p_rd_rdy

from block-of-data rd/wr module to user logic

1

1=block-of-data rd/wr module has data for user logic to read, 0=otherwise

Data Transfer

p_rd_en

from user logic to block-of-data rd/wr module

1

1=user logic reads out one word of data from the block-of-data rd/wr module, 0=otherwise

Data Transfer

p_rd_data

from block-of-data rd/wr module to user logic

PKT_DATA_WIDTH

data transferred from block-of-data rd/wr module to user logic

Data Transfer

p_rd_done

from block-of-data rd/wr module to user logic

1

1=this is the last read data and no more data will be read for this block-of-data, 0=otherwise

 

读DRAM时序如图3.4-8:

图3.4-8 写DRAM时序图

图3.4-8 写DRAM时序图

② 其他模块对DRAM控制器的读/写过程:

当DRAM读写控制器将一个数据包读/写完之后, 就将rd_idle/wr_rdy_arb置为1,当外部模块需要对DRAM进行读写时,首先要判断这两个信号是否有效,在有效的情况下进行对数据的操作。.端口列表如下:

 

信号名称

位宽bits

I/O

描述

wr_vld_arb

1

I

Input_arbiter输入有效

out_data_0

64

I

输入的数据包的data_bus

out_ctrl_0

8

I

输入数据包的ctrl_bus

port_num_dram

2

I

输入信号的端口号,指明数据存放在DRAM的区域

wr_rdy_arb

1

O

写空闲信号

port_num_rd

2

I

读取数据包的区域

addr_vld

1

I

读地址有效

block_num_rd

8

I

数据包存放的block的起始地址

rd_idle

1

O

读空闲信号

in_rdy

1

I

数据输出输出允许信号

out_data

64

O

读出的数据包的data_bus

out_ctrl

8

O

输出数据包的ctrl_bus

data_vld

1

O

输出数据有效

 

(1)当decode_control_panel对DRAM控制器进行读操作时,将信道号和block地址发送至DRAM控制器,接着DRAM控制器从DRAM中读取数据,当decoder空闲时将数据发送出去,时序图如3.4-9所示:

 

图3.4-9 对DRAM控制器的读操作

图3.4-9 对DRAM控制器的读操作

 

(2)当DRAM控制器进行写操作时,将按照input_arbiter发送过来的端口号,按照地址大小顺序写DRAM,时序图如3.4-10:

 

图3.4-10 对DRAM控制器的写操作

图3.4-10 对DRAM控制器的写操作

 

5、decode_control_panel

① 本模块的内部结构图如3.4-11所示,它由以下五个模块组成:cam_info_save, decode_control_sm和3个CAM组成。

 

图3.4-11:decode_control_panel内部结构图

图3.4-11:decode_control_panel内部结构图

 

本模块的输入输出端口定义表如下:

端口名称

位宽  bits

I/O

描述

port_num_cam

2

In

数据写入的CAM号,即信道号

Src_gen_seq

24

In

输入数据包的信源号、代编号

Cam_vld

1

In

写有效

Cam_rdy

1

Out

写Cam准备好

rd_idle

1

In

DRAM准备好

block_num_rd

8

Out

读DRAM的地址

addr_vld

1

Out

读地址有效

port_num_rd

2

out

要读取的DRAM的编号

Pkt_vld

1

Out

要解码的数据包输出有效标志

Pkt_decoding

12

out

正在解码的数据包的信源号、代编号

Decod_com

1

In

数据包解码完成标志

has_other_factor

1

Out

有另外一个解码因子

Pkt_not_find

1

Out

所需要解码数据包未找到

pkt_need_src_gen

12

In

解码需要的数据包

need_pkt_vld

1

In

所需数据包有效

rd_dcod_reg_req_1

1

Out

读解码标志寄存器请求

req_ack_vld_1

1

In

标志位有效

Alredy_Decod_1

1

In

解码标志位

rd_dcod_src_gen_1

12

out

查询数据包是否已经解码

 

② cam_info_save:

该模块的主要功能是将输入的数据包的信源号和代的编号按地址大小顺序存入到三个cam中,每个cam分别对应于三个数据输入通道。每个CAM的大小是24bits×256,我们要求CAM的读写操作可以同时进行,写数据从DIN进入,而读(查询)的数据从CMP_DIN进入,写操作时BUSY信号有效,表示不可以响应其他写请求,图3.4-12是一个CAM的读写操作时序:

 

图3.4-12:CAM读写过程

图3.4-12:CAM读写过程

③decode_control_sm

该模块的功能是按照轮询策略,控制decoder解码储存在DRAM中的数据包。通过查询CAM中的数据包的存储地址,将查询到的地址输出给DRAM读写控制模块,从而找到解码所需要的数据,同时将要查询的数据包的信源号和代的编号发送给解码模块。若不能查找到解码因子,则将信号Pkt_not_find置为有效电平,通知decoder无法解码,同时将状态转到解码下一个数据包的状态上。在开始查找CAM时,要等待储存一定数量的数据包,在我们的系统里面,暂定为32。

 

状态机处理控制流程如图3.4-13:

图3.4-13:decode_control_sm状态机及数据处理流程

图3.4-13:decode_control_sm状态机及数据处理流程

 

6、decoder

decoder是整个解码路由器的核心之一,它的主要功能是接收来自DRAM的编码后的IP数据包,在decode_control_panel模块的控制下对数据包进行解码,它包括多个小模块,其整体图和内部结构图如3.4-14和3.4-15所示:

 

图3.4-14 decoder整体结构图

图3.4-14 decoder整体结构图

 

图3.4-15:decoder内部结构图

图3.4-15:decoder内部结构图

 

① header_parser

分析接收到的数据包,如果已经被编码,根据包头提取信源号、代号、长度和系数给运算控制模块,如果没有被编码,则查询解码标志寄存器,如果已经解码并储存在二级缓存中,则该数据包只是一个解码因子,把数据发送到fwd_sel,若没有解码,则同时发送到capsulation和forward sel。如果数据是编码后的数据包,则将数据包去掉包头后将数据发送给forward sel模块。当发送到最后的64位数据时,eop信号有效,指明是数据包的最后有效字节。

 

下图所示为输入输出接口图3.4-16:

图3.4-16:header_parser模块图

图3.4-16:header_parser模块图

 

其输入输出端口列表如下:

信号名称

位宽bits

I/O

描述

in_rdy

1

O

数据输出输入允许信号

out_data

64

I

输入的数据包的data_bus

out_ctrl

8

I

输入数据包的ctrl_bus

data_vld

1

I

输入数据有效

rd_dcod_reg_req_0

1

O

读取解码标志位请求

rd_dcod_src_gen_0

12

O

要读取的数据包的信源号和代编号

req_ack_vld_0

1

I

输入有效

alredy_decod_0

1

I

解码标志(“1”代表已经解码,“0”代表未解码)

Uncod_data

64

O

未编码数据包的数据总线

Uncod_ctrl

8

O

未编码数据包的控制总线

Wr_vld

1

O

写capsulation数据有效

Out_rdy

1

I

输出capsulation允许信号

fwd_rdy

1

I

输出fwd_sel允许信号

out_vld

1

O

输出fwd_sel有效

pay_load

64

O

输出fwd_sel数据(不含包头)

eop

4

O

最后指示一个有效字节的指示

uncod

1

O

指明输出的数据包是否编码

src_gen_num

12

O

Decoder接收到的数据包的信源号和代的编号

len_0

16

O

被编码的第一个数据包的有效载荷的长度

len_1

16

O

被编码的第二个数据包的有效载荷的长度

coef_0

8

O

被编码的第一个数据包的编码系数

coef_1

8

O

被编码的第二个数据包的编码系数

hp_info_vld

1

O

输出信息有效

encod_pkt_trans_fi

1

O

编码数据包传输完毕标志

oc_info_vld

1

I

解码控制输入信息有效

uncod_pkt_need

1

I

未编码的数据包是/否解码因子(1=是,0=否)

 

 

 图3.4-17所示为状态机处理流程:

图3.4-17:header_parser状态机处理流程

图3.4-17:header_parser状态机处理流程

 

② forwd_sel

该模块功能主要是转发数据包:接收来自header_parser的数据包,若uncod=0,则表明数据包是编码后数据包,将已经编码后的数据包的载荷转换为72bits后,将数据发送到RAM读写控制器,否则发送到decod_operation。当有反馈输入请求时,若输出到decod_operation 的数据线空闲时,将反馈数据发送到decod_operation。

 

本模块的端口列表如下:

信号名称

位宽bits

I/O

信号描述

fwd_rdy

1

O

输入fwd_sel允许信号

out_vld

1

I

输入fwd_sel有效

pay_load

64

I

输入fwd_sel数据总线(不含包头)

eop

4

I

最后指示一个有效字节的指示

uncod

1

I

指明输出的数据包是否编码

wr_req

1

O

写RAM请求

encod_data

72

O

写RAM的数据总线

ram_data_vld

1

O

数据有效

encod_data_eop

4

O

数据包结束标志,指明最后一个有效字节

wr_ack

1

I

写RAM响应

uncod_data_vld

1

O

输出至dcod_operation的数据有效

uncod_data_factor

64

O

输出至dcod_operation的数据总线

uncod_data_eop

4

O

数据包结束标志,指明最后一个有效字节

dcod_rdy

1

I

输出至dcod_operation允许信号

fd_back_ack

1

O

接受反馈响应

fd_back_vld

1

I

反馈数据有效标志

fd_back_req

1

I

反馈请求

fd_back_data

64

I

反馈数据总线

fd_back_data_eop

4

I

反馈数据结束标志,指明最后一个有效字节

③ RAM读写控制器

在写数据时,先从运算控制模块中得出要储存的RAM号,接着RAM读写控制器将从收到forward sel 模块收到的数据存到片内RAM里面去。在读数据时,根据dcod_operation模块提供的ram号,从相应的ram中读取数据,由于使用的是双端口ram,因此读写可以同时进行。模块信号列表如下:

 

信号名称

位宽bits

I/O

信号描述

wr_req

1

I

写RAM请求

encod_data

72

I

写RAM的数据总线

ram_data_vld

1

I

数据有效

encod_data_eop

4

I

数据包结束标志,指明最后一个有效字节

wr_ack

1

O

写RAM响应

wr_ram_num

2

I

要写入的RAM号

info_vld

1

I

数据有效标志

req_ram_num

1

O

读RAM号请求

rd_ram_num

2

I

需要读取数据的RAM号

rd_req

1

I

读RAM请求

ram_data_eop

4

O

数据包结束标志,指明最后一个有效字节

ram_data

72

O

读RAM的数据总线

ram_vld

1

O

读RAM数据有效

 

RAM读写时序图如图3.4-18:

图3.4-18:RAM读写时序

图3.4-18:RAM读写时序

 

每个RAM由双端口block RAM组成,位宽为72位,深度为180,因此读写的地址位宽均为8位。由于RAM的读写控制时序是固定的,所以在此不再赘述。

④ operation_control

运算控制(operation_control)是decoder模块的控制核心,它和decode_control_panel配合,完成对编码数据包的解码。

输入输出信号列表:

信号名称

位宽bits

I/O

信号描述

Pkt_vld

1

I

要解码的数据包输出有效标志

Pkt_decoding

12

I

正在解码的数据包的信源号、代编号

Decod_com

1

O

数据包解码完成标志

has_other_factor

1

I

有另外一个解码因子

Pkt_not_find

1

I

所需要解码数据包未找到

pkt_need_src_gen

12

O

解码需要的数据包

need_pkt_vld

1

O

所需数据包有效

src_gen_num

12

I

Decoder接收到的数据包的信源号和代的编号

len_0

16

I

被编码的第一个数据包的有效载荷的长度

len_1

16

I

被编码的第二个数据包的有效载荷的长度

coef_0

8

I

被编码的第一个数据包的编码系数

coef_1

8

I

被编码的第二个数据包的编码系数

hp_info_vld

1

I

输入信息有效

encod_pkt_trans_fi

1

I

编码数据包传输完毕标志

oc_info_vld

1

O

解码控制输出信息有效

uncod_pkt_need

1

O

未编码的数据包是/否解码因子(1=是,0=否)

wr_ram_num

2

O

要写入的RAM号

info_vld

1

O

数据有效标志

req_ram_num

1

I

读RAM号请求

rd_info_req

1

I

读取解码信息请求

dcod_info_vld

1

O

解码信息有效

ram_num

2

O

解码数据包的所存储的RAM号

coef_mut

8

O

乘法系数

coef_div

8

O

除法系数

cap_info_req

1

I

封装信息请求

dcod_comp

1

I

解码封装完成

cap_info_vld

1

O

封装信息有效

need_feed_back

1

O

需要反馈

pkt_len

16

O

数据包长度

src_num

4

O

数据包的信源号

gen_num

8

O

数据报的代编号

Operation_control模块的主要功能是:接收header_parser发送过来的数据,通过计算和比较后与decode control panel通信,告诉decode control panel解码所需要的数据包和解码完成标志;给RAM读写给出RAM号(即存储在哪个RAM中);给decode operation模块提供解码所需要的系数和RAM号;给capsulation模块提供源IP和是否需要反馈数据的命令,其控制状态如图3.4-19下:

 

图3.4-19:Operation_control状态机处理流程

图3.4-19:Operation_control状态机处理流程

 

⑤ decode operation

decode operation是解码运算模块,它将来自fwd_sel模块的未编码的数据和来自RAM的编码数据完成减法和除法运算,还原被编码的数据。解码后将数据总线的位宽恢复为64bits。解码运算模块的端口列表如下:

 

信号名称

位宽bits

I/O

信号描述

dcod_payload

64

O

解码后的数据包的有效载荷

end_payload

4

O

数据包结束标志,指明最后一个有效字节

payload_vld

1

O

输出数据有效

wr_rdy

1

I

输出数据允许信号

uncod_data_vld

1

I

输入至dcod_operation的数据有效

uncod_data_factor

64

I

输入至dcod_operation的数据总线

uncod_data_eop

4

I

数据包结束标志,指明最后一个有效字节

dcod_rdy

1

O

输入至dcod_operation允许信号

rd_ram_num

2

O

需要读取数据的RAM号

rd_req

1

O

读RAM请求

ram_data_eop

4

I

数据包结束标志,指明最后一个有效字节

ram_data

72

I

读RAM的数据总线

ram_vld

1

I

读RAM数据有效

rd_info_req

1

O

读取解码信息请求

dcod_info_vld

1

I

解码信息有效

ram_num

2

I

解码数据包的所存储的RAM号

coef_mut

8

I

乘法系数

coef_div

8

I

除法系数

 

为了快速完成解码运算,我们在此采取并行除法的方法使之能快速解码,解码运算的算法图如图3.4-20:

图3.4-20 decoder_operation内部的并行除法

图3.4-20 decoder_operation内部的并行除法

⑥ capsulation

Capsulation是解码运算的最后一个模块,其主要功能是封装解码后的数据包。其主要任务是:(1)接收来自decode operation和header_parser的数据;(2)将来自header_parser的未编码的数据包去掉NCP包头;(3)计算新的包头校验和,更新TTL;(4)置位解码标志寄存器;(5)将来自decode operation模块的数据,先向运算控制模块询问是否要反馈,若需要,则将数据反馈至forward_sel模块;(6)恢复IP数据包头;(7)将IP包头和有效载荷封装好,并恢复ctrl_bus和module header,将其一起同步发送出去。

 

端口信号列表如下:

信号名称

位宽bits

I/O

信号描述

decoder_in_rdy

1

I

输出至SRAM允许信号

decoder_in_wr

1

O

输出有效

decoder_in_data

64

O

输出至SRAM数据总线

decoder_in_ctrl

8

O

输出至SRAM控制总线

set_req

1

O

置位请求

set_src_gen

12

O

需要置位的数据包(表示已经解码完毕)

set_info_vld

1

O

置位信息有效

set_ack

1

I

置位请求响应

cap_info_req

1

O

封装信息请求

dcod_comp

1

O

解码封装完成

cap_info_vld

1

I

封装信息有效

need_feed_back

1

I

需要反馈

pkt_len

16

I

数据包长度

src_num

4

I

数据包的信源号

gen_num

8

I

数据报的代编号

dcod_payload

64

I

解码后的数据包的有效载荷

end_payload

4

I

数据包结束标志,指明最后一个有效字节

payload_vld

1

I

输入数据有效

wr_rdy

1

O

输入数据允许信号

fd_back_ack

1

I

接受反馈响应

fd_back_vld

1

O

反馈数据有效标志

fd_back_req

1

O

反馈请求

fd_back_data

64

O

反馈数据总线

fd_back_data_eop

4

O

反馈数据结束标志,指明最后一个有效字节

Uncod_data

64

I

未编码数据包的数据总线

Uncod_ctrl

8

I

未编码数据包的控制总线

Wr_vld

1

I

写capsulation数据有效

Out_rdy

1

O

输入数据包允许信号

 

封装过程中的状态转换图如图3.4-21:

图3.4-21capsulation封装包头流程图

图3.4-21capsulation封装包头流程图

 

7、SRAM读写控制器

SRAM读写控制的作用是:①将capsulation模块来的数据写入SRAM中,写入时按照代的大小和信源号写入block中。SRAM按照地址分为3个区域,每个区域存储对应由一个信源。每个区域分为256个block,每个block深度是400,宽度为36bits,可以存储1800字节的数据(即至少可容纳一个正常大小的IP数据包)。②读取数据时按照block逐个读取,读取后的数据直接发送至output_arbiter。在每发送完一个数据包后,对解码标志寄存器复位。

 

SRAM读写控制器的端口列表如下:

信号名称

位宽bits

I/O

信号描述

decoder_in_rdy

1

O

写SRAM控制器允许信号

decoder_in_wr

1

I

输入有效

decoder_in_data

64

I

输入至SRAM控制器数据总线

decoder_in_ctrl

8

I

输入至SRAM控制器控制总线

reset_req

1

O

复位请求

reset_src_gen

12

O

需要复位的数据包(表示解码后已发送完毕)

reset_info_vld

1

O

复位信息有效

reset_ack

1

I

复位请求响应

dcod_data_0

64

O

输出的IP数据包的数据总线

dcod_ctrl_0

8

O

输出的IP数据包的控制总线

wr_vld_0

1

O

输出有效

wr_rdy_0

1

I

发送数据允许标志

sram_addr

19

O

Sram读/写地址

sram_we

1

O

Sram写使能

sram_bw

4

O

SRAM写入控制信号

sram_wr_data

36

O

SRAM写数据总线

sram_rd_data

36

I

SRAM读数据总线

sram_tri_en

1

O

SRAM写三态控制

 

SRAM的读写时序如图3.4-22:

图3.4-22 SRAM读写时序

图3.4-22 SRAM读写时序

4 结论

网络编码从提出到现在已有十年,在这期间,网络编码的理论研究和工程应用不断发展和成熟,基于网络编码的多信源组播系统是网络编码在硬件方面的实现。它突破了以往网络编码的应用研究只停留在软件和虚拟网络,通过搭建实际的组播通信网络,并应用NetFPGA平台使网络编码在硬件中得以实现。

 

文档的前面分别介绍了网络编码的基本概念和研究动态、编解码策略和算法以及编码、转发、解码三个系统的详细设计方案,包括系统的软硬接口和软件的基本功能。由于系统中的网络编解码都是由硬件完成,软件的功能主要是控制和测试时使用,因此方案设计以硬件为主。

 

图4-1,图4-2和图4-3分别是编码、转发以及解码路由器三个系统的verilog代码树状图,除去MAC层和core generator产生的代码,代码量有11,000行。附录给出了编码路由器和解码路由器中的关键代码。

 

图4-1 编码路由器代码树状图

图4-1 编码路由器代码树状图



图4-2 转发路由器代码树状图

图4-2 转发路由器代码树状图

 

 

图4-3 解码路由器代码树状图

图4-3 解码路由器代码树状图

 

 

附录

1:编码路由器核心代码:编码模块: payload_router.v

/////////////////////////////////////////////////////////////////////////////

// vim:set shiftwidth=3 softtabstop=3 expandtab:

// Copyright(c) 2009, All rights reserved.

// Advanced Network technology Lab, Shenzhen graduated school of PKU

// Module: payload_router.v

// Project: nf2_coding.ise

// Time and Author: 2009-12-25 liyining 

// Description:determine whether should carry out coding operation, and route

// the packets

/////////////////////////////////////////////////////////////////////////////

   `define DLY 1

   `timescale 1ns/1ns

 

   module payload_router

    #(parameter DATAWIDTH = 64,

      parameter CTRLWIDTH = DATAWIDTH / 8 //bit-width parameter

      )

   (

      //payload fifo 1 port

      input [DATAWIDTH - 1:0]                   data_payloadfifo_router_1,

      input [CTRLWIDTH - 1:0]                   ctrl_payloadfifo_router_1,

      input                              empty_payloadfifo_router_1,

      output reg                      rd_en_payloadfifo_router_1,

 

      //payload fifo 2 port

      input [DATAWIDTH - 1:0]                   data_payloadfifo_router_2,

      input [CTRLWIDTH - 1:0]                   ctrl_payloadfifo_router_2,

      input                              empty_payloadfifo_router_2,

      output reg                      rd_en_payloadfifo_router_2,

 

      //multiplier 1 port

      input                              rdy_router_multiplier_1,

      output reg [DATAWIDTH - 1:0]            data_router_multiplier_1,

      output reg                      first_dword_1, //flag to indicate the start of a pkt. only when it is the first double word of a pkt, should the random number be updated.

      output reg                      val_router_multiplier_1,

 

      //multiplier 2 port

      input                              rdy_router_multiplier_2,

      output reg [DATAWIDTH - 1:0]            data_router_multiplier_2,

      output reg                      first_dword_2, //flag to indicate the start of a pkt. only when it is the first double word of a pkt, should the random number be updated.

      output reg                      val_router_multiplier_2,

 

      //rand number generator port

      output reg                      rand_num_en, //enable the random number generator

      input                                  rand_num_val,

 

      //packing fifo port

      input                              rdy_router_packingfifo,

      input                              empty_packingfifo, // only when the whole last pkt is sent out, and the packing fifo is empty, then proceed the next pkt

      output reg [DATAWIDTH + CTRLWIDTH:0]   data_router_packingfifo,  //an extra bit(MSB) to indicate whether it is a coded pkt

      output reg                      val_router_packingfifo,

      output reg [2:0]                      router_status, //send router_status to packing_fifo, indicate where to get data

 

      //misc

      input                              clk,

      input                              rst_n

      );

 

      reg [DATAWIDTH - 1:0]               data_temp1;

      reg [CTRLWIDTH - 1:0]               ctrl_temp1;

      reg [DATAWIDTH - 1:0]               data_temp2;

      reg [CTRLWIDTH - 1:0]               ctrl_temp2;

      reg [1:0]                                 counter_getdata; //counter for the read-FIFO-delay, 1 clock circle

 

 

      parameter                                JUDGE = 3'b000;

      parameter                                GET_DATA2 = 3'b001;

      parameter                                SEND_DATA2 = 3'b010;

      parameter                                GET_DATA1 = 3'b011;

      parameter                                SEND_DATA1 = 3'b100;

      parameter                                GET_BOTH = 3'b101;

      parameter                                SEND_BOTH_1 = 3'b110;

      parameter                                SEND_BOTH_2 = 3'b111;

 

      

      always @(posedge clk or negedge rst_n) begin

 

         //reset process

         if (rst_n == 0) begin

           router_status <= JUDGE;

           data_temp1 <= 64'h0;

           ctrl_temp1 <= 8'h0;

           data_temp2 <= 64'h0;

           ctrl_temp2 <= 8'h0;

           counter_getdata <= 2'b0;

        end

        else begin

           case (router_status)       

              JUDGE: begin

                first_dword_1 <= 0;

                first_dword_2 <= 0;

                rand_num_en <= 0;

                  val_router_multiplier_2 <= 0; //clear some signals

 

                  //program hold, when packing FIFO inempty

                if (!empty_packingfifo) begin

                   router_status <= JUDGE;

                end

 

                else begin

                     //both FIFO ctrl payload 1 & 2 are empty

                   if (empty_payloadfifo_router_1 && empty_payloadfifo_router_2) begin

                     rd_en_payloadfifo_router_1 <= 0;

                     rd_en_payloadfifo_router_2 <= 0;

                     router_status <= JUDGE;

                   end

 

                     //FIFO ctrl paylaod 2 is inempty, read from this FIFO,

                     //coding will be unnecessary

                   else if (empty_payloadfifo_router_1 && (!empty_payloadfifo_router_2)) begin

                     rd_en_payloadfifo_router_2 <= 1;

                      rd_en_payloadfifo_router_1 <= 0;

                      counter_getdata <= 0;

                     router_status <= GET_DATA2;

                   end

 

                     //FIFO ctrl payload 1 is inempty, read from this FIFO,

                     //coding will be unnecessary

                   else if ((!empty_payloadfifo_router_1) && empty_payloadfifo_router_2) begin

                     rd_en_payloadfifo_router_1 <= 1;

                     rd_en_payloadfifo_router_2 <= 0;

                     counter_getdata <= 0;

                     router_status <= GET_DATA1;

                   end

 

                     //both FIFO ctrl payload 1&2 are inempty, read from both

                     //of them, coding is needed

                   else if ((!empty_payloadfifo_router_1) && (!empty_payloadfifo_router_2)) begin

                     rd_en_payloadfifo_router_1 <= 1;

                     rd_en_payloadfifo_router_2 <= 1;

                    counter_getdata <= 0;

                     router_status <= GET_BOTH;

                   end

                end

              end //state JUDGE ends

 

               //read data from FIFO ctrl payload 2

              GET_DATA2: begin

                val_router_packingfifo <= 0; //clear the output valid signal

 

                  //read-FIFO-delay

                if (counter_getdata < 2'b01) begin

                   counter_getdata <= counter_getdata + 1;

                   router_status <= GET_DATA2;

                   rd_en_payloadfifo_router_2 <= 0; //clear rd_en signal

                end

 

                  else begin

                   data_temp2 <= data_payloadfifo_router_2;

                   ctrl_temp2 <= ctrl_payloadfifo_router_2;

                   router_status <= SEND_DATA2;

                end

              end //state GET_DATA2 ends

 

               //send data to packing fifo without coding

              SEND_DATA2: begin

                if (!rdy_router_packingfifo) begin

                   router_status <= SEND_DATA2;

                end

                else begin

                   data_router_packingfifo <= {ctrl_temp2, 1'b0 , data_temp2 }; //MSB = 0 means it is an uncoded pkt                       

                   val_router_packingfifo <= 1;

 

                     //this is the end of a packet, goto JUDGE

                   if (& (ctrl_temp2)) begin

                     router_status <= JUDGE;

                   end

 

                     //this is not the end of a packet, goto GET_DATA2

                   else begin

                      router_status <= GET_DATA2;

                     rd_en_payloadfifo_router_2 <= 1;

                     counter_getdata <= 0;

                   end

                end

              end //state SEND_DATA2 ends

 

              GET_DATA1: begin

                val_router_packingfifo <= 0; //clear output valid signal

 

                  //read-FIFO-delay

                if (counter_getdata < 2'b01) begin

                   counter_getdata <= counter_getdata + 1;

                   router_status <= GET_DATA1;

                   rd_en_payloadfifo_router_1 <= 0; //clear rd_en signal

                end

 

                 else begin

                   data_temp1 <= data_payloadfifo_router_1;

                   ctrl_temp1 <= ctrl_payloadfifo_router_1;

                   rd_en_payloadfifo_router_1 <= 0;                   

                   router_status <= SEND_DATA1;

                end

              end //state GET_DATA1 ends

 

              SEND_DATA1: begin

                if (!rdy_router_packingfifo) begin

                   router_status <= SEND_DATA1;

                end

 

                else begin

                   data_router_packingfifo <= {ctrl_temp1, 1'b0 , data_temp1 }; //MSB = 0 means it is an uncoded pkt                       

                   val_router_packingfifo <= 1;

 

                     //this is the end of a packet, goto JUDGE

                   if (& (ctrl_temp1)) begin

                     router_status <= JUDGE;

                   end

 

                     //this is not the end of a packet, goto GET_DATA1

                   else begin

                     router_status <= GET_DATA1;

                     rd_en_payloadfifo_router_1 <= 1;

                     counter_getdata <= 0;

                   end

                end

              end //state SEND_DATA1 ends

 

              GET_BOTH: begin

                first_dword_2 <= 0; //

                val_router_multiplier_2 <= 0; //clear valid signal

 

                  //read-FIFO-delay

                if (counter_getdata < 2'b01) begin

                   counter_getdata <= counter_getdata + 1;

                   router_status <= GET_BOTH;

                   rd_en_payloadfifo_router_1 <= 0;

                   rd_en_payloadfifo_router_2 <= 0; //clear rd_en signals

                end

                else begin

                   data_temp1 <= data_payloadfifo_router_1;

                   ctrl_temp1 <= ctrl_payloadfifo_router_1;

                   data_temp2 <= data_payloadfifo_router_2;

                   ctrl_temp2 <= ctrl_payloadfifo_router_2;

                   router_status <= SEND_BOTH_1;

                end

              end //state GET_BOTH ends

 

               //according to the random number generator, data from both

               //input channels should be sent out seperately

              SEND_BOTH_1: begin

                 if (!rdy_router_multiplier_1) begin

                   val_router_multiplier_1 <= 0;

                   router_status <= SEND_BOTH_1;

                end

                else begin

                   data_router_multiplier_1 <= data_temp1;

                   val_router_multiplier_1 <= 1;

 

                   if (ctrl_temp1 == 8'hff) begin

                     first_dword_1 <= 1;

                     rand_num_en <= 1;

                   end

                   else begin

                     first_dword_1 <=0;

                     rand_num_en <= 0;

                    end

                   router_status <= SEND_BOTH_2;

                end

              end //state SEND_BOTH_1 ends

 

              SEND_BOTH_2: begin

                first_dword_1 <= 0;

                val_router_multiplier_1 <= 0; //clear valid signal

 

                  //confirm the first random number is generated successfully

                  //before enable to generate the second.

                  if (ctrl_temp1 == 8'hff) begin

                     if (!rand_num_val) begin

                        rand_num_en <= 0;

                        router_status <= SEND_BOTH_2;

                     end

                  end

 

                  else begin

                   if (!rdy_router_multiplier_2) begin

                      val_router_multiplier_2 <= 0;

                      router_status <= SEND_BOTH_2;

                   end

                   else begin

                      data_router_multiplier_2 <= data_temp2;

                      val_router_multiplier_2 <= 1;

 

                      if (ctrl_temp2 == 8'hff) begin

                        first_dword_2 <= 1;

                        rand_num_en <= 1;

                      end

                      else begin

                        first_dword_2 <= 0;

                        rand_num_en <= 0;

                      end

                      if (((ctrl_temp1 == 8'hf0) && (& (ctrl_temp2))) || ((ctrl_temp2 == 8'hf0) && (& (ctrl_temp1)))) begin

                        router_status <= JUDGE;

                      end

                      else begin

                        rd_en_payloadfifo_router_1 <= 1;

                        rd_en_payloadfifo_router_2 <= 1;

                       counter_getdata <= 0;

                         router_status <= GET_BOTH;

                      end

                   end

                  end

              end //state SEND_BOTH_2 ends

            endcase                

        end

      end

 

endmodule

 

2:解码路由器核心代码之一:解码控制模块:decode_control_sm. v

///////////////////////////////////////////////////////////////////////////////

// vim:set shiftwidth=3 softtabstop=3 expandtab:

// Copyright(c) 2009, All rights reserved.

// Advanced Network technology Lab, Shenzhen graduated school of PKU

// Module: decode_control_sm.v

// Project: NF2.1

// Time and Author: 2009-12-15 zhang ming long

// Description: According to the pkts' source and generation sequence number,

//              this module goes round-robin strategy to control the module decoder

//              to decode the pkts stored in DRAMS.  

///////////////////////////////////////////////////////////////////////////////

   `define DLY #1

   `timescale 1ns/1ps

   module decode_control_sm

    #(parameter SRC_WIDTH     = 4,

      parameter GEN_WIDTH     = 8,

      parameter REG_GRP_WIDTH = 12,

      parameter SRC_GEN_SEQ_WIDTH = 24,

      parameter DRAM_NUMS      = 3,

      parameter CAM_NUMS       = 3,

      parameter DRAM_NUMS_WIDTH = log2(DRAM_NUMS),

      parameter CAM_NUMS_WIDTH  = log2(CAM_NUMS),

      parameter DRAM_BLOCK_WIDTH = 8,

      parameter CAM_ADDR_WIDTH = 8,

      parameter CMP_DATA_MASK = 12'hfff

      )

 

   (// --- cam interface

    output [SRC_GEN_SEQ_WIDTH-1:0]          cmp_data_0,

    output reg [SRC_GEN_SEQ_WIDTH-1:0]             cmp_data_mask_0,

    input [CAM_ADDR_WIDTH-1:0]                match_addr_0,  

    input                                     match_0,

 

    output [SRC_GEN_SEQ_WIDTH-1:0]          cmp_data_1,

    output reg [SRC_GEN_SEQ_WIDTH-1:0]       cmp_data_mask_1,

    input      [CAM_ADDR_WIDTH-1:0]        match_addr_1,  

    input                                      match_1,

 

    output [SRC_GEN_SEQ_WIDTH-1:0]         cmp_data_2,

    output reg [SRC_GEN_SEQ_WIDTH-1:0]      cmp_data_mask_2,

    input      [CAM_ADDR_WIDTH-1:0]            match_addr_2,  

    input                                        match_2,   

 

    // ---DRAM control interface

    output reg [DRAM_NUMS_WIDTH-1:0]       port_num_rd,

    output reg [DRAM_BLOCK_WIDTH-1:0]      block_num_rd,

    output reg                                 addr_vld,

    input                                     rd_idle,

 

    // ---input_arbiter interface

    input                                    cam_vld,

        

    // ---decoder interface

    output reg                                pkt_vld,

    output reg [REG_GRP_WIDTH-1:0]          pkt_dcoding,

    output reg                                pkt_not_find,

    output reg                                has_other_factor,

    input      [REG_GRP_WIDTH-1:0]         pkt_need_src_gen,

    input                                    need_pkt_vld,

    input                                    decod_com,

 

    // ---decoded reg grp interface

    output reg                                rd_dcod_reg_req_1,

    output  [REG_GRP_WIDTH-1:0]            rd_dcod_src_gen_1,

    input                                    req_ack_vld_1,

    input                                    alredy_decod_1,

 

    // --- Misc

   

    input                                  rst_n,

    input                                  clk

   );

  

   function integer log2;

      input integer number;

      begin

         log2=0;

         while(2**log2<number) begin

            log2=log2+1;

         end

      end

   endfunction // log2

 

   // ------------ Internal Params --------

   parameter NUM_STATES          =  4;

   parameter IDLE                =  4'b0;

   parameter GET_SRC_GEN_NUM     =  4'b0001;

   parameter LOOK_UP_CAM         =  4'b0010;

   parameter GET_CMP_RESLT_FIRST =  4'b0011;

   parameter GET_CMP_RESLT_SEC   =  4'b0100;

   parameter RD_DRAM_MAIN_STEP   =  4'b0101;

   parameter LUP_DCOD_FACTOR1_FIRST =  4'b0110;

   parameter LUP_DCOD_FACTOR1_SEC = 4'b0111;

   parameter GET_FACTOR1_RESLT   =  4'b1000;

   parameter RD_DRAM_MINOR_STEP  =  4'b1001;

   parameter LUP_DCOD_FACTOR2    =  4'b1011;

   // ------------- Regs/ wires -----------

   wire [SRC_WIDTH-1:0]                       src_num_plus1;

   reg  [SRC_WIDTH-1:0]                    src_num,src_num_sel,src_num_sel_next;      //source sequence number for packets that is being decoded

   reg  [SRC_WIDTH-1:0]                    src_num_next;

   wire [GEN_WIDTH-1:0]                    gen_num_plus1;

   reg  [GEN_WIDTH-1:0]                    gen_num,gen_num_sel,gen_num_sel_next;      //generation sequence number for packets that is being decoded

   reg  [GEN_WIDTH-1:0]                    gen_num_next;

 

   reg  [CAM_NUMS-1:0]             cam_lookup_reslt;                           // result of looking up packets in cam,stands for which cam finds the packet

   reg  [CAM_NUMS-1:0]                     cam_lookup_reslt_next;

   reg[CAM_NUMS-1:0]                   cam_lookup_reslt_pre,cam_lookup_reslt_save;

   reg[CAM_NUMS-1:0]          cam_lookup_reslt_pre_next,cam_lookup_reslt_save_next;

      

   reg  [CAM_ADDR_WIDTH-1:0]               other_dram_addr;

   reg  [CAM_ADDR_WIDTH-1:0]               other_dram_addr_next;

   reg  [DRAM_NUMS_WIDTH-1:0]             other_port_num_rd;              //the other result from looking up cams

   reg                                     has_factor2;                       //has  the other looking up result

   reg                                     has_factor2_next;        

   reg  [DRAM_NUMS_WIDTH-1:0]              other_port_num_rd_next;

   reg [NUM_STATES-1:0]                    state;

   reg [NUM_STATES-1:0]                    state_next;

   reg [4:0]                               couter;

   wire [4:0]                              couter_next;

   reg                                     couter_start;

   reg[CAM_ADDR_WIDTH-1:0]             atch_addr_temp_2,match_addr_temp_2_next;  

   reg[CAM_ADDR_WIDTH-1:0]           match_addr_temp_1,match_addr_temp_1_next;

   reg[CAM_ADDR_WIDTH-1:0]           match_addr_temp_0,match_addr_temp_0_next;

   reg [SRC_GEN_SEQ_WIDTH-1:0]             cmp_data;

   // ------------ main code and logic -------------

   assign src_num_plus1     = (src_num == 2) ? 0 : src_num + 1;

   assign gen_num_plus1     = (gen_num == 2**GEN_WIDTH-1) ? 0 : gen_num + 1;

   assign rd_dcod_src_gen_1 = {src_num_sel,gen_num_sel};

   assign couter_next       = (couter_start == 1) ? couter+1 : couter;

   assign cmp_data_0        = cmp_data;

   assign cmp_data_1        = cmp_data;

   assign cmp_data_2        = cmp_data;

   /* This state machine completes decode control task. If enough packets have

    * been saved in cams and DRAMS, it starts to decode to packets. If

    * a packet can not be decoded becouse of losing, it will decode the next

    * packet automatically */

 

   always @(*) begin

      state_next     = state;

      gen_num_next   = gen_num;

      src_num_next   = src_num;

      src_num_sel_next = src_num_sel;

      gen_num_sel_next = gen_num_sel;

      cam_lookup_reslt_next = cam_lookup_reslt;

      rd_dcod_reg_req_1 = 1'b0;

      addr_vld       = 1'b0;

      pkt_vld        = 1'b0;

      pkt_not_find   = 1'b0;

      other_dram_addr_next = other_dram_addr;

      other_port_num_rd_next =other_port_num_rd;

      has_factor2_next = has_factor2;

      pkt_dcoding = 12'hfff;

      block_num_rd = 2'b0;

      cam_lookup_reslt_pre_next = cam_lookup_reslt_pre;

      cam_lookup_reslt_save_next = cam_lookup_reslt_save;

      port_num_rd = 2'b11;

      couter_start = 1'b0;

      match_addr_temp_2_next = match_addr_temp_2;

      match_addr_temp_1_next = match_addr_temp_1;

      match_addr_temp_0_next = match_addr_temp_0;

      cmp_data_mask_0 = 24'h0;

      cmp_data_mask_1 = 24'h0;

      cmp_data_mask_2 = 24'h0; 

      has_other_factor = 0;

      cmp_data = 24'hffffff;

 

      case(state)

      /* --- waiting for the cam has been writen enough packet */

         IDLE: begin

            if(cam_vld) begin

              couter_start = 1;

            end

            if(couter == 5'b11111)                                 

               state_next = GET_SRC_GEN_NUM;

           end 

      /*  Goes round-robin around the sources and generations,

       *  gets the source sequence number and generation sequebce

       *  number of a packet need to be decoded */    

      GET_SRC_GEN_NUM: begin

        state_next = LOOK_UP_CAM;

         rd_dcod_reg_req_1 = 1;                             // read the decoded reg grp 

         src_num_sel_next = src_num;

         gen_num_sel_next = gen_num;

         src_num_next = src_num_plus1;

         if(src_num == 4'b0010)

            gen_num_next = gen_num_plus1;            

         end  

          /* --- look up pkt in three cams to get block number of DRAM*/

      LOOK_UP_CAM:

         if(req_ack_vld_1) begin

            if(alredy_decod_1 == 1)                     // it has been decoded,decode the next packet

              state_next = GET_SRC_GEN_NUM;

            else begin

               cmp_data = {src_num_sel,gen_num_sel,12'hfff};

              cmp_data_mask_0 = {12'h0,CMP_DATA_MASK};                 

              cmp_data_mask_1 = {12'h0,CMP_DATA_MASK};                

              cmp_data_mask_2 = {12'h0,CMP_DATA_MASK};

               state_next = GET_CMP_RESLT_FIRST;

            end

         end            

      GET_CMP_RESLT_FIRST: begin

         cam_lookup_reslt_next = {match_2,match_1,match_0};

        cmp_data = {12'hfff,src_num_sel,gen_num_sel};

        cmp_data_mask_0 = {CMP_DATA_MASK,12'h0};

        cmp_data_mask_1 = {CMP_DATA_MASK,12'h0};

        cmp_data_mask_2 = {CMP_DATA_MASK,12'h0};

        state_next = GET_CMP_RESLT_SEC;

        match_addr_temp_2_next = match_addr_2;

        match_addr_temp_1_next = match_addr_1;             

        match_addr_temp_0_next = match_addr_0;                                                       

      end

      /* get the address from the cams, if there are two adresses from

       * the cams, then outputs the one to the DRAM control and save

       * the other for later use. If there is no valid address, we could not

       * decode, then get out and decode the next one */

      GET_CMP_RESLT_SEC: begin

        state_next = RD_DRAM_MAIN_STEP;

         cam_lookup_reslt_next = cam_lookup_reslt | {match_2,match_1,match_0};

         cam_lookup_reslt_pre_next = cam_lookup_reslt | {match_2,match_1,match_0};

        cam_lookup_reslt_save_next = cam_lookup_reslt | {match_2,match_1,match_0};

         if(match_2) begin

           match_addr_temp_2_next = match_addr_2;

         end

         if(match_1) begin

           match_addr_temp_1_next = match_addr_1;

         end               

         if(match_0) begin

           match_addr_temp_0_next = match_addr_0;

         end

      end

      /* reads the DRAM accroding to the CAM's address, then updates the look

       * up result */

      RD_DRAM_MAIN_STEP:

         if(rd_idle) begin

            if(|cam_lookup_reslt) begin

               if(cam_lookup_reslt==3'b101) begin

                  other_dram_addr_next = match_addr_temp_2;

                  other_port_num_rd_next = 2'b10;

                  has_factor2_next     = 1;

                  addr_vld = 1;

                  block_num_rd = match_addr_temp_0;

                  port_num_rd = 0;

                  cam_lookup_reslt_next = 3'b100;

               end

               else if (cam_lookup_reslt == 3'b011) begin

                  other_dram_addr_next = match_addr_temp_1;

                  other_port_num_rd_next = 2'b01;

                  has_factor2_next     = 1;

                  addr_vld = 1;

                  block_num_rd = match_addr_temp_0;

                  port_num_rd = 0;

                  cam_lookup_reslt_next = 3'b010;

               end

               else if (cam_lookup_reslt==3'b110) begin

                  other_dram_addr_next = match_addr_temp_2;

                  other_port_num_rd_next = 2'b10;

                  has_factor2_next     = 1;

                  addr_vld = 1;

                  block_num_rd = match_addr_temp_1;

                  port_num_rd = 2'b01;

                  cam_lookup_reslt_next=3'b100;                     

               end

               else if (cam_lookup_reslt==3'b001) begin

                  has_factor2_next     = 0;

                  addr_vld = 1;

                  block_num_rd = match_addr_0;

                  port_num_rd = 2'b00;

                  cam_lookup_reslt_next = 0;

               end

               else if (cam_lookup_reslt==3'b010) begin

                  has_factor2_next     = 0;

                  addr_vld = 1;

                  block_num_rd = match_addr_1;

                  port_num_rd = 2'b01;

                  cam_lookup_reslt_next = 0;

               end

               else if (cam_lookup_reslt==3'b100) begin

                  has_factor2_next     = 0;

                  addr_vld = 1;

                  block_num_rd = match_addr_2;

                  port_num_rd = 2'b10;

                  cam_lookup_reslt_next = 0;

               end

               state_next=LUP_DCOD_FACTOR1_FIRST;

               pkt_vld = 1;

               pkt_dcoding = {src_num_sel,gen_num_sel};

            end  // end-- if(|cam_lookup_reslt)

         else

            state_next = GET_SRC_GEN_NUM;  //could not find the pkt in cams.

         end   //end--if(rd_idle)

        

      /* waiting for decoding completion, if needs the decoding factor pkt,

       * then look up the factor in the remain cams */

       LUP_DCOD_FACTOR1_FIRST: begin

          if(decod_com) begin

             state_next=GET_SRC_GEN_NUM;

          end

          if(need_pkt_vld) begin                          // need other packet to decode current packet

             if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b110) begin

                cmp_data = {pkt_need_src_gen,12'hfff};

                cmp_data_mask_2 = {12'h0,CMP_DATA_MASK};

                cmp_data_mask_1 = {12'h0,CMP_DATA_MASK};

             end

             else if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b101) begin

                cmp_data = {pkt_need_src_gen,12'hfff};

                cmp_data_mask_2 = {12'h0,CMP_DATA_MASK};

                cmp_data_mask_0 = {12'h0,CMP_DATA_MASK};

             end         

            else if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b011) begin

                cmp_data = {pkt_need_src_gen,12'hfff};

                cmp_data_mask_1 = {12'h0,CMP_DATA_MASK};

                cmp_data_mask_0 = {12'h0,CMP_DATA_MASK};

            end  

            else if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b001) begin

               cmp_data = {pkt_need_src_gen,12'hfff};

               cmp_data_mask_0 = {12'h0,CMP_DATA_MASK};

               end  

            else if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b010) begin

               cmp_data = {pkt_need_src_gen,12'hfff};

               cmp_data_mask_1 = {12'h0,CMP_DATA_MASK};

            end

            else if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b100) begin

               cmp_data = {pkt_need_src_gen,12'hfff};

               cmp_data_mask_2 = {12'h0,CMP_DATA_MASK};

            end                                                                

            state_next = LUP_DCOD_FACTOR1_SEC;

         end

       end

         LUP_DCOD_FACTOR1_SEC: begin

            state_next = GET_FACTOR1_RESLT;

            cam_lookup_reslt_next = {match_2,match_1,match_0};

           match_addr_temp_2_next = match_addr_2;

           match_addr_temp_1_next = match_addr_1;        

           match_addr_temp_0_next = match_addr_0;

            if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b110) begin

               cmp_data = {12'hfff,pkt_need_src_gen};

               cmp_data_mask_2 = {CMP_DATA_MASK,12'h0};

               cmp_data_mask_1 = {CMP_DATA_MASK,12'h0};

            end

            else if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b101) begin

               cmp_data = {12'hfff,pkt_need_src_gen};

               cmp_data_mask_2 = {CMP_DATA_MASK,12'h0};

               cmp_data_mask_0 = {CMP_DATA_MASK,12'h0};

            end

            else if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b011) begin

               cmp_data = {12'hfff,pkt_need_src_gen};

               cmp_data_mask_0 = {CMP_DATA_MASK,12'h0};

               cmp_data_mask_1 = {CMP_DATA_MASK,12'h0};

            end

           else if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b001) begin

               cmp_data = {12'hfff,pkt_need_src_gen};

               cmp_data_mask_0 = {CMP_DATA_MASK,12'h0};

            end

           else if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b010) begin

               cmp_data = {12'hfff,pkt_need_src_gen};

               cmp_data_mask_1 = {CMP_DATA_MASK,12'h0};

            end

           else if((cam_lookup_reslt^~cam_lookup_reslt_pre)==3'b100) begin

               cmp_data = {12'hfff,pkt_need_src_gen};

               cmp_data_mask_2 = {CMP_DATA_MASK,12'h0};

            end                             

      end

     /* --- get the factor pkt address from the cam, then reads the DRAM

            if no address matches, then check the decode factor2 */

      GET_FACTOR1_RESLT: begin

         state_next = RD_DRAM_MINOR_STEP;

         cam_lookup_reslt_next    = cam_lookup_reslt | {match_2,match_1,match_0};

         cam_lookup_reslt_pre_next = cam_lookup_reslt | {match_2,match_1,match_0};

         if(match_2) begin

            match_addr_temp_2_next = match_addr_2;

         end

         if(match_1) begin

            match_addr_temp_1_next = match_addr_1;

         end               

         if(match_0) begin

           match_addr_temp_0_next = match_addr_0;

         end

      end

 

      RD_DRAM_MINOR_STEP:

            if(rd_idle)

               if(|cam_lookup_reslt) begin

                  state_next = LUP_DCOD_FACTOR1_FIRST;

                  if(cam_lookup_reslt==3'b001)

                      begin

                      addr_vld = 1;

                      block_num_rd = match_addr_temp_0;

                      port_num_rd = 2'b00;

                      cam_lookup_reslt_next=0;

                      end

                 else if (cam_lookup_reslt==3'b010)

                     begin

                     addr_vld = 1;

                     block_num_rd = match_addr_temp_1;

                     port_num_rd = 2'b01;

                     cam_lookup_reslt_next=0;

                     end          

                 else if (cam_lookup_reslt==3'b100)

                     begin

                     addr_vld = 1;

                     block_num_rd = match_addr_temp_2;

                     port_num_rd = 2'b10;

                     cam_lookup_reslt_next=0;

                     end        

                 end

               else

                 begin

                 state_next = LUP_DCOD_FACTOR2;

                                   pkt_not_find = 1;

                 has_other_factor = has_factor2;

                 end

      /* decoding the packet by decode factor2 */

      LUP_DCOD_FACTOR2:

           if(has_factor2) begin

               addr_vld = 1;

               block_num_rd = other_dram_addr;

               port_num_rd    = other_port_num_rd;

               state_next   = LUP_DCOD_FACTOR1_FIRST;

              cam_lookup_reslt_pre_next = cam_lookup_reslt_save;

              has_factor2_next = 0;

           end

           else begin

              pkt_not_find = 1;

              has_other_factor = has_factor2;

              state_next   = GET_SRC_GEN_NUM;

           end

      endcase // case(state)

   end // always @ (*)

 

 

   always @(posedge clk) begin

      src_num_sel <= `DLY src_num_sel_next;

      gen_num_sel <= `DLY gen_num_sel_next;

      cam_lookup_reslt_pre <= `DLY cam_lookup_reslt_pre_next;

      other_dram_addr <= `DLY other_dram_addr_next;

      other_port_num_rd <= `DLY other_port_num_rd_next;

      match_addr_temp_2 <= `DLY match_addr_temp_2_next;

      match_addr_temp_1 <= `DLY match_addr_temp_1_next;

      match_addr_temp_0 <= `DLY match_addr_temp_0_next;

      cam_lookup_reslt_save <= `DLY cam_lookup_reslt_save_next;

   end

 

   always @(posedge clk or negedge rst_n) begin

      if(rst_n == 1'b0) begin

         state   <= IDLE;

         src_num <= 0;

         gen_num <= 0;

         has_factor2 <= 0;

         cam_lookup_reslt <= 0;

        couter <= 5'b0;

      end

      else begin

         state   <= `DLY state_next;

         src_num <= `DLY src_num_next;

         gen_num <= `DLY gen_num_next;

        couter  <= `DLY couter_next;

         cam_lookup_reslt <= `DLY cam_lookup_reslt_next; 

        has_factor2 <= `DLY has_factor2_next;    

      end

   end

   endmodule   //decode_control_sm