在写之前,我要申明两点精神。这两点精神当然不是我创造的,我只是引用起来,让大家更能读下去,能相信我是能创造这个奇迹的,当然你也能创造这个奇迹的。第一点就是毛主席在军事上经常用的“分而歼之”,在政治上的意思就是“拉一派,打一派”。这一招在毛主席的斗争生涯中屡试不爽,成就了他成了伟人。这一点国外叫做“divide and conqur(没拼写对,懒得查了)",也是很重要的一个方法。所以在面对庞然大物的时候,千万别害怕,一定要祭起这个”法宝“。第一步,先试着“divide",一定让这个庞然大物小起来,然后再小下去,先条分缕析了,已经算成功了一大半了;第二步,从最小的开始,一点点的做,做对了,做好了。好到什么程度?好到这一小点绝不会打扰我们继续征服下一小点为至。那么征服这个庞然大物就只是时间问题了。包括我现在写这个文章,就得用这个精神,不然的话,千头万绪,从哪里说呢?从哪里说的清呢?不用怕,我既然用这个方法征服了ARM core,那么把它讲出来,讲明白,绝对比写arm core要简单,我相信我也能够完成的。
但是我缺一点东西:那就是视角问题。因为我是站在我的立场上,我了解一切,我讲的时候,只是想当然的从我的角度认为大家该了解什么。但实际上,这中间的差距,就像梦想和现实的差距一样远。所以我需要大家有反馈,那一点忽略了,及时提醒我,让我始终站在大家的立场上,讲东西,而不是让我自说自话。如果我自说自话,效果非常差。所以请大家成全我,成全我就是成全自己。如果可能,请及时提出不明白的地方。让我把这今天的这一小节征服到不会打扰我征服下一小节,这是符合我上面的精神。
有网友,可能会问,我费心费力的图什么?为什么要成全我?我图啥呢?反正我从小也算一个调皮的孩子,越是大人不让我干的事情,我还是愿意冒险试一下。当然总体来说,我小时候也算听话,属于只做”建设性“破坏的人,掏马蜂窝、堵烟筒这事不干。现在有一件特别有意义的事情,比如ARM公司的这些达人们,卖ARM7核卖的不亦乐乎。突然,我闯进来,说这东西根本不值钱,你得卖真货,不是特别有意思么?ARM公司越不爽,其实对于大家来说越是爽。因为大家总体的水平提高了,那么ARM公司就必须努力提高自己的水平,这样才能凸显他自己的价值。所以这件事情想起来就特别有意思,所以我就决定做这么一件”建设性“破坏的事情。所以请大家成全我,成全别人其实也是成就自己,请大家和我一起实践吧。所以,我如果是个软件工程师,我一定会写些病毒啥的,有意思呀!但放心我只会做“建设性”的,我做的病毒绝不会给大家带来太多麻烦,因为这不符合我的风格。但我现在既然是一个硬件工程师,就得想方法在硬件上做一些大事。做一些让让某些“大人”不爽的事。人在世上,也就图一乐嘛。呵呵,说多了。
说了半天,还没有说第二点精神。其实第二点也就包括在第一点上了。不过还是有分别的。这第二点精神就是古人的”格物致知“的功夫。古代这些儒学大家们经常对着一花一叶格个半天啥的,就是这种精神的极致。"divide and conqur"只是斗争原则,但是怎么conqur呢?我觉得要用古人的”格物致知“,也就是耐得烦,从最细小的东西”格“起。我在后面对每一个net,每一个wire都描述出来,就是这样”格“的结果。cpu是一套复杂的系统,要做的好,就得用net, wire, register搭起来,听说intel就是这么干的。不过我是和它有分别的。因为我的这一套,还是把很多功夫交给综合器完成,我只是描述出来,让综合器明白而已。
闲话休提,我希望大家看了我这一系列的文章后,能够把我的arm核写出来。当然你能发挥,我希望的是大家发挥,把这个核写的更好。因为我在做离经叛道的事情,哪能希望别人”墨守成规“把我的核当成标杆?我只是希望抛砖引玉。我要抛出一块砖,对arm这个皇帝的新衣说出:你根本没穿衣服!难道我知道这个了,不应该告诉大家么?所以尽情的糟蹋我的arm核吧,因为这样,它存在的意义更大。
开始写了:第一句是: module arm ( 。这恐怕是verilog设计的经典开篇了。然后是什么?是定义接口。接口其实规定了大部分的功能,对于IP核的重用,交代清楚接口,跟下家说明清楚,别人才好用核。
module arm (
clk,
rst,
cpu_en,
clk是时钟,rst是异步复位信号。这个就不需要我多解释了。cpu_en是什么?cpu_en是同步使能信号。也就是说只有在cpu_en==1'b1时,整个核才工作。如果cpu_en==1'b0时,那么这个arm 核就不工作了。简单的说,就是在这个verilog文件里面的所有register都不做什么改变。这就好像有些童话里面说的“时间停止”,城堡里面的人都静住了,一切都停止了。那么寄存器就属于住在城堡里面的人,因为只要他们安静了,没有活物了,那些依靠人而存在的工具就不会动了。这个cpu_en对于整个模块也是重要的,比如你不想让它工作了,就可让cpu_en==1'b0,那么他就不工作。再让他工作,只要让"cpu_en==1'b1"就可。我在这个FPGA的项目中,就应用这个输入连到一个“开关”上。如果扳到"1'b1",那系统开始工作;如果扳到"1'b0",那它就停住,我就通过串口,把新的code下到它的rom中。
cpu_restart,
irq,
fiq,
rom_abort,
ram_abort,
这是ARM的五个中断源,具体的可以参考ARM的文档,我在这里只是简略带一遍。cpu_restart相当于一个同步复位,它只要是高电平,那么系统又重头开始了。irq,fiq是两个中断,只要它等于“1'b1”如果cpsr没关掉它,就得执行相应的中断。rom_abort, ram_abort是对应于rom,ram读错误,则启动一个中断来处理这些事情。
rom_en,
rom_addr,
rom_data,
这三个信号连接到ROM中,是指令的来源。取指令的方法是:rom_en==1'b1时,在下一个时钟,存放在rom_addr位置的code就出现在rom_data了。当然如果rom_en==1'b0,则rom_data保持原来的值不变。这是一个非常普通的ROM。取指令的主动权掌握在ARM核中。如果它要处理非常复杂的指令,一个周期根本处理不过来,那怎么办?那就不启动rom_en,只有当处理完了,有空闲了再启动rom_en,更新rom_data。
ram_cen,
ram_wen,
ram_addr,
ram_wdata,
ram_rdata,
ram_flag
);
前五个“ram_cen,ram_wen,ram_addr,ram_wdata,ram_rdata”是典型的单端口RAM的接口。功能是:在ram_cen==1'b1时,开始执行对RAM的操作,同时ram_wen==1'b1,执行写操作,把ram_wdata写入ram_addr对应的位置;如果ram_wen==1'b0,表示是读操作,就得在下一个时钟,把放在ram_addr的数据出现在ram_rdata。
ram_flag是我新增加的。因为RAM里面出现了LDRB, STRH这样对字节、字的操作。为了操作简单,我给每一个字节对应了一个标志位:如果ram_flag[0]==1'b1表示第一个字节的操作有效;如果ram_flag[0]==1'b1,则读写操作对第一个字节无效。比如我执行STRB 0x4000_0000,则ram_flag==4'b0001, 表示只对地址0x4000_0000的低8bit进行写入。如果STRH 0x4000_0002,则ram_flag==4'b1100, 表示写入0x4000_0000的高 2 byte。
所以我建议连上4块RAM,每块RAM的位宽都是8 bit。让ARM核对每byte的操作是独立的。那每一块的cen就是:ram_cen&ram_flag[3]; ram_cen&ram_flag[2]; ram_cen&ram_flag[1]; ram_cen&ram_flag[0]。
好了,接下来,就是他们位宽的定义:
input clk;
input rst;
input cpu_en;
input cpu_restart;
input irq;
input fiq;
input rom_abort;
input ram_abort;
output rom_en;
output [31:0] rom_addr;
input [31:0] rom_data;
output ram_cen;
output ram_wen;
output [31:0] ram_addr;
output [31:0] ram_wdata;
input [31:0] ram_rdata;
output [31:0] ram_flag;
好了,本篇到此结束,下一节再见!
上一篇:跟我写ARM处理器之二:主体结构的确定
下一篇:u-boot在s3c2410开发板上移植过程
推荐阅读最新更新时间:2024-03-16 15:00