SkyEye硬件模拟平台:硬件仿真实现之六

本系列文章主要介绍了SkyEye硬件模拟平台的实现细节。主要内容包括SkyEye的总体设计、SkyEye的可扩展框架、SkyEye的关键数据结构、SkyEye对各种CPU的模拟实现、SkyEye对各种外设的模拟实现、如何安装使用SkyEye以及如何扩展SkyEye的仿真模块等。对SkyEye的深入了解,有助于对嵌入式硬件系统有更深入的认识,特别是对操作系统、驱动程序如何与嵌入式硬件系统进行交互有更深刻的了解。

1.1 改动和扩展SkyEye
对SkyEye的扩展可以在三个层次上,一是加入新的体系结构,如X86、MIPS等;二是在已有的体系结构下添加新的开发板,如你可以在ARM体系结构中添加Lubbock开发板;第三种就是在SkyEye已经模拟的开发板上添加新的硬件。

目前SkyEye模拟的体系结构相关目录都在sim目录中,如sim/arm是模拟arm体系结构的开发板,sim/ppc是模拟ppc体系结构的开发板,sim/mips是模拟mips体系结构中的开发板等等。如果需要加新的体系结构进去,需要在sim/目录下新建一个目录,把你的相关代码放入。而加新的开发板进去,则要视所加具体开发板处理器的体系结构而定,来重用已有代码。

下面我们以在ep7312开发板上扩展8019网络芯片为例,来讲解如何在模拟的ep7312开发板加入网络芯片模拟。驱动程序作为底层硬件和操作系统之间的接口,管理硬件,并为操作系统屏蔽底层硬件,提供服务。

我们需要做两件事情,操作系统的驱动程序如何可以访问我们虚拟网络芯片的数据和控制信息?在虚拟网络芯片接收到数据包时,如何通知CPU发出中断,通知驱动程序处理到达的数据包?

我们在ep7312的硬件手册上可以看到它的地址分布:

起始地址 用途 大小
0x80004000 未使用 ~1G
0x80000000 内部寄存器 8k
0x70000000 BootRom(nCS[7]) 128字节

在这里,我们是使用0x8000a000为起始地址,大小为 255字节的地址空间作为虚拟网络芯片的io内存,供驱动程序访问。同时我们选择了尚未被使用的外部中断号EINT1作为我们的网络中断。关于中断寄存器的定义请参考ep7312的相关文档。

相关代码在sim/arm/skyeye_mach_ep7312.c的ep7312_io_reset函数中:


io.net_int = EINT1; /* Here we use RINT1 as netcard interrupt
io.net_io_baseaddr = 0x8000a000; /* netcard iomem start address*/
io.net_io_size = 255; /* netcard iomeme size*/

下面我们来看一下虚拟网络芯片的硬件中断是如何产生的:

图 0-1 中断处理流程图

在这里,有些人会问,我们产生中断之后,谁来处理?首先我们要明确,硬件只产生中断,如何处理则是操作系统的任务,虚拟网络芯片会将自己相应的中断置位,由操作系统轮询中断状态寄存器,并调用网络芯片的驱动程序在初始化时所注册的中断处理程序处理中断。需要注意的是,在处理完中断之后,一定要清除相应的中断位,否则后面的中断无法进来。

SkyEye的相关代码如下:


//判断当前模拟开发板的网络选项是否打开,并且当前是否已经有中断在处理
if(skyeye_net_on && !(io.intsr & io.net_int)){
fd_set frds;
	struct timeval tv;
	FD_ZERO(&frds);		
	skyeye_net_fdset(&frds);
	tv.tv_sec = 0;
	tv.tv_usec = 0;
	ret = 0;
//判断虚拟网络接口是否接收到数据,如果有,则转入网络芯片的接收处理函数
	if((ret = select(skyeye_net_maxfd+1,&frds,NULL,NULL,&tv))>0){
		skyeye_net_input(&frds,state);
	}
}
下面是网络芯片接收函数skyeye_net_input
void  tapif_input(int tapif_fd, ARMul_State *state)
{

…………………………………………
//这里省略大段网络芯片接收数据的代码
……………………………………………




//如果接收数据正常,则调用SET_NET_INT()来给相应的中断置位
 if((ISR_PRX & rtl8019.IMR)){
    
	SET_NET_INT();		
   skyeye_config.mach->mach_update_int(state);
  }
  DBG_PRINT("tapif_input end/n");
}

SET_NET_INT();是一个定义在skyeye-ne2k.c的宏,定义如下: #define SET_NET_INT() *state->mach_io.instr |= *state->mach_io.net_int 这样我们便完成了和驱动程序通信的任务。

在这里我们并没有指定特定的开发板,所有的开发板和CPU的细节被放到了state这个结构指针中,这样我们可以在不同的开发板和CPU上不加更改的重用这段代码。

在这里我们还需要注意的一个细节是,对于有MMU的CPU来说,驱动程序看到的地址是经过MMU变换的虚拟地址。至于具体到ep7312开发板,对应于我们虚拟网络芯片的io内存的虚地址为0xffffa000。

1.2 小结
本文讲解了SkyEye硬件模拟平台的实现细节,以及如何扩展SkyEye。了解SkyEye的实现细节可以让嵌入式系统开发人员对嵌入式系统硬件的运行机理有更深入的掌握,特别是对操作系统、驱动程序如何与嵌入式硬件

你可能感兴趣的:(SkyEye硬件模拟平台:硬件仿真实现之六)