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