跟我寫ARM處理器之一:從寫module arm開始
在寫之前,我要申明兩點精神。這兩點精神當然不是我創(chuàng)造的,我只是引用起來,讓大家更能讀下去,能相信我是能創(chuàng)造這個奇跡的,當然你也能創(chuàng)造這個奇跡的。第一點就是毛主席在軍事上經(jīng)常用的“分而殲之”,在政治上的意思就是“拉一派,打一派”。這一招在毛主席的斗爭生涯中屢試不爽,成就了他成了偉人。這一點國外叫做“divide and conqur(沒拼寫對,懶得查了)",也是很重要的一個方法。所以在面對龐然大物的時候,千萬別害怕,一定要祭起這個”法寶“。第一步,先試著“divide",一定讓這個龐然大物小起來,然后再小下去,先條分縷析了,已經(jīng)算成功了一大半了;第二步,從最小的開始,一點點的做,做對了,做好了。好到什么程度?好到這一小點絕不會打擾我們繼續(xù)征服下一小點為至。那么征服這個龐然大物就只是時間問題了。包括我現(xiàn)在寫這個文章,就得用這個精神,不然的話,千頭萬緒,從哪里說呢?從哪里說的清呢?不用怕,我既然用這個方法征服了ARM core,那么把它講出來,講明白,絕對比寫arm core要簡單,我相信我也能夠完成的。
但是我缺一點東西:那就是視角問題。因為我是站在我的立場上,我了解一切,我講的時候,只是想當然的從我的角度認為大家該了解什么。但實際上,這中間的差距,就像夢想和現(xiàn)實的差距一樣遠。所以我需要大家有反饋,那一點忽略了,及時提醒我,讓我始終站在大家的立場上,講東西,而不是讓我自說自話。如果我自說自話,效果非常差。所以請大家成全我,成全我就是成全自己。如果可能,請及時提出不明白的地方。讓我把這今天的這一小節(jié)征服到不會打擾我征服下一小節(jié),這是符合我上面的精神。
有網(wǎng)友,可能會問,我費心費力的圖什么?為什么要成全我?我圖啥呢?反正我從小也算一個調(diào)皮的孩子,越是大人不讓我干的事情,我還是愿意冒險試一下。當然總體來說,我小時候也算聽話,屬于只做”建設(shè)性“破壞的人,掏馬蜂窩、堵煙筒這事不干。現(xiàn)在有一件特別有意義的事情,比如ARM公司的這些達人們,賣ARM7核賣的不亦樂乎。突然,我闖進來,說這東西根本不值錢,你得賣真貨,不是特別有意思么?ARM公司越不爽,其實對于大家來說越是爽。因為大家總體的水平提高了,那么ARM公司就必須努力提高自己的水平,這樣才能凸顯他自己的價值。所以這件事情想起來就特別有意思,所以我就決定做這么一件”建設(shè)性“破壞的事情。所以請大家成全我,成全別人其實也是成就自己,請大家和我一起實踐吧。所以,我如果是個軟件工程師,我一定會寫些病毒啥的,有意思呀!但放心我只會做“建設(shè)性”的,我做的病毒絕不會給大家?guī)硖嗦闊?,因為這不符合我的風(fēng)格。但我現(xiàn)在既然是一個硬件工程師,就得想方法在硬件上做一些大事。做一些讓讓某些“大人”不爽的事。人在世上,也就圖一樂嘛。呵呵,說多了。
說了半天,還沒有說第二點精神。其實第二點也就包括在第一點上了。不過還是有分別的。這第二點精神就是古人的”格物致知“的功夫。古代這些儒學(xué)大家們經(jīng)常對著一花一葉格個半天啥的,就是這種精神的極致。"divide and conqur"只是斗爭原則,但是怎么conqur呢?我覺得要用古人的”格物致知“,也就是耐得煩,從最細小的東西”格“起。我在后面對每一個net,每一個wire都描述出來,就是這樣”格“的結(jié)果。cpu是一套復(fù)雜的系統(tǒng),要做的好,就得用net, wire, register搭起來,聽說intel就是這么干的。不過我是和它有分別的。因為我的這一套,還是把很多功夫交給綜合器完成,我只是描述出來,讓綜合器明白而已。
閑話休提,我希望大家看了我這一系列的文章后,能夠把我的arm核寫出來。當然你能發(fā)揮,我希望的是大家發(fā)揮,把這個核寫的更好。因為我在做離經(jīng)叛道的事情,哪能希望別人”墨守成規(guī)“把我的核當成標桿?我只是希望拋磚引玉。我要拋出一塊磚,對arm這個皇帝的新衣說出:你根本沒穿衣服!難道我知道這個了,不應(yīng)該告訴大家么?所以盡情的糟蹋我的arm核吧,因為這樣,它存在的意義更大。
開始寫了:第一句是: module arm ( 。這恐怕是verilog設(shè)計的經(jīng)典開篇了。然后是什么?是定義接口。接口其實規(guī)定了大部分的功能,對于IP核的重用,交代清楚接口,跟下家說明清楚,別人才好用核。
module arm (
clk,
rst,
cpu_en,
clk是時鐘,rst是異步復(fù)位信號。這個就不需要我多解釋了。cpu_en是什么?cpu_en是同步使能信號。也就是說只有在cpu_en==1b1時,整個核才工作。如果cpu_en==1b0時,那么這個arm 核就不工作了。簡單的說,就是在這個verilog文件里面的所有register都不做什么改變。這就好像有些童話里面說的“時間停止”,城堡里面的人都靜住了,一切都停止了。那么寄存器就屬于住在城堡里面的人,因為只要他們安靜了,沒有活物了,那些依靠人而存在的工具就不會動了。這個cpu_en對于整個模塊也是重要的,比如你不想讓它工作了,就可讓cpu_en==1b0,那么他就不工作。再讓他工作,只要讓"cpu_en==1b1"就可。我在這個FPGA的項目中,就應(yīng)用這個輸入連到一個“開關(guān)”上。如果扳到"1b1",那系統(tǒng)開始工作;如果扳到"1b0",那它就停住,我就通過串口,把新的code下到它的rom中。
cpu_restart,
irq,
fiq,
rom_abort,
ram_abort,
這是ARM的五個中斷源,具體的可以參考ARM的文檔,我在這里只是簡略帶一遍。cpu_restart相當于一個同步復(fù)位,它只要是高電平,那么系統(tǒng)又重頭開始了。irq,fiq是兩個中斷,只要它等于“1b1”如果cpsr沒關(guān)掉它,就得執(zhí)行相應(yīng)的中斷。rom_abort, ram_abort是對應(yīng)于rom,ram讀錯誤,則啟動一個中斷來處理這些事情。
rom_en,
rom_addr,
rom_data,
這三個信號連接到ROM中,是指令的來源。取指令的方法是:rom_en==1b1時,在下一個時鐘,存放在rom_addr位置的code就出現(xiàn)在rom_data了。當然如果rom_en==1b0,則rom_data保持原來的值不變。這是一個非常普通的ROM。取指令的主動權(quán)掌握在ARM核中。如果它要處理非常復(fù)雜的指令,一個周期根本處理不過來,那怎么辦?那就不啟動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==1b1時,開始執(zhí)行對RAM的操作,同時ram_wen==1b1,執(zhí)行寫操作,把ram_wdata寫入ram_addr對應(yīng)的位置;如果ram_wen==1b0,表示是讀操作,就得在下一個時鐘,把放在ram_addr的數(shù)據(jù)出現(xiàn)在ram_rdata。
ram_flag是我新增加的。因為RAM里面出現(xiàn)了LDRB, STRH這樣對字節(jié)、字的操作。為了操作簡單,我給每一個字節(jié)對應(yīng)了一個標志位:如果ram_flag[0]==1b1表示第一個字節(jié)的操作有效;如果ram_flag[0]==1b1,則讀寫操作對第一個字節(jié)無效。比如我執(zhí)行STRB 0x4000_0000,則ram_flag==4b0001, 表示只對地址0x4000_0000的低8bit進行寫入。如果STRH 0x4000_0002,則ram_flag==4b1100, 表示寫入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;
好了,本篇到此結(jié)束,下一節(jié)再見!
評論