|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
本帖最后由 free-arm 于 2012-3-28 18:37 编辑
不知道有没有人看过《源代码》这部电影。里面讲的是一个海军陆战队战士死了,但他的脑组织并没有完全死透。有科学机构把他的脑细胞放在一个全新的模拟环境中。当这个战士苏醒的时候,发现自己处在一个黑窖中。当然并不是说该战士真的苏醒了,而是他的脑组织开始活跃起来,他以为苏醒了,只是脑组织的一种感觉而已。镜头切换过去,是他躺在一个大箱子里,脑袋上插满了各种触头。他所以为的关在黑窖中,其实是这些触头传递给他的信息。
比如我们一觉醒来,看见窗外阳光明媚。这就是眼睛传递给我们的信息。现在这些触头绕过了眼睛,把“眼睛看到一片黑茫茫”这一信息传递给了大脑。那么大脑就认为自身出于一个大黑窖中。甚至他伸臂探腿,也会有某种触头发射给他某种信息,使得大脑“觉得”真的伸臂探腿了一样,当然,仅仅是感觉,大脑实际上仍然孤零零的躺在那儿。科学机构让他处在黑窖内,而不是花团锦簇的场所,就在于,模拟一个黑窖相对要容易一些。
我就曾经做过类似的事情。我也得到了一块“脑组织”,也把它复活了。这块“脑组织”是从一块ARM9的MCU开发板mini2440的NAND flash里面dump出来的。这块NAND flash的大小是256 MB,里面存放着完整的Linux操作系统。我要像做过很多次的Modelsim仿真一样,把这个完整的Linux操作系统启动起来。
我手中的材料只有一个开发完毕的兼容ARM9的软核处理器。它是兼容于ARM9的,也就是这块NAND flash的内容里面存放的指令,完全可以被它执行。于是,在阅读了mini2440的资料后,开始着手建立仿真环境。
初期的仿真环境比较简单。因为这个bin文件是NAND flash的内容,必须有一个.v来模拟nand flash的工作情况,在内核读取nand flash的时候,能够从bin文件对应的位置读出数据。因此,最终的仿真文件包含三个.v文件:tb.v, nand_flash.v, arm.v。其中tb.v是testbench文件;nand_flash.v会读取NAND flash的1.bin文件,在tb.v取flash数据时,找到相应的数据;arm.v自然是我们的兼容ARM9软核处理器。
首先,NAND flash的前4 K byte会读出来,作为启动程序。X86对应的是bios程序,嵌入式开发人员称它为boot程序。它会把Linux内核解压缩到sdram内。下面是tb.v中对应代码。
- reg [7:0] rom [4095:0];
- initial begin
- #1 for(i=0;i<2048;i=i+1)
- rom[i] = u_flash.flash[i];
- for(i=2048;i<4096;i=i+1)
- rom[i] = u_flash.flash[i+64];
- end
复制代码
中间的64 byte是校验数据,所以忽略掉了。这段程序最主要的任务是把Linux内核,解压缩加载入SDRAM内。该ARM9开发板mini2440的大小是:64 MB。
- reg [7:0] sdram[(1<<26)-1:0];
- integer i;
- initial for (i=0;i<(1<<26);i=i+1) sdram[i]=0;
复制代码
如此描述,64MB的sdram就实现了。在仿真的时候,我们只需要给出地址就可得到sdram的数据,例如sdram。那么,这就帮我省了很大的麻烦,不用考虑cache,tlb这些东西。
只有sdram远远不够。ARM9开发板上的ARM9 MCU也就是三星的sc2440芯片,连接了很多的外设。在Linux系统启动的时候,它会不断初始化这些外设。但在仿真的时候,实际上是没有这些外设的,而我只需要一个真正的外设,那就是UART串口——让它显示出启动的进程信息。
在没有这些实际的外设,怎么让Linux操作系统感觉有这些外设,正正常常的启动下去呢?这个问题,和《源代码》电影里“欺骗”脑组织的方式相同。Linux操作系统和外设发生联系,不外乎两种方式,一种是写外设,好比电影里脑组织发出拳打脚踢的指令,由于没有真正的拳和脚,这些指令自然是不理了。这里也采用同样的方式,除了串口外的写操作,一概不理。另外一种是读外设,它要获取外设的状态信息,这就不能不理了,电影里不理的话,大脑就不能激活,Linux也就认为外设处于异常状态,它也会歇菜了事。因此,对于读外设的操作,给它一个正确的信息,让Linux认定该外设正常,以便正常执行。
因此,我必须收集cpu处理器内核对sdram以外的读操作信息,并为读操作提供正确的数据。在知道了处理器对哪个地址发起了读操作后,根据软核处理器的执行状态,就能知道对应的指令地址。正好ARM9开发板有一个debug功能,能够设置断点。我知道了这条指令的地址,对它设一个断点,然后单步执行,我也就知道了开发板上给出的正确的读信息。获得这个读信息后,添加在tb.v里面,那么Linux操作系统就迈过了一个小坎,直到遇到读下一个未知的寄存器地址。
我就像一个侦察队员,为了深入敌穴,不断以假口令骗取Linux操作系统,以便进入要塞。唯一能够支撑我进行下去的是软核处理器的强劲性能。
再后来,随着Linux的不断执行,涉及到虚拟地址到物理地址的映射,我都采用sdram的数据按照arm architecture reference manual的要求,对它进行映射。如此,满足了Linux操作系统的执行要求。
下面两张图是Linux操作系统在启动初始和启动结束前的Modelsim仿真截图。如果有对这个仿真过程感兴趣的,可以在:http://code.google.com/p/arm-cpu-core/downloads/list下载整个仿真包。
这个仿真包采用的是100MHz时钟,全部仿真时间在8 s左右。因此,在下载完linux.rar后,使用Modelsim对tb_reload.v, nand_flash.v和arm.v进行编译。选择tb_kernel,一定要选中“Simulation with full optimization”,不然速度会很慢。但即便如此,全部跑完这8 s,也就是输入run 8000 ms,也会花上五个小时以上。特别是在前面两条语句:
- # load Image of Linux...
- #
- # Uncompressing Linux................................................................................................................................................... done, booting the kernel.
复制代码 中间的每一个圆点,都会花上很长时间才能打印出来。
感兴趣的打开我的.v文件,会发现我.v写法完全是设计工程师建立仿真过程的通常做法。我本质上只对verilog有一些心得。真的要整合嵌入式资源,为处理器软核配上各种外设,以及cache, tlb, 虚拟地址转换、安全检查,还有很长的路要走。这个仿真过程不过是一个show,向着使用32位处理器启动Linux操作系统,发动一次探险。
我个人只是擅长verilog,想使用verilog做一些事情。希望得到大家的支持,使得我们使用FPGA的,也能做出一些成绩出来,希望得到大家的支持。因此,我会陆续推出各种不同处理器内核,希望能够帮到大家。
借用一句谚语结束:一个人可以走的很快,但是更多的人在一起才能走的更远。
|
|