张 杰,孟 琪
(西安电子科技大学电子信息攻防对抗与仿真重点实验室,陕西西安 710071)
由于环境的特殊性,不仅要求设备具有较高的性能,也对设备的体积功耗等提出了严格的要求。为增加系统运行的可靠性,硬件设备需尽可能的紧凑。在满足系统运行需求的前提下,硬件中分立元件越少越好。基于现场可编程门阵列(FPGA)的以太网设计是一个较好的解决方案。
SOPC Builder是一种特殊的嵌入式系统,其是片上系统,即由单个芯片完成系统的主要逻辑功能,并具有灵活的设计方式,可裁剪、可扩充和升级、且具备软硬件在系统可编程功能。NiosⅡ嵌入式处理器是Altera公司推出的采用哈佛结构、具有32位指令集的第二代可编程软核处理器[1-3],其最大优势是模块化的硬件结构,在设计阶段根据实际需求来增减外设的种类和数量。LWIP是瑞士计算机科学院的Adam Dunkela等开发出的一套用于嵌入式系统的开放源代码TCP/IP协议栈。一般情况下,LWIP既可移植到操作系统上,又可在无操作系统的情况下独立运行。LWIP实现的主要优点是在保持TCP/IP协议主要功能的基础上,又减少了其对RAM的占用,这使得LWIP协议适合在嵌入式系统中使用[4-6]。
以软核NiosⅡ为核心,在FPGA中搭建存储器、DMA、三速以太网MAC等多种外设的SOPC系统,在片外配置三速以太网物理层芯片(PHY)。通过对TCP/IP协议栈的移植以及基于UDP协议的网络编程实现以太网应用。系统整体设计方案如图1所示,系统设计主要分整体硬件电路设计、基于FPGA的SOPC系统设计和系统软件设计。
图1 系统整体结构图
硬件模块主要由FPGA模块、网络接口模块及电源模块等组成。核心器件是FPGA,其作为SOPC系统的搭载平台,并对其他硬件进行控制。网络接口模块选用Marvell公司的三速以太网物理层芯片88e1111,硬件结构如图2所示。
图2 系统硬件框图
用SOPC Builder工具从NiosⅡ处理器内核和开发套件提供的外设列表中选取合适的CPU,存储器以及各自的外围器件,并定制和配置其作用;分配外设地址及中断号;设定复位地址;最后生成系统。硬件开发使用Quartus II和SOPC Builder GUI处理器库选择并配置外设。设计中除了必要的外设外还需添加MAC子层,MAC是以太网控制器的核心,主要提供与上层协议间的接口及与PHY设备间的介质无关接口,并对以太网数据包进行封装、解封装以及错误监测等。设计选择三速以太网(10/100/1 000 Mbit·s-1)MAC,其结构如图 3 所示[7-9]。
图3 三速以太网MAC结构图
FIFO用于缓存接收或发送的数据。设计采用M9K存储器块作为FIFO,设置发送FIFO为2 048×32 bit,接收FIFO设置为512×32 bit,因系统主要用于向上位机传送数据并接收上位机控制命令,因此接收FIFO需求较小。
在与PHY通信一侧,三速以太网MAC核提供RGMII接口,工作在全双工模式,并提供PHY管理接口。其中,PHY管理接口提供4个信号,分别是数据管理时钟MDC、管理数据输入MDIO_in、管理数据输出MDIO_out以及管理数据输出使能MDIO_oen。由于在PHY芯片上只有时钟MDC和双向数据接口MDIO,所以MAC与PHY对接时中间需要一个双向三态缓冲器,连接电路如图4所示。
图4 数据管理接口
LWIP的移植可分为两大类,第一类是只移植内核核心,此时用户应用程序的编写只能基于raw/callback API进行;第二类是移植内核核心和上层API函数模块,此时用户可使用3种API进行编程,即除了raw/callback API外,还有sequentia API和BSD-style socket API。本文进行的是第一种移植,该移植较为简单,移植者只需完成头文件的定义,同时根据使用的具体网卡情况完成ethernetif.c中函数的编写。
介绍LWIP的源代码结构。解压后,源代码目录共有doc、src和test 3个文件夹。其中,doc文件夹下包含了几个与协议栈使用相关的文本文档,较为重要的文件有两个:rawapi.txt为告诉读者如何使用协议栈的raw/callback API进行编程,其通过直接与协议栈内核函数交互以实现编程;sys_arch.txt在移植时被使用到,其中描述了移植说明,规定了移植者需实现的函数、宏定义等。Test文件夹则是LWIP提供的一些协议栈的内核测试程序。文件夹src包含了协议栈内核的所有源代码。
在NiosⅡ中建立新工程,添加srccore文件夹下的所有文件,同时包括其下IPV4文件夹中的所有文件。应该注意,这里添加了较多的文件,但其中有些是可条件编译的,如文件sys.c,若不提供操作系统模拟层的文件,则该文件不会被编译。接着添加netif文件夹中的 loopif.c、etharp.c、ethernetif.c文件到工程中,同时在源文件目录下新建lwipopts.h、perf.h和cc.h这3个头文件,并同时将其添进工程。这3个头文件是内核要求用户在移植时需完成的头文件。
Cc.h文件主要完成协议栈内部使用的数据类型定义,用户应根据具体编译器和处理器特性定义这些数据类型的长度;此外,cc.h文件还要完成临界代码的保护、协议栈调试信息输出相关的宏和大小端的定义等。
Perf.h文件是与系统统计和测量相关的头文件,该头文件和平台的处理器密切相关,本文平台无需使用任何统计和测量功能。因此,该头文件中的两个宏直接定义为空。
最后一个头文件lwipopts.h,其包含用户对协议栈内核的参数设置,在内核的opt.h文件中,包含了内核所有参数的默认配置,当用户在lwipopts.h中配置相关参数,若用户对某个参数未配置,则内核将使用opt.h中的默认值。需注意,在移植时重新定义某些内核参数是必要的,否则协议栈可能无法正常运行。
Ethernetif.c的编写移植者应根据自身使用的网卡特性完善这一函数。LWIP源码提供者将ethernetif.c中的函数实现为一个框架形式。总体而言,在文件ethernetif.c中已有5个函数的框架,包括函数名、函数参数、函数内容等,要完成如下5个函数的编写:
(1)Static void low_level_init(struct netif*netif)
(2)Static err_t low_level_output(struct netif*netif,struct pbuf*p)
(3)Static struct pbuf* low_level_input(struct netif*netif)
(4)Static void ethernetif_input(struct netif*netif)
(5)err_t ethernetif_init(struct netif*netif)。
这5个函数中,前3个与网卡功能密切相关。low_level_init为网卡初始化函数,其主要用于完成网卡复位及参数初始化,同时根据实际网卡特性,还需设置协议栈网络接口管理结构neitif中与网卡属性相关的字段,例如网卡MAC地址长度等;low_level_output为网卡数据包发送函数,该函数的主要工作是将内核数据结构pbuf描述的数据包发送出去;low_level_input为网卡数据包接收函数;ethernetif_input的主要作用是调用网卡数据包接收函数low_level_input从网卡处读取一个数据包,然后解析该数据包的类型,最后将数据包递交给上层;ethernetif_init是上层在管理网络接口结构netif时会调用的函数,该函数主要完成netif结构中某些字段的初始化,并最终调用low_level_init完成网卡的初始化。到此,关于网卡驱动的移植就基本完成了。
void lwip_init_task(void)
{
struct ip_addr lwipStaticIp,lwipnetmask,lwipgw;
lwip_init();
IP4_ADDR(&lwipStaticIp,192,168,0,68);
IP4_ADDR(&lwipnetmask,255,255,255,0);
IP4_ADDR(&lwipgw,192,168,0,254);
netif_set_addr(&alteraTseNetif,&lwipStaticIp,&lwipnetmask,&lwipgw);
netif_add(&alteraTseNetif,&lwipStaticIp,&lwipnetmask,&lwipgw,NULL,ethernetif_init,ethernet_input);
netif_set_default(&alteraTseNetif);
netif_set_up(&alteraTseNetif);
}
在使用协议栈之前,协议栈内核必须完成初始化,若要使用网卡进行通信,则网卡相关的网络接口结构也需被注册到内核中。在此用函数lwip_init_task来完成协议栈的初始化和网卡信息的注册。初始化工作主要是调用内核函数lwip_init来完成的,其依次调用各模块的初始化函数,例如内存初始化函数、数据包结构初始化函数、网络接口结构初始化函数、IP初始化函数、TCP初始化函数等。接口结构注册通过调用函数netif_add完成,该函数除了使用3个IP地址作为参数外,还需另外两个函数地址作为参数,即ethernetif_init和ethernet_input。这两个函数地址会被赋值给netif结构的相关字段,内核通过这些字段指向的函数来完成网卡的初始化以及向上层递交数据。
利用FPGA上的JTAG接口将程序烧写至串行配置芯片EPCS64中,再通过SOPC Builder中CPU的配置,将RESET VECTOR指向EPCS_FLASH_CONTROLLER,此时程序会被下载到串行配置芯片中,串行配置芯片在通电时,将运行程序拷贝到代码运行区,并从reset address启动。SOPC中的exception address指定的是系统异常处理代码的存放处。若exception address和reset address不同,则程序从reset address启动后将放在reset address处的系统异常处理代码拷贝到exception address,设置如图5所示。
图5 系统的复位地址和异常处理地址
利用移植的协议栈中UDP协议,调用udpsend()函数往计算机发送数据,在计算机端,打开TCP&UDP测试工具,在FPGA中模拟数据产生模块,并向上位机发送递增码,从测试工具栏中,看到上位机接收到的数据。从接收窗口中,能看到捕获的udp数据包,是正常的16进制递增码,如图6所示。
图6 从上位机收到的数据图
通过提出基于FPGA的SOPC自定义MACIP核的设计思路,用Verilog HDL硬件语言编程,满足特殊器件的特殊要求,其从设计到实现验证,充分感受到SOPC的优势。SOPC将中央处理器和外围接口集成到一块芯片上,具有体积小、成本低、高精度的优点。而NIOS的可定制性,可根据需要添加组件,同时也可根据需要编写IP模块,具有较强的灵活性。此外,还可直接由C语言完成软件系统的开发设计,调用现成C语言算法,提高工作效率,且具有良好的便捷性和灵活性。
[1]周立功,张华.深入浅出ARM[M].北京:北京航空航天大学出版社,2005.
[2]李岩,荣盛祥.基于S3C44B0X嵌入式uClinux系统原理及应用[M].北京:清华大学出版社,2005.
[3]ARM Ltd.ARM7TDMI technical reference microprocessor[DB/OL].(2011-04-29)[2014-04-10]http://wenku.baidu.com/view/5a2b8b102d276a22f4a.html.
[4]杜春雷.ARM体系结构与编程[M].北京:清华大学出版社,2008.
[5]夏宇闻.Verilog数字系统设计教程[M].北京:北京航空航天大学出版社,2003.
[6]侯建军,郭勇.SOPC技术基础教程[M].北京:清华大学出版社,2008.
[7]Altera Crops.Nios Ⅱ processor reference handbook[EB/OL].(2009 -03-02)[2014 -04 -10]http://www.altera.com/literature/hb/nios2/n2cpu_nii5v1.pdf.
[8]Altera Conpration.Altera crops quartusⅡ简介[EB/OL].(2005-04-20)[2014-04-10]http://www.altera.com.cn/literature/manual/cn/intro_to_quartus2_chinese.pdf.
[9]王传新.FPGA设计基础[M].北京:高等教育出版社,2007.