大俠好,歡迎來到FPGA技術(shù)江湖,江湖偌大,相見即是緣分。大俠可以關(guān)注FPGA技術(shù)江湖,在“闖蕩江湖”、"行俠仗義"欄里獲取其他感興趣的資源,或者一起煮酒言歡。
今天給大俠帶來基于FPGA的電子計(jì)算器設(shè)計(jì)。話不多說,上貨。
本篇介紹了一個(gè)簡單計(jì)算器的設(shè)計(jì),基于 FPGA 硬件描述語言 Verilog HDL,系統(tǒng)設(shè)計(jì)由計(jì)算部分、顯示部分和輸入部分四個(gè)部分組成,計(jì)算以及存儲主要用狀態(tài)機(jī)來實(shí)現(xiàn)。顯示部分由六個(gè)七段譯碼管組成,分別來顯示輸入數(shù)字,輸入部分采用4*4矩陣鍵盤,由0-9一共十個(gè)數(shù)字按鍵,加減乘除四個(gè)運(yùn)算符按鍵,一個(gè)等號按鍵組成的。通過外部的按鍵可以完成加、減、乘、除四種功能運(yùn)算,其結(jié)構(gòu)簡單,易于實(shí)現(xiàn)。本篇為本人畢業(yè)設(shè)計(jì)部分整理,各位大俠可依據(jù)自己的需要進(jìn)行閱讀,參考學(xué)習(xí)。
在國外,電子計(jì)算器在集成電路發(fā)明后,只用短短幾年時(shí)間就完成了技術(shù)飛躍,經(jīng)過激烈的市場競爭,現(xiàn)在的計(jì)算器技術(shù)己經(jīng)相當(dāng)成熟。計(jì)算器已慢慢地脫離原來的“輔助計(jì)算工具”的功能定位,正在向著多功能化、可編程化方向發(fā)展,在各個(gè)領(lǐng)域都得到了廣泛的應(yīng)用。用計(jì)算器不僅可以實(shí)現(xiàn)各種各樣復(fù)雜的數(shù)學(xué)計(jì)算還可以用來編制、運(yùn)行程序,甚至解方程組,圖形計(jì)算器還可以進(jìn)行圖形處理。計(jì)算器內(nèi)置的軟件允許用戶進(jìn)行類似于對計(jì)算機(jī)的文件和目錄管理等操作,允許用戶對圖形界面進(jìn)行定制,同時(shí)各種新技術(shù)也被應(yīng)用到計(jì)算器里使計(jì)算器功能越來越強(qiáng)大??梢哉f,計(jì)算器就是一個(gè)“微微型”的計(jì)算機(jī)。國內(nèi)也有廠商利用計(jì)算器芯片開發(fā)新的產(chǎn)品,但對計(jì)算器技術(shù)的研究、計(jì)算器芯片的設(shè)計(jì)還處于起步階段。計(jì)算器的主要功能還是在于“計(jì)算”,不妨稱之為“低檔計(jì)算器”。即便是對這種計(jì)算器,很多廠商也只從事計(jì)算器的組裝、銷售業(yè)務(wù)。一些IC設(shè)計(jì)公司、芯片提供商也開始研究計(jì)算器技術(shù)。
本次設(shè)計(jì)基于現(xiàn)場可編程邏輯器件FPGA進(jìn)行設(shè)計(jì),應(yīng)用硬件描述語言Verilog編程并在Altera公司的QuartusⅡ軟件上實(shí)現(xiàn)仿真。需要進(jìn)行計(jì)算器的常用運(yùn)算功能的實(shí)現(xiàn),通過外接鍵盤輸入、LED數(shù)碼顯示來達(dá)成運(yùn)算目的。
一、緒論
Verilog HDL 是一種硬件描述語言(HDL:Hardware Description Language),以文本形式來描述數(shù)字系統(tǒng)硬件的結(jié)構(gòu)和行為的語言,用它可以表示邏輯電路圖、邏輯表達(dá)式,還可以表示數(shù)字邏輯系統(tǒng)所完成的邏輯功能。Verilog HDL和VHDL是世界上最流行的兩種硬件描述語言,都是在20世紀(jì)80年代中期開發(fā)出來的。前者由Gateway Design Automation公司(該公司于1989年被Cadence公司收購開發(fā))。兩種HDL均為IEEE標(biāo)準(zhǔn)。
1.1 Verilog HDL?的發(fā)展
Verilog是由Gateway設(shè)計(jì)自動(dòng)化公司的工程師于1983年末創(chuàng)立的。當(dāng)時(shí)Gateway設(shè)計(jì)自動(dòng)化公司還叫做自動(dòng)集成設(shè)計(jì)系統(tǒng)(Automated Integrated Design Systems),1985年公司將名字改成了前者。該公司的菲爾·莫比(Phil Moor by)完成了Verilog的主要設(shè)計(jì)工作。1990年,Gateway設(shè)計(jì)自動(dòng)化被Cadence公司收購。
1990年代初,開放Verilog國際(Open Verilog International,OVI)組織(即現(xiàn)在的Accellera)成立,Verilog面向公有領(lǐng)域開放。1992年,該組織尋求將Verilog納入電氣電子工程師學(xué)會標(biāo)準(zhǔn)。最終,Verilog成為了電氣電子工程師學(xué)會1364-1995標(biāo)準(zhǔn),即通常所說的Verilog-95。
設(shè)計(jì)人員在使用這個(gè)版本的Verilog的過程中發(fā)現(xiàn)了一些可改進(jìn)之處。為了解決用戶在使用此版本Verilog過程中反映的問題,Verilog進(jìn)行了修正和擴(kuò)展,這部分內(nèi)容后來再次被提交給電氣電子工程師學(xué)會。這個(gè)擴(kuò)展后的版本后來成為了電氣電子工程學(xué)會1364-2001標(biāo)準(zhǔn),即通常所說的Verilog-2001。Verilog-2001是對Verilog-95的一個(gè)重大改進(jìn)版本,它具備一些新的實(shí)用功能,例如敏感列表、多維數(shù)組、生成語句塊、命名端口連接等。目前,Verilog-2001是Verilog的最主流版本,被大多數(shù)商業(yè)電子設(shè)計(jì)自動(dòng)化軟件包支持。
2005年,Verilog再次進(jìn)行了更新,即電氣電子工程師學(xué)會1364-2005標(biāo)準(zhǔn)。該版本只是對上一版本的細(xì)微修正。這個(gè)版本還包括了一個(gè)相對獨(dú)立的新部分,即Verilog-AMS。這個(gè)擴(kuò)展使得傳統(tǒng)的Verilog可以對集成的模擬和混合信號系統(tǒng)進(jìn)行建模。容易與電氣電子工程師學(xué)會1364-2005標(biāo)準(zhǔn)混淆的是加強(qiáng)硬件驗(yàn)證語言特性的SystemVerilog(電氣電子工程師學(xué)會1800-2005標(biāo)準(zhǔn)),它是Verilog-2005的一個(gè)超集,它是硬件描述語言、硬件驗(yàn)證語言(針對驗(yàn)證的需求,特別加強(qiáng)了面向?qū)ο筇匦裕┑囊粋€(gè)集成。
2009年,IEEE 1364-2005和IEEE 1800-2005一共兩個(gè)部分合并為IEEE 1800-2009,成為了一個(gè)新的、統(tǒng)一的SystemVerilog硬件描述驗(yàn)證語言(hardware description and verification language,HDVL)。
1.2?Verilog?HDL?的特點(diǎn)
描述復(fù)雜的硬件電路,設(shè)計(jì)人員總是將復(fù)雜的功能劃分為簡單的功能,模塊是提供每個(gè)簡單功能的基本結(jié)構(gòu)。設(shè)計(jì)人員可以采取“自頂向下”的思路,將復(fù)雜的功能模塊劃分為低層次的模塊。這一步通常是由系統(tǒng)級的總設(shè)計(jì)師完成,而低層次的模塊則由下一級的設(shè)計(jì)人員完成。自頂向下的設(shè)計(jì)方式有利于系統(tǒng)級別層次劃分和管理,并提高了效率、降低了成本?!白缘紫蛏稀狈绞绞恰白皂斚蛳隆狈绞降哪孢^程。
1.3?Verilog?HDL?的語言結(jié)構(gòu)
Verilog的設(shè)計(jì)初衷是成為一種基本語法與C語言相近的硬件描述語言。這是因?yàn)镃語言在Verilog設(shè)計(jì)之初,已經(jīng)在許多領(lǐng)域得到廣泛應(yīng)用,C語言的許多語言要素已經(jīng)被許多人習(xí)慣。一種與C語言相似的硬件描述語言,可以讓電路設(shè)計(jì)人員更容易學(xué)習(xí)和接受。不過,Verilog與C語言還是存在許多差別。另外,作為一種與普通計(jì)算機(jī)編程語言不同的硬件描述語言,它還具有一些獨(dú)特的語言要素,例如向量形式的線網(wǎng)和寄存器、過程中的非阻塞賦值等??偟膩碚f,具備C語言的設(shè)計(jì)人員將能夠很快掌握Verilog硬件描述語言。下面介紹Verilog語言基本規(guī)范:
1)空白符
空白符是指代碼中的空格(對應(yīng)的轉(zhuǎn)義標(biāo)識符為b)、制表符(t)和換行(n)。如果這些空白符出現(xiàn)在字符串里,那么它們不可忽略。除此之外,代碼中的其他空白符在編譯的時(shí)候都將會被視為分隔標(biāo)識符,即使用2個(gè)空格或者1個(gè)空格并無影響。不過,在代碼中使用合適的空格,可以讓上下行代碼的外觀一致(例如使賦值運(yùn)算符位于同一個(gè)豎直列),從而提高代碼的可讀性。
2)注釋
為了方便代碼的修改或其他人的閱讀,設(shè)計(jì)人員通常會在代碼中加入注釋。與C語言一樣,有兩種方式書寫注釋。第一種為多行注釋,即注釋從/*開始,直到*/才結(jié)束;另一種為單行注釋,注釋從//開始,從這里到這一行末尾的內(nèi)容會被系統(tǒng)識別為注釋。
3)某些電子設(shè)計(jì)自動(dòng)化工具,會識別出代碼中以特殊格式書寫、含有某些預(yù)先約定關(guān)鍵詞的注釋,并從這些注釋所提取有用的信息。這些注釋不是供人閱讀,而是向第三方工具提供有關(guān)設(shè)計(jì)項(xiàng)目的額外信息。例如,某些邏輯綜合工具可以從注釋中讀取綜合的約束信息。
4)大小寫敏感性
Verilog是一種大小寫敏感的硬件描述語言。其中,它的所有系統(tǒng)關(guān)鍵字都是小寫的。
5)標(biāo)識符及保留字
Verilog代碼中用來定義語言結(jié)構(gòu)名稱的字符稱為標(biāo)識符,包括變量名、端口名、模塊名等等。標(biāo)識符可以由字母、數(shù)字、下劃線以及美元符($)來表示。但是標(biāo)識符的第一個(gè)字符只能是字母、數(shù)字或者下劃線,不能為美元符,這是因?yàn)橐悦涝_始的標(biāo)識符和系統(tǒng)任務(wù)的保留字沖突。
和其他許多編程語言類似,Verilog也有許多保留字(或稱為關(guān)鍵字),用戶定義的標(biāo)識符不能夠和保留字相同。Verilog的保留字均為小寫。變量類型中的wire、reg、integer等、表示過程的initial、always等,以及所有其他的系統(tǒng)任務(wù)、編譯指令,都是關(guān)鍵字。可以查閱官方文獻(xiàn)以完整的關(guān)鍵字的列表。
1.4 FPGA開發(fā)環(huán)境簡介
系統(tǒng)電路的軟件設(shè)計(jì)可采用工具軟件Quartus Ⅱ,用該工具軟件所支持的語言——硬件描述語言,以文本的方式進(jìn)行編程輸入。在編程時(shí)分別對控制、計(jì)數(shù)、鎖存、譯碼等電路模塊進(jìn)行Verilog文本描述,使每個(gè)電路模塊以及器件都以文本的形式出現(xiàn),然后通過編譯、波形分析、仿真、調(diào)試來完善每個(gè)器件的功能。單個(gè)器件制作完成后,然后將它們生成庫文件,并產(chǎn)生相應(yīng)的符號,最后用語言將各個(gè)已生成庫文件的器件的各個(gè)端口連接在一起,從而形成了系統(tǒng)主電路的軟件結(jié)構(gòu)。在連接器件時(shí),也可以采用圖形輸入方式,即在圖形輸入界面中調(diào)出先制作好的庫文件器件符號,再將每個(gè)器件符號的各端口直接連線,從而構(gòu)成系統(tǒng)主電路。在上述工作的基礎(chǔ)上,再進(jìn)行波形分析、仿真調(diào)試便完成整個(gè)軟件設(shè)計(jì)。
二、現(xiàn)場可編程門陣列(FPGA)簡介
2.1?可編程邏輯器件簡介
可編程邏輯器件(PLD——Programmable Logic Devices)是一種由用戶編程以實(shí)現(xiàn)某種邏輯功能的新型邏輯器件。它誕生于20世紀(jì)70年代,在20世紀(jì)80年代以后,隨著集成電路技術(shù)和計(jì)算機(jī)技術(shù)的發(fā)展而迅速發(fā)展起來的??删幊踢壿嬈骷詥柺酪詠?,PLD經(jīng)歷了從PROM、PLA、PAL、GAL到FPGA、ispLSI等高密度PLD的發(fā)展過程。在此期間,PLD的集成度、速度不斷提高,功能不斷增強(qiáng),結(jié)構(gòu)趨于更合理,使用變得更靈活方便。PLD的出現(xiàn)打破了由中小型通用型集成電路和大規(guī)模專用集成電路壟斷的局面。與中小規(guī)模通用型集成電路相比,用PLD實(shí)現(xiàn)數(shù)字系統(tǒng),有研制周期短、先期投資少、無風(fēng)險(xiǎn)、修改邏輯設(shè)計(jì)方便、小批量生產(chǎn)成本低等優(yōu)勢。
隨著可編程邏輯器件性能價(jià)格比的不斷提高,EDA開發(fā)軟件的不斷完善,現(xiàn)代電子系統(tǒng)的設(shè)計(jì)將越來越多地使用可編程邏輯器件,特別是大規(guī)??删幊踢壿嬈骷H绻f一個(gè)電子系統(tǒng)可以像積木堆積起來的話,那么現(xiàn)在構(gòu)成許多電子系統(tǒng)僅僅需要3種標(biāo)準(zhǔn)的積木塊——微處理器、存儲器和可編程邏輯器件,甚至只需一塊大規(guī)??删幊踢壿嬈骷AL(Programmable Array Logic)器件是20世紀(jì)70年代末期出現(xiàn)的一種低密度、一次性可編程邏輯器件。GAL(Generic Array Logic)器件是繼PAL器件之后,在20世紀(jì)80年代中期推出的一種低密度可編程邏輯器件。它在結(jié)構(gòu)上采用了輸出邏輯宏單元(OLMC——Output Logic Macro Cell)結(jié)構(gòu)形式,在工藝上吸收EEPROM的浮柵技術(shù),從而使GAL器件具有可擦除、可重新編程、數(shù)據(jù)可長期保存的結(jié)構(gòu)特點(diǎn)。CPLD(Complex Programmable Logic Device)是萬門以上的復(fù)雜可編程邏輯器件,采用CMOS EPROM、EEPROM、快閃存儲器和SRAM等編程技術(shù),從而構(gòu)成高密度、高速度和低功耗的可編程邏輯器件。
2.2?現(xiàn)場可編程門陣列(FPGA)
FPGA是現(xiàn)場可編程門陣列(Field Programmable Gate Array)的簡稱。FPGA器件及其開發(fā)系統(tǒng)是開發(fā)大規(guī)模數(shù)字集成電路的新技術(shù)。它利用計(jì)算機(jī)輔助設(shè)計(jì),繪制出實(shí)現(xiàn)用戶邏輯的原理圖、編輯布爾方程或用硬件描述語言等方式作為設(shè)計(jì)輸入;然后經(jīng)一系列轉(zhuǎn)換程序、自動(dòng)布局布線、模擬仿真的過程;最后生成配置FPGA器件的數(shù)據(jù)文件,對FPGA器件初始化。這樣就實(shí)現(xiàn)了滿足用戶要求的專用集成電路,真正達(dá)到了用戶自行設(shè)計(jì)、自行研制和自行生產(chǎn)集成電路的目的。
FPGA是一種半定制的集成電路,其特點(diǎn)是直接面向用戶,具有極大的靈活性和通用性,開發(fā)效率高,硬件測試和實(shí)現(xiàn)快捷,工作可靠性好而且技術(shù)維護(hù)簡單。
FPGA相對于CPLD而言,其結(jié)構(gòu)特點(diǎn)在于FPGA是基于查找表look-up-table的。查找表(look-up-table)簡稱為LUT,LUT本質(zhì)上是一個(gè)RAM。FPGA使用4輸入的LUT,所以每一個(gè)LUT 可以看成一個(gè)有4位地址線的16*1的RAM。當(dāng)用戶通過原理圖或HDL語言描述了一個(gè)邏輯電路后,PLD/FPGA開發(fā)軟件會自動(dòng)計(jì)算邏輯電路的所有可能的結(jié)果,并把結(jié)果事先寫入RAM,這樣,每輸入一個(gè)信號進(jìn)行邏輯運(yùn)算就等于輸入一個(gè)地址進(jìn)行查表,找出地址對應(yīng)的內(nèi)容,然后輸出即可。
2.2.1?FPGA的器件結(jié)構(gòu)與工作原理
FPGA(Field Programmable Gate Array)即現(xiàn)場可編程邏輯陣列,是大規(guī)??删幊碳呻娐返闹髁髌骷?。FPGA一般由三種可編程電路和一個(gè)用于存放編程數(shù)據(jù)的SRAM(靜態(tài)隨機(jī)存儲器)組成,這三種可編程電路是:可編程邏輯陣列LAB(Logic Array Block),輸入輸出模塊IOB(I/O Block)和互連資源IR(Interconnect Resource)。FPGA可編程邏輯形成的方法是基于查找表LUT(Look Up Table)結(jié)構(gòu)的,LUT是可編程的最小邏輯構(gòu)成單元。
1)可編程邏輯陣列LAB
可編程邏輯陣列是由一系列相鄰的邏輯單元LE(Logic Element)構(gòu)成的,每個(gè)LAB包括八個(gè)邏輯單元LE、相連的進(jìn)位鏈和級聯(lián)鏈,LAB控制信號和LAB局部互連。LAB的構(gòu)成、ACEK系列芯片的“粗粒度(coarse-grained)”結(jié)構(gòu),有利于EDA軟件進(jìn)行布局布線,優(yōu)化器件的利用進(jìn)而提高整個(gè)數(shù)字系統(tǒng)的性。
其中的邏輯單元LE是一種基于查找表的函數(shù)發(fā)生器。它能夠?qū)崿F(xiàn)4輸入1輸出的任意邏輯函數(shù)。每個(gè)LE包含一個(gè)4輸入的查找表、一個(gè)帶有同步使能的可編程觸發(fā)器、一個(gè)進(jìn)位鏈和一個(gè)級聯(lián)鏈。每個(gè)LE有兩個(gè)輸出分別可以驅(qū)動(dòng)局部互連和快速通道互連。LE有兩個(gè)輸出驅(qū)動(dòng)內(nèi)部互連,一個(gè)是驅(qū)動(dòng)局部互連輸出,另一個(gè)驅(qū)動(dòng)行或列的快速通道Fast Track的互連輸出,這兩個(gè)輸出可以單獨(dú)控制。因此在一個(gè)邏輯單元LE中的觸發(fā)器和查找表能夠用來完成不相關(guān)的功能,從而提高LE的資源利用率。
在ACEK系列芯片的結(jié)構(gòu)中還提供了兩種專用的高速數(shù)據(jù)通道,用于連接相鄰的LE,但不占用局部互連通路,它們是進(jìn)位鏈和級聯(lián)鏈。進(jìn)位鏈用來支持高速計(jì)數(shù)器和加法器,它提供了LE之間的快速向前進(jìn)位功能。來自低位的進(jìn)位信號經(jīng)進(jìn)位鏈向前直接送到高位,同時(shí)反饋入查找表和進(jìn)位鏈的下一段。這種特點(diǎn)使得ACEK結(jié)構(gòu)能夠?qū)崿F(xiàn)高速計(jì)數(shù)器、加法器和寬位比較器。級聯(lián)鏈可以用來實(shí)現(xiàn)多輸入數(shù)的邏輯函數(shù)。相鄰的查找表并行地完成部分邏輯功能,級聯(lián)鏈把中間結(jié)果拼接起來。進(jìn)位鏈和級聯(lián)鏈的使用有利于提高器件的工作速度,但是大量使用進(jìn)位鏈和級聯(lián)鏈會限制布局布線的靈活性,導(dǎo)致資源的浪費(fèi)。因此在設(shè)計(jì)過程應(yīng)該權(quán)衡考慮,在FPGA芯片資源利用和工作速度之間尋求平衡。
2)輸入/輸出模塊IOB
ACEK器件的I/O引腳是由一些I/O單元驅(qū)動(dòng)的。IOE(I/O Element)位于快速通道的行和列末端,包含一個(gè)雙向的緩沖器和一個(gè)寄存器。這個(gè)寄存器可以用作需要快速建立時(shí)間的外部數(shù)據(jù)輸入寄存器,也可以作為需要快速“時(shí)鐘到輸出”性能的數(shù)據(jù)輸出寄存器。IOE可以配置成輸入、輸出或雙向口。
ACEK器件中的IOE具有許多特性,支持JTAG編程、三態(tài)緩沖和漏極開路輸出等等。每個(gè)IOE的時(shí)鐘、清零、時(shí)鐘使能和輸出使能的控制均由I/O控制信號網(wǎng)絡(luò)提供,采用高速驅(qū)動(dòng)以減小通過器件的時(shí)間偏差。此外,ACEK器件還提供了若干專用輸入引腳,這些引腳用來驅(qū)動(dòng)IOE寄存器的控制端,使用了專用的布線通道,以便具有比快速通道更短的延遲和更小的偏差。
3)互連資源IR
可編程的互連資源包括各種長度的金屬連線線段和一些可編程的連線開關(guān),它們將各個(gè)邏輯陣列之間、及其與IO模塊之間互相連接起來,構(gòu)成各種功能復(fù)雜的系統(tǒng)。
在ACEK中互連結(jié)構(gòu)是通過快速通道(Fast Track)實(shí)現(xiàn)的。Fast Track遍布于整個(gè)ACEK器件,是一系列水平和垂直走向的連續(xù)式布線通道。每一行的LAB都有一個(gè)專用的“行互連”,“行互連”可以驅(qū)動(dòng)。I/O引腳或饋送到器件中的其LAB;“列互連”連接各行,也能驅(qū)動(dòng)I/O引腳。這種布線結(jié)構(gòu)能夠有效提高布線效率,使得即使非常復(fù)雜的設(shè)計(jì)也能夠測定其延時(shí)性。
4)嵌入式陣列塊EAB
嵌入式陣列塊EAB是在輸入輸出口上帶有寄存器的靈活的RAM塊,是由一系列嵌式RAM單元組成的。EAB的邏輯功能是在配置期間,用只讀模式對EAB編程產(chǎn)生一個(gè)大型查找表來實(shí)現(xiàn)的。采用查找表實(shí)現(xiàn)組合邏輯比一般算法快,EAB的快速時(shí)間通道使得這一先進(jìn)性能進(jìn)一步得到加強(qiáng)。當(dāng)要實(shí)現(xiàn)存儲器功能時(shí),每個(gè)EAB提供2048比特位,每一個(gè)EAB是一個(gè)獨(dú)立的結(jié)構(gòu),它具有共同的輸入、互連和控制信號。每個(gè)EAB含有一個(gè)行互連饋端,EAB的輸出能夠同時(shí)驅(qū)動(dòng)行互連通道和列互連通道。這一特性增加了EAB的可利用布線資源。因此,EAB可以非常方便地用于實(shí)現(xiàn)一些規(guī)模不大的RAM、ROM、FIFO等功能模塊;同時(shí)在實(shí)現(xiàn)地址譯碼器、狀態(tài)機(jī)、微控制器等復(fù)雜邏輯時(shí)也具備了一定優(yōu)勢。
2.2.2?基于EDA平臺的FPGA開發(fā)流程
一個(gè)完整、典型的EDA設(shè)計(jì)流程即是自頂向下設(shè)計(jì)方法的具體實(shí)施過程,也是EDA軟件本身的組成結(jié)構(gòu)。在實(shí)踐中進(jìn)一步了解支持這一個(gè)設(shè)計(jì)流程的諸多設(shè)計(jì)工具,有利于排解設(shè)計(jì)中的具體問題,提高設(shè)計(jì)質(zhì)量。
1)設(shè)計(jì)輸入
基于EDA軟件平臺的FPGA開發(fā)流程,一般有兩種設(shè)計(jì)輸入方式:圖形輸入和硬件描述語言文本輸入。下面將重點(diǎn)介紹采用Verilog硬件描述語言進(jìn)行設(shè)計(jì)輸入方法,這是我們在設(shè)計(jì)開發(fā)過程中采用的主要方法。Verilog作為電子工程主流硬件描述語言,是EDA技術(shù)的重要組成部分。它于1983年由美國國防部創(chuàng)建,由IEEE協(xié)會進(jìn)一步發(fā)展并在1987年成為IEEE國際標(biāo)準(zhǔn)。自IEEE協(xié)會公布了Verilog標(biāo)準(zhǔn)版本(IEEE Std 1076)之后,各大EDA公司相繼推出支持Verilog語言的開發(fā)環(huán)境。從此Verilog作為硬件描述語言的業(yè)界標(biāo)準(zhǔn)之一,在電子設(shè)計(jì)領(lǐng)域得到廣泛應(yīng)用,并逐步成為事實(shí)上的通用硬件描述語言。
Verilog語言具有很強(qiáng)的電路建模能力,具有良好的電路行為描述和系統(tǒng)描述的能力,能從多個(gè)層次對數(shù)字系統(tǒng)進(jìn)行建模和描述;Verilog語言還具有與硬件電路無關(guān)和設(shè)計(jì)平臺無關(guān)的特性,并且在語言易讀性和層次化結(jié)構(gòu)化設(shè)計(jì)方面表現(xiàn)了強(qiáng)大的生命力和應(yīng)用潛力。這些特性使得Verilog語言在支持自頂向下的EDA設(shè)計(jì)流程方面顯得游刃有余。因此,采用Verilog進(jìn)行電子系統(tǒng)設(shè)計(jì)可以讓設(shè)計(jì)者專心致力于其功能的實(shí)現(xiàn),而不需要對不影響功能的與工藝相關(guān)的問題花費(fèi)過多的時(shí)間和精力,提高了設(shè)計(jì)效率和可靠性。
采用Verilog文本設(shè)計(jì)輸入與傳統(tǒng)的計(jì)算機(jī)軟件語言編輯輸入基本上一樣,就是使用Verilog描述數(shù)字系統(tǒng)的功能,進(jìn)行文本編輯輸入。事實(shí)上,純粹的Verilog設(shè)計(jì)輸入方法仍然是最基本、最有效和最普遍的設(shè)計(jì)輸入方法。
2)設(shè)計(jì)綜合
在電子設(shè)計(jì)領(lǐng)域“綜合”的概念可以表示為:將行為和功能層次表達(dá)的電子系統(tǒng)轉(zhuǎn)化為低層次的便于具體實(shí)現(xiàn)的模塊組合裝配而成的過程。事實(shí)上,設(shè)計(jì)過程通常從高層次的行為描述開始,直到最底層的結(jié)構(gòu)描述結(jié)束,每一個(gè)步驟都是上一個(gè)層次的綜合轉(zhuǎn)換。在FPGA設(shè)計(jì)開發(fā)過程中,整個(gè)綜合過程就是設(shè)計(jì)者在EDA軟件平臺上編輯輸入Verilog文本,依據(jù)給定電路結(jié)構(gòu)組件和約束控制條件進(jìn)行編譯、優(yōu)化、轉(zhuǎn)換和綜合,最終獲得門級電路甚至更底層的電路描述網(wǎng)表文件。因此設(shè)計(jì)綜合的過程就是將軟件設(shè)計(jì)的Verilog描述文本與硬件結(jié)構(gòu)掛鉤,是軟件描述轉(zhuǎn)化為硬件電路的關(guān)鍵步驟,是文本描述與硬件實(shí)現(xiàn)之間的一座橋梁。
3)結(jié)構(gòu)適配
適配器也稱為結(jié)構(gòu)綜合器,它的功能是將綜合器產(chǎn)生的網(wǎng)表文件配置于指定的FPGA目標(biāo)器件中,使之產(chǎn)生最終的下載文件。適配過程中所選定的FPGA目標(biāo)器件必須屬于綜合器原來指定的目標(biāo)器件系列,這是因?yàn)檫m配器的適配對象是直接與器件的結(jié)構(gòu)細(xì)節(jié)相對應(yīng)的。邏輯綜合通過后必須利用適配器將綜合后的網(wǎng)表文件針對某一具體目標(biāo)器件進(jìn)行邏輯映射操作,其中包括底層器件配置、邏輯分割、邏輯優(yōu)化、邏輯布局布線操作。適配完成后可以利用適配所產(chǎn)生的仿真文件作精確的時(shí)序仿真,同時(shí)產(chǎn)生可用于編程下載文件。
4)功能仿真和時(shí)序仿真
在編程下載前必須利用EDA工具對配置生成的結(jié)果進(jìn)行模擬分析,這就是所謂的仿真。仿真的過程就是讓計(jì)算機(jī)根據(jù)一定的算法和一定的仿真庫對EDA設(shè)計(jì)進(jìn)行模擬,以驗(yàn)證設(shè)計(jì),排除錯(cuò)誤。仿真包括功能仿真和時(shí)序仿真。
功能仿真:不經(jīng)過綜合和適配階段,在設(shè)計(jì)項(xiàng)目編譯后直接進(jìn)入門級仿真器進(jìn)行模擬測試。主要用于測試設(shè)計(jì)項(xiàng)目的邏輯功能,用以了解其實(shí)現(xiàn)的功能是否滿足設(shè)計(jì)要求,在功能仿真的過程不涉及任何具體器件的硬件特性。
時(shí)序仿真:當(dāng)設(shè)計(jì)項(xiàng)目通過功能仿真初步確定滿足設(shè)計(jì)要求后,需要綁定具體器件進(jìn)行時(shí)序仿真。時(shí)序仿真就是接近真實(shí)器件運(yùn)行特性的仿真,仿真文件包含了器件硬件特性參數(shù),因而仿真精度高。
5)編程下載
把適配后生成的下載或配置文件,通過編程器或編程電纜向FPGA進(jìn)行下載,以便進(jìn)行硬件調(diào)試和驗(yàn)證,從而實(shí)現(xiàn)滿足設(shè)計(jì)要求的電子系統(tǒng)。
三、整體設(shè)計(jì)原理介紹
FPGA具有運(yùn)算速度快,編程簡易等優(yōu)點(diǎn),它是在PAL、GAL、CPLD等可編程器件的基礎(chǔ)上進(jìn)一步發(fā)展的產(chǎn)物。它還是作為專用集成電路領(lǐng)域中的一種半定制電路而出現(xiàn)的,既解決了定制電路的不足,又克服了原有可編程器件門電路數(shù)有限的缺點(diǎn)。所以我采用FPGA原理設(shè)計(jì)了本次計(jì)算器,主要包括數(shù)碼管部分,按鍵電路部分以及運(yùn)算器部分,設(shè)計(jì)方案基本原理如下。
3.1?數(shù)碼管顯示
數(shù)碼管的顯示分為兩種,靜態(tài)顯示和動(dòng)態(tài)顯示,在這里我們使用的是動(dòng)態(tài)顯示。動(dòng)態(tài)顯示的特點(diǎn)是將所有位數(shù)碼管的段選并聯(lián)在一起,由位選線控制是哪一位數(shù)碼管是有效的。這樣一來,就沒有為每一位數(shù)碼管配置一個(gè)鎖存器的必要,從而就會大大簡化了硬件電路。選亮的數(shù)碼管采用動(dòng)態(tài)掃描顯示。所謂的動(dòng)態(tài)掃描顯示就是輪流向各位數(shù)碼管送出字形碼和相應(yīng)的位選,利用發(fā)光管的余輝和人眼視覺暫留作用,使人的感覺好像各位數(shù)碼管在同時(shí)都在顯示。動(dòng)態(tài)的顯示的亮度要比靜態(tài)的顯示略差了一些,因而我們在選擇需要的限流電阻應(yīng)小于靜態(tài)顯示電路中的。
3.2?按鍵部分原理
我們采用了4*4矩陣鍵盤掃描在鍵盤中按鍵數(shù)量較多時(shí),為了減少I/O口的占用,通常將按鍵排列成矩陣形式。在矩陣式鍵盤中,每條水平線和垂直線在交叉處不直接連通,而是通過一個(gè)按鍵加以連接。這樣,一個(gè)端口就可以構(gòu)成4*4=16個(gè)按鍵,比之直接將端口線的應(yīng)用于鍵盤多出了一倍,而且線數(shù)越多,區(qū)別越明顯,比如再多加一條線就可以構(gòu)成20鍵的鍵盤,而直接用端口線則只能多出一鍵(9鍵)。由此可見,我們在需要的鍵數(shù)比較多時(shí),采用矩陣法來做鍵盤是合理的。
矩陣式結(jié)構(gòu)的鍵盤顯然比直接法要復(fù)雜一些,識別也要復(fù)雜一些,列線通過了電阻連接正電源,并將行線所接的I/O口作為輸出端,而列線所接的I/O口則作為輸入。這樣,當(dāng)按鍵沒有按下時(shí),所有的輸入端都是高電平,代表無鍵按下。行線輸出是低電平,一旦有鍵按下,則輸入線就會被拉低,這樣,通過讀入輸入線的狀態(tài)就可得知是否有鍵按下了。下面我們介紹行掃描法。
行掃描法又稱為逐行(或列)掃描查詢法,是一種最常用的按鍵識別方法,介紹過程如下。
首先判斷鍵盤中有無鍵按下:將全部行線置低電平,然后檢測列線的狀態(tài)。只要有一列的電平為低,則表示鍵盤中有鍵被按下,而且閉合的鍵位于低電平線與4根行線相交叉的4個(gè)按鍵之中。若所有的列線均是高電平,則鍵盤中無鍵按下。
其次判斷閉合鍵所存在的位置:在確認(rèn)有鍵按下后,即可進(jìn)入確定具體閉合鍵的過程。其方法是:依次將行線置為低電平,就是在置某根行線為低電平時(shí),其它線為高電平。在確定某根行線位置為低電平后,再逐行檢測各列線的電平狀態(tài)。若某列為低,則該列線與置為低電平的行線交叉處的按鍵就是閉合的按鍵。
3.3?狀態(tài)機(jī)原理
運(yùn)算部分我們主要應(yīng)用了狀態(tài)機(jī)進(jìn)行運(yùn)算和存儲的,主要是有限狀態(tài)機(jī),下面對有限狀態(tài)機(jī)進(jìn)行簡單的介紹。
狀態(tài)機(jī)簡寫為FSM(Finite State Machine),主要分為2大類:第一類,若輸出只和狀態(tài)有關(guān)而與輸入無關(guān),則稱為Moore狀態(tài)機(jī);第二類,輸出不僅和狀態(tài)有關(guān)而且和輸入有關(guān)系,則稱為Mealy狀態(tài)機(jī)。要特別注意的是,因?yàn)镸ealy狀態(tài)機(jī)和輸入有關(guān),輸出會受到輸入的干擾,所以可能會產(chǎn)生毛刺(Glitch)現(xiàn)象,使用時(shí)應(yīng)當(dāng)注意。事實(shí)上現(xiàn)在市面上有很多EDA工具可以很方便的將狀態(tài)圖的描述轉(zhuǎn)換成可以綜合的Verilog程序代碼。
關(guān)于狀態(tài)機(jī)的一個(gè)極度確切的描述是它是一個(gè)有向圖形,由一組節(jié)點(diǎn)和一組相應(yīng)的轉(zhuǎn)移函數(shù)組成。狀態(tài)機(jī)通過響應(yīng)一系列事件而“運(yùn)行”。每個(gè)事件都在屬于“當(dāng)前”節(jié)點(diǎn)的轉(zhuǎn)移函數(shù)的控制范圍內(nèi),其中函數(shù)的范圍是節(jié)點(diǎn)的一個(gè)子集。函數(shù)返回“下一個(gè)”(也許是同一個(gè))節(jié)點(diǎn)。這些節(jié)點(diǎn)中至少有一個(gè)必須是終態(tài)。當(dāng)?shù)竭_(dá)終態(tài),狀態(tài)機(jī)停止。
包含一組狀態(tài)集(states)、一個(gè)起始狀態(tài)(start state)、一組輸入符號集(alphabet)、一個(gè)映射輸入符號和當(dāng)前狀態(tài)到下一狀態(tài)的轉(zhuǎn)換函數(shù)(transition function)的計(jì)算模型。當(dāng)輸入符號串,模型隨即進(jìn)入起始狀態(tài)。它要改變到新的狀態(tài),依賴于轉(zhuǎn)換函數(shù)。在有限狀態(tài)機(jī)中,會有有許多變量,例如,狀態(tài)機(jī)有很多與動(dòng)作(actions)轉(zhuǎn)換(Mealy機(jī))或狀態(tài)(摩爾機(jī))關(guān)聯(lián)的動(dòng)作,多重起始狀態(tài),基于沒有輸入符號的轉(zhuǎn)換,或者指定符號和狀態(tài)(非定有限狀態(tài)機(jī))的多個(gè)轉(zhuǎn)換,指派給接收狀態(tài)(識別者)的一個(gè)或多個(gè)狀態(tài),等等。
傳統(tǒng)應(yīng)用程序的控制流程基本是順序的:遵循事先設(shè)定的邏輯,從頭到尾地執(zhí)行。很少有事件能改變標(biāo)準(zhǔn)執(zhí)行流程;而且這些事件主要涉及異常情況?!懊钚袑?shí)用程序”是這種傳統(tǒng)應(yīng)用程序的典型例子。
另一類應(yīng)用程序由外部發(fā)生的事件來驅(qū)動(dòng)——換言之,事件在應(yīng)用程序之外生成,無法由應(yīng)用程序或程序員來控制。具體需要執(zhí)行的代碼取決于接收到的事件,或者它相對于其他事件的抵達(dá)時(shí)間。所以,控制流程既不能是順序的,也不能是事先設(shè)定好的,因?yàn)樗蕾囉谕獠渴录?。事件?qū)動(dòng)的GUI應(yīng)用程序是這種應(yīng)用程序的典型例子,它們由命令和選擇(也就是用戶造成的事件)來驅(qū)動(dòng)。
Web應(yīng)用程序由提交的表單和用戶請求的網(wǎng)頁來驅(qū)動(dòng),它們也可劃歸到上述類別。但是,GUI應(yīng)用程序?qū)τ诮邮盏降氖录杂幸欢ǔ潭鹊目刂?,因?yàn)檫@些事件要依賴于向用戶顯示的窗口和控件,而窗口和控件是由程序員控制的。Web應(yīng)用程序則不然,因?yàn)橐坏┯脩舨扇〔辉陬A(yù)料之中的操作(比如使用瀏覽器的歷史記錄、手工輸入鏈接以及模擬一次表單提交等等),就很容易打亂設(shè)計(jì)好的應(yīng)用程序邏輯。
顯然,必須采取不同的技術(shù)來處理這些情況。它能處理任何順序的事件,并能提供有意義的響應(yīng),即使這些事件發(fā)生的順序和預(yù)計(jì)的不同。有限狀態(tài)機(jī)正是為了滿足這方面的要求而設(shè)計(jì)的。
有限狀態(tài)機(jī)是一種概念性機(jī)器,它能采取某種操作來響應(yīng)一個(gè)外部事件。具體采取的操作不僅能取決于接收到的事件,還能取決于各個(gè)事件的相對發(fā)生順序。之所以能夠做到這一點(diǎn),是因?yàn)闄C(jī)器能跟蹤一個(gè)內(nèi)部狀態(tài),它會在收到事件后進(jìn)行更新。為一個(gè)事件而響應(yīng)的行動(dòng)不僅取決于事件本身,還取決于機(jī)器的內(nèi)部狀態(tài)。另外,采取的行動(dòng)還會決定并更新機(jī)器的狀態(tài)。這樣一來,任何邏輯都可建模成一系列事件/狀態(tài)組合。
狀態(tài)機(jī)可歸納為4個(gè)要素,即現(xiàn)態(tài)、條件、動(dòng)作、次態(tài)。這樣的歸納,主要是出于對狀態(tài)機(jī)的內(nèi)在因果關(guān)系的考慮?!艾F(xiàn)態(tài)”和“條件”是因,“動(dòng)作”和“次態(tài)”是果。
有限狀態(tài)機(jī)用于描述電路模型的時(shí)序行為,所有的輸入都可以看成是模型的激勵(lì),所有的輸出可以看成是模型對激勵(lì)的響應(yīng)。CLK提供時(shí)間基準(zhǔn)。
圖3-1 抽象時(shí)序電路的行為模型Figure 3-1 abstract behavior model of sequential circuits
時(shí)序電路模型可以表示為:R=F(t),這里F(t)是模型行為的描述。當(dāng)電路的輸出僅僅與狀態(tài)時(shí)間有關(guān)時(shí)候,所描述的模型為摩爾型狀態(tài)機(jī);當(dāng)電路的輸出不僅與時(shí)間有關(guān),也與當(dāng)前的輸入信號有關(guān)時(shí),稱為米利型狀態(tài)機(jī)。
四、計(jì)算器設(shè)計(jì)的電路部分
4.1 ?FPGA的最小系統(tǒng)
FPGA最小系統(tǒng)是可以使FPGA正常工作的最簡單的系統(tǒng)。它的外圍電路盡量最少,只包括FPGA必要的控制電路。一般我們所說的FPGA的最小系統(tǒng)主要包括:FPGA芯片,下載電路,外部時(shí)鐘,復(fù)位電路和電源。
4.1.1 ?電源時(shí)鐘復(fù)位
我們采用了低電平復(fù)位電路,電路圖如下
圖4-1 復(fù)位電路 Figure 4-1 reset circuit
4.1.2 ?JTAG接口
JTAG最初是用來對芯片進(jìn)行測試的,JTAG的基本原理是在器件內(nèi)部定義一個(gè)TAP(Test Access Port;測試訪問口)通過專用的JTAG測試工具對內(nèi)部節(jié)點(diǎn)進(jìn)行測試。JTAG測試允許多個(gè)器件通過JTAG接口串聯(lián)在一起,形成一個(gè)JTAG鏈,能實(shí)現(xiàn)對各個(gè)器件分別測試。如今,JTAG接口還常用于實(shí)現(xiàn)ISP(In——System Programmer,在系統(tǒng)編程),對FLASH等器件進(jìn)行編程。
JTAG編程方式是在線編程,傳統(tǒng)生產(chǎn)流程中先對芯片進(jìn)行預(yù)編程然后再裝到板上,簡化的流程為先固定器件到電路板上,再用JTAG編程,從而大大加快工程進(jìn)度。JTAG接口可對DSP芯片內(nèi)部的所有部件進(jìn)行編程。
JTAG(Joint Test Action Group,聯(lián)合測試行動(dòng)小組)是一種國際標(biāo)準(zhǔn)測試協(xié)議,主要用于芯片內(nèi)部測試及對系統(tǒng)進(jìn)行仿真、調(diào)試,JTAG技術(shù)是一種嵌入式調(diào)試技術(shù),它在芯片內(nèi)部封裝了專門的測試電路TAP(Test Access Port,測試訪問口),通過專用的JTAG測試工具對內(nèi)部節(jié)點(diǎn)進(jìn)行測試。
如今大多數(shù)比較復(fù)雜的器件都支持JTAG協(xié)議,如ARM、DSP、FPGA器件等。標(biāo)準(zhǔn)的JTAG接口是4線:TMS、TCK、TDI、TDO,分別為測試模式選擇、測試時(shí)鐘、測試數(shù)據(jù)輸入和測試數(shù)據(jù)輸出。如今JTAG接口的連接有兩種標(biāo)準(zhǔn),即14針接口和20針接口。
支持邊界掃描的邏輯元器件與測試相關(guān)的所有外部通信都采用串行通信方式,允許測試指令及相關(guān)的測試數(shù)據(jù)串行送給元器件,然后允許把測試指令的執(zhí)行結(jié)果從元器件中串行讀出。為了完成這樣的功能,邊界掃描技術(shù)包含了一個(gè)與元器件的每個(gè)引腳相接,包含在邊界掃描寄存器單元中的寄存器鏈,這樣元器件的邊界信號可以用掃描測試原理進(jìn)行控制和觀察,這也是邊界掃描的含義。
圖4-2 JTAG配置接口電路Figure 4-2 the JTAG configuration interface circuit
4.1.3 ?FLASH
閃存存儲器是一類非易失性存儲器,即使在供電電源關(guān)閉后仍能保持片內(nèi)信息。數(shù)字電路中經(jīng)常需要使用大容量存儲器,串行Flash存儲速度快,體積小,功耗低,在FPGA中設(shè)計(jì)中發(fā)揮的作用也越來越大,廣泛應(yīng)用于實(shí)現(xiàn)系統(tǒng)及功能驗(yàn)證。FPGA的靈活性和串行Flash的體積小的特點(diǎn)相結(jié)合,具有靈活性強(qiáng)實(shí)用性強(qiáng)等特點(diǎn)。我們的Flash程序存儲電路如圖4-3所示。
圖4-3 Flash程序存儲電路Figure 4-3 Flash program memory circuit
4.2 ?數(shù)碼管電路
我們應(yīng)用的LED數(shù)碼管段數(shù)為7段,就是7個(gè)發(fā)光二極管,任意一個(gè)阿拉伯?dāng)?shù)字0-9都是可以通過亮滅組合來實(shí)現(xiàn)的。LED數(shù)碼管根據(jù)LED的接法不同分為共陰和共陽兩類,共陰極數(shù)碼管公共端接地,共陽極數(shù)碼管公共端接電源,另一個(gè)非公共端的引腳留給用戶的I/O直接控制了,在這里我們采用共陽極數(shù)碼管。我們在這個(gè)應(yīng)用中,把公共端連接到了FPGA的I/O引腳上,這就是我們數(shù)碼管的片選信號。如果我們FPGA的I/O引腳輸出低電平0,那么這個(gè)數(shù)碼管就是可以顯示數(shù)字的,如果我們這個(gè)I/O輸出高電平1。那么即使不管數(shù)碼管的段選端輸出0還是1,都沒有辦法將這7個(gè)發(fā)光二極管的任意一個(gè)點(diǎn)亮,這也達(dá)到了關(guān)閉數(shù)碼管顯示的效果。一旦這樣,這個(gè)數(shù)碼管的公共端被當(dāng)作數(shù)碼管片選引腳使用了,雖然不是名副其實(shí)的“片選”,也是可以達(dá)到我們想要的效果。了解LED的這些特性,對編程是很重要的,不同類型的數(shù)碼管,除了它們的硬件電路有差異外,方法也是不同的。
圖4-4?數(shù)碼管電路圖Figure 4-4 digital tube circuit diagram
4.3 ?按鍵輸入電路
我們要實(shí)現(xiàn)一個(gè)計(jì)算器,首先需要有計(jì)算器的輸入信號,通常是使用連接在FPGA的GPIO接口上的pushbutton作為輸入信號。簡易計(jì)算器的輸入信號比較少,只需要數(shù)字和運(yùn)算符號。我們可以將其各自使用一個(gè)按鍵來表示,然后都連接在FPGA的通用接口上。此時(shí),我們便引入了矩陣鍵盤構(gòu)造計(jì)算器的輸入。
我們采用的是4*4矩陣鍵盤電路,矩陣鍵盤又稱行列式鍵盤,它是用4條I/O線作為行線,4條I/O線作為列線組成的鍵盤。在行線和列線的每一個(gè)交叉點(diǎn)上,設(shè)置一個(gè)按鍵。這樣鍵盤中的按鍵的個(gè)數(shù)就是4*4=16個(gè)。這種行列式鍵盤結(jié)構(gòu)能夠有效地提高單片機(jī)系統(tǒng)中I/O口的利用率。其中的ROW0,ROW1,ROW2,ROW3,以及COL0,COL1,COL2,COL3信號分別連接到了FPGA上,使用一種獨(dú)特的方法,這8個(gè)信號能夠表示出16個(gè)按鍵各自按下的狀態(tài)。即這16個(gè)按鍵只占用了FPGA的8個(gè)管腳,而使用每個(gè)按鍵都連接到了FPGA的輸入管腳需要占用16個(gè)管腳。
行列矩陣采用了掃描的形式,其8個(gè)連接到FPGA上的信號是4個(gè)輸入4個(gè)輸出的。我們一般使用的其他按鍵方法都是將按鍵產(chǎn)生的信號作為輸入。在這里,ROW0-ROW3為FPGA的輸入信號,COL0-COL3是FPGA的輸出信號;電路上,ROW0-ROW3還要連接一個(gè)上拉電阻。
如果左上方第一個(gè)按鍵被按下,ROW0和COL0連接在一起;如果不按下,兩個(gè)信號則沒有連接。16個(gè)按鍵表示16種連接的關(guān)系,在沒有按鍵按下的時(shí)候,輸出的COL信號就懸空了,輸入的4個(gè)ROW信號收到上拉電阻的影響都是高電平1。如果說連接COL3與ROW2的按鍵被按下,那么FPGA的輸入信號ROL2就等于輸出信號COL3的值,其他的ROW輸入信號則全部為1。
我們在FPGA內(nèi)部使輸出的COL0信號為0而其他的COL是1,那么不管其他的列上對應(yīng)的按鍵都怎么按下,都有輸入的FPGA的ROW為全1;僅僅當(dāng)?shù)谝涣械?個(gè)按鍵中有一個(gè)按下時(shí),對應(yīng)的行值為0,其余3個(gè)的行值為1,這樣的話第一列所對應(yīng)的按鍵就唯一確定下來了。在這樣的輸出狀態(tài)下(COL[3:0]=1110),4個(gè)輸入只能確定出來第一列的4個(gè)按鍵。要是按下的不是第一行的4個(gè)按鍵,那么輸入值ROW[3:0]為1111,表示第一列沒有按鍵被按下。于是我們開始掃描第二列,就是令COL[3:0]輸出1101,然后查看ROW上是否有值為0。如果此列上仍然沒有掃描到,就繼續(xù)掃描下一列。
對于一組數(shù)碼管動(dòng)態(tài)掃描顯示需要由兩組信號來控制:一組是輸出口輸出的字形代碼,用來控制顯示的字形,稱為段碼;另一組是位輸出口輸出的控制信號,用來選擇第幾位數(shù)碼管的工作,稱為位碼。
由于各位數(shù)碼管的段線并聯(lián),段碼的輸出對各位數(shù)碼管來說都是相同的。因此,同一時(shí)刻如果各位數(shù)碼管的位選線都處于選通狀態(tài)的話,位數(shù)碼管將顯示相同的字符。若要各位數(shù)碼管能夠顯示出與本位相應(yīng)的字符,就必須采用掃描顯示方式。即在某一時(shí)刻,只讓某一位的選線處于導(dǎo)通狀態(tài),而其他各位的位選線處于關(guān)閉狀態(tài)。同時(shí),段線上輸出相應(yīng)位要顯示字符的字形碼。這樣同一時(shí)刻,只有選通的那一位顯示出字符,而其它各位則是熄滅的,如此循環(huán)下去,就可以使各位數(shù)碼管顯示出將要顯示的字符。
雖然這些字符是在不同時(shí)刻出現(xiàn)的,而且同一時(shí)刻只有一位顯示,其它各位熄滅,但是由于數(shù)碼管具有余輝特性和人眼有視覺暫留現(xiàn)象,只要每位數(shù)碼管顯示間隔足夠短,給人眼的視覺印象就會是連續(xù)穩(wěn)定地顯示。
圖4-5鍵盤電路Figure 4-5 The keyboard circuit
4.4 ?電源電路設(shè)計(jì)
我們使用的是LM1117,LM1117是一個(gè)低壓差電壓調(diào)節(jié)器系列。其壓差在1.2V輸出,負(fù)載電流為800mA時(shí)為1.2V。它與國家半導(dǎo)體的工業(yè)標(biāo)準(zhǔn)器件LM317有相同的管腳排列。LM1117有可調(diào)電壓的版本,通過2個(gè)外部電阻可實(shí)現(xiàn)1.25~13.8V輸出電壓范圍。另外還有5個(gè)固定電壓輸出(1.8V、2.5V、2.85V、3.3V和5V)的型號。
LM1117提供電流限制和熱保護(hù)。電路包含1個(gè)齊納調(diào)節(jié)的帶隙參考電壓以確保輸出電壓的精度在±1%以內(nèi)。LM1117系列具有LLP、TO-263、SOT-223、TO-220和TO-252 D-PAK封裝。輸出端需要一個(gè)至少10μF的鉭電容來改善瞬態(tài)響應(yīng)和穩(wěn)定性。
圖4-6 5V轉(zhuǎn)數(shù)字3.3V電路Figure 4-6 5V to?3.3V circuit
?
圖4-7 5V轉(zhuǎn)數(shù)字2.5V電路Figure 4-7 5V to?2.5V circuit?
圖4-8 5V轉(zhuǎn)數(shù)字1.2V電路Figure 4-8 5V to?1.2V circuit?
圖4-9 電源插座電路Figure 4-9 power socket circuit?
圖4-10 電源開關(guān)電路Figure 4-10 power switch circuit
五、總體代碼設(shè)計(jì)
系統(tǒng)總體設(shè)計(jì)框圖如圖5-1所示。此設(shè)計(jì)由計(jì)算部分、存儲部分、顯示部分和輸入部分組成。
圖5-1 計(jì)算器的系統(tǒng)組成框圖Figure 5-1 calculator system composition block diagram
圖5-2 RTL視圖Figure 5-2 RTL view
5.1 ?計(jì)算器的輸入部分
計(jì)算器輸入部分的設(shè)計(jì)最主要的是按鍵譯碼電路的設(shè)計(jì)和實(shí)現(xiàn)。計(jì)算器的輸入部分是由0—9十個(gè)數(shù)字按鍵、加減乘除四則運(yùn)算的運(yùn)算符按鍵、一個(gè)等號按鍵和一個(gè)清零按鍵組成的,設(shè)計(jì)所要做的是對按鍵信息進(jìn)行譯碼,使其在計(jì)算器內(nèi)部可以使用。這里使用的是4*4鍵盤矩陣作為輸入。數(shù)字按鍵譯碼電路的主體部分Verilog語言描述如下。
圖5-3 數(shù)字電路譯碼部分代碼Figure 5-3 digital tube display program code
設(shè)計(jì)的鍵盤矩陣輸入模塊如圖:
圖5-4 鍵盤矩陣驅(qū)動(dòng)模塊
Figure 5-4 matrix keyboard driver module
在輸入鍵盤矩陣驅(qū)動(dòng)模塊中,我們有三個(gè)輸入,四個(gè)輸出,其中clk為主時(shí)鐘輸入,rst_n為復(fù)位信號,row為4*4鍵盤的行輸入信號,輸出col列信號,data為鍵入的數(shù)字(0-15),valid為數(shù)字的脈沖信號,clk_1k為給計(jì)算模塊輸出的時(shí)鐘。
5.2 ?計(jì)算器的運(yùn)算和存儲部分
存儲部分用狀態(tài)機(jī)和寄存器來實(shí)現(xiàn),我們輸入的數(shù)字應(yīng)用了移位拼接的原理,若第一個(gè)輸入的是數(shù)字鍵,則保存下來,第二次輸入還是輸入的是數(shù)字鍵時(shí),第一個(gè)數(shù)值左移變?yōu)槭唬诙蔚臑閭€(gè)位,第三次若還是數(shù)字鍵,那么第一個(gè)數(shù)值將變?yōu)榘傥唬诙€(gè)為十位,第三個(gè)為個(gè)位,以此類推,直到有符號鍵輸入。
當(dāng)進(jìn)行第一次計(jì)算時(shí),第一個(gè)數(shù)字存放在num1里面。按下運(yùn)算符以后,第二個(gè)數(shù)字放在bin_data里面。當(dāng)再按下運(yùn)算符號或者等號時(shí),第一次計(jì)算的結(jié)果將存放在ans里面,同時(shí)reg清零,等待下一個(gè)數(shù)字的輸入。進(jìn)行第二次運(yùn)算時(shí),將num1里面的結(jié)果與reg里面新輸入的數(shù)字進(jìn)行運(yùn)算,再將運(yùn)算結(jié)果存放在num1里面,直到最后按下等號按鍵的時(shí)候,顯示最終的運(yùn)算結(jié)果。
程序框圖如下:
圖5-5 狀態(tài)1程序框圖
Figure 5-5 state 1 program block diagram
圖5-6 狀態(tài)2程序框圖
Figure 5-6 state 2 program block diagram
計(jì)算部分驅(qū)動(dòng)模塊如圖5-7所示,共有4個(gè)輸入部分,一個(gè)輸出。其中clk為時(shí)鐘,flag為數(shù)字脈沖信號,rst_n為復(fù)位,key_data為按鍵數(shù)據(jù)輸入,bin_data為二進(jìn)制中間數(shù)據(jù)輸出。
圖5-7 計(jì)算部分驅(qū)動(dòng)模塊
Figure 5-7 calculation part of the driver module
5.3 ?計(jì)算器的顯示部分
顯示部分是系統(tǒng)的輸出部分,用于顯示按鍵值及計(jì)算結(jié)果,由于數(shù)字系統(tǒng)的數(shù)據(jù)運(yùn)算都是二進(jìn)制的,而輸出表達(dá)式都是BCD碼,為了滿足BCD碼的譯碼顯示,最方便的方法就是利用譯碼程序在FPGA中實(shí)現(xiàn)。本文采用的是共陽極7段數(shù)碼管,顯示數(shù)字時(shí)需要將對應(yīng)管腳置為低電平,輸出時(shí),從左到右,按從高到低位的順序依次接g、f、e、d、c、b、a,小數(shù)點(diǎn)為h,為最高位。七段譯碼器的基本結(jié)構(gòu)如圖5-8所示。
圖5-8 七段譯碼器的結(jié)構(gòu)
Figure5-8 The structure of the seven-segment decoder
Verilog硬件位選信號描述性語言描述如下圖5-9所示:
圖5-9 數(shù)碼管顯示位選程序代碼
Figure 5-9 digital tube display program code
Verilog硬件段選信號描述性語言描述如下圖5-10所示:
圖5-10 數(shù)碼管顯示段選程序代碼
Figure 5-10 digital tube display program code segment
圖5-11 數(shù)碼管顯示驅(qū)動(dòng)模塊
Figure 5-11 digital tube display driver module
圖5-11為數(shù)碼管顯示驅(qū)動(dòng)模塊,一共三個(gè)輸入,兩個(gè)輸出,其中clk為時(shí)鐘,rst_n為復(fù)位,data_in數(shù)據(jù)輸入,sel為位選信號,seg為段選信號。
六、仿真驗(yàn)證設(shè)計(jì)
6.1 ?ModelSim簡介
在仿真設(shè)計(jì)時(shí),用到了Mentor公司的Modelsim,這是一款硬件描述語言仿真軟件,該款軟件不單單能提供十分友好的仿真環(huán)境,而且它也是我們業(yè)界第一個(gè)也是僅此一個(gè)的單內(nèi)核支持VHDL和Verilog語言混合仿真的軟件。它采用直接優(yōu)化的編譯技術(shù)、Tcl/Tk技術(shù)、和單一內(nèi)核仿真技術(shù),從而達(dá)到令人編譯仿真速度快的效果,而且編譯代碼和整個(gè)平臺沒有關(guān)系,這樣就更容易保護(hù)IP核,它是FPGA/ASIC設(shè)計(jì)的首選仿真軟件。
Modelsim有不同版本,例如:SE、PE、LE和OEM,其中最高級的版本是SE,而集成在 Actel、Atmel以及Lattice等FPGA廠商設(shè)計(jì)工具中的都是其OEM版本。
Modelsim SE支持PC、UNIX和LINUX的混合平臺;能給出十分全面到位以及高性能的驗(yàn)證功能;全面支持業(yè)界設(shè)定的廣泛標(biāo)準(zhǔn);同時(shí)Mentor Graphics公司提供了整個(gè)行業(yè)最出色的技術(shù)支持與服務(wù)。
Modelsim的主要特點(diǎn)有:
1)支持單內(nèi)核的VHDL和Verilog混合在一起進(jìn)行仿真處理;
2)具有源代碼模版、助手以及項(xiàng)目管理功能;
3)匯聚了性能考核、波形參考、代碼覆蓋、數(shù)據(jù)流Chase X、Signal Spy、虛擬對象Virtual Object、Assertion窗口、Memory窗口、源碼窗口顯示信號值、信號條件斷點(diǎn)等眾多調(diào)試功能;
4)C和Tcl/Tk接口,C調(diào)試;
5)能夠?qū)崿F(xiàn)對System C的直接支持功能,同時(shí)可以和HDL任意混合使用;
6)能夠?qū)崿F(xiàn)System Verilog的設(shè)計(jì)功能;
7)可以做到對系統(tǒng)級描述語言進(jìn)行最全面的支持;
8)可以單獨(dú)或同時(shí)進(jìn)行行為(behavioral)、RTL級、和門級(gate-level)的代碼。
9)能夠?qū)崿F(xiàn)RTL和門級優(yōu)化,編譯仿真速率非???,跨平臺跨版本的仿真。
6.2 ?模塊仿真驗(yàn)證分析
FPGA設(shè)計(jì)流程包括設(shè)計(jì)輸入,仿真,綜合,生成,板級驗(yàn)證等很多階段。在整個(gè)設(shè)計(jì)流程中,完成設(shè)計(jì)輸入并成功進(jìn)行編譯僅僅能說明設(shè)計(jì)符合一定的語法規(guī)范,并不能說明設(shè)計(jì)功能的正確性,這時(shí),我們就需要通過仿真對設(shè)計(jì)進(jìn)行驗(yàn)證。我們主要進(jìn)行的是功能仿真,又叫邏輯仿真,是指在不考慮器件延時(shí)和布線延時(shí)的理想情況下對源代碼進(jìn)行邏輯功能驗(yàn)證;而時(shí)序仿真是在布局布線后進(jìn)行。我們仿真是為了保證設(shè)計(jì)的正確性。
6.2.1 ?矩陣按鍵模塊
矩陣鍵盤測試程序流程框圖如下:
圖6-1 按鍵測試程序流程圖
Figure 6-1 key testing program flow chart
首先,我們要先進(jìn)行按鍵檢測,判斷是否有按鍵閉合,如果沒有說明沒有按鍵鍵入,那么返回就是我們常說的消抖,重新進(jìn)行按鍵檢測,直到有按鍵閉合。接下來會有10ms的延遲,保存鍵值;再繼續(xù)判斷按鍵是否松開,如果是則又會產(chǎn)生10ms的延遲,否則返回判斷直到按鍵有松開為止,最后返回鍵值。
我們需要編譯一個(gè)模擬鍵盤定義data0-15,然后模擬輸入給FPGA一個(gè)行信號,F(xiàn)PGA接收行信號,同時(shí)輸出給模擬鍵盤一個(gè)列信號,如果輸出的列信號不存在低電平,那么行信號為4‘b1111,代表輸入的按鍵不在本列上,繼續(xù)掃描下一列直到找到相應(yīng)的行信號為止。部分代碼如圖所示。
圖6-2 鍵盤掃描部分代碼
Figure 6-2 keyboard scan code
圖6-3為鍵盤掃描仿真圖,當(dāng)我們按下1時(shí),數(shù)據(jù)顯示1,按下10顯示10,按下2顯示的是2,按下15顯示15,仿真結(jié)果有效,程序編譯正確。
圖6-3 鍵盤掃描仿真
Figure 6-3 keyboard scanning simulation
6.2.2 ?計(jì)算仿真舉例
加法計(jì)算舉例,首先pnumber輸入1,data_in輸入也為1,掃描結(jié)果為1;然后輸入10;pnumber輸入為2,data_in輸入為2,掃描結(jié)果為2;最后按鍵“=”,顯示結(jié)果即為3。仿真顯示結(jié)果正確,說明我們的編譯代碼沒有問題,計(jì)算有效,計(jì)算器結(jié)果可信。
圖6-4 1+2=3程序仿真圖Figure 6-4 1+2=3 process simulation diagram
七、結(jié)論
本次電子計(jì)算器的設(shè)計(jì)是基于FPGA設(shè)計(jì)的,計(jì)算器基本上可以實(shí)現(xiàn)的加減乘除的功能。系統(tǒng)的計(jì)算部分、存儲部分、顯示部分和輸入部分四個(gè)部分都可以完成設(shè)計(jì)要求,輸入部分采用鍵盤矩陣原理,存儲部分用狀態(tài)機(jī)來實(shí)現(xiàn),并進(jìn)行了仿真。實(shí)現(xiàn)了防消抖的要求,計(jì)算結(jié)果較精確。達(dá)到了預(yù)期的要求目標(biāo)。
附錄:設(shè)計(jì)主體源代碼
二進(jìn)制轉(zhuǎn)BCD代碼:
module bin2bcd_12bit(bin, bcd);
input [19:0] bin;
output reg [23:0] bcd;
always @ (*)
begin
bcd[3:0] = bin%10;
bcd[7:4] = bin/10%10;
bcd[11:8] = bin/100%10;
bcd [15:12] = bin/1000%10;
bcd[19:16] = bin/10000%10;
bcd[23:20] = bin/100000%10;
end
endmodule
計(jì)算模塊代碼:
module calculator (clk, rst_n, flag, key_data, bin_data);
input clk;
input rst_n;
input flag;
input [3:0] key_data;
output reg [19:0] bin_data;
reg [1:0] state;
reg [19:0] num1;
reg [3:0] opcode;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
state <= 0;
num1 <= 0;
bin_data <= 0;
opcode <= 0;
end
else
begin
case (state)
0 : begin
if (flag)
begin
if (key_data < 10)
begin
bin_data <= bin_data * 10 + key_data;
end
else
begin
if (key_data == 14)
begin
state <= 0;
end
else
begin
opcode <= key_data;
state <= 1;
num1 <= bin_data;
bin_data <= 0;
end
end
end
else
begin
state <= 0;
end
end
1 : begin
if (flag)
begin
if (key_data < 10)
begin
bin_data <= bin_data * 10 + key_data;
end
else
begin
if (key_data == 14)
begin
case (opcode)
10 : begin bin_data <= num1 + bin_data; state <= 2; end
11 : begin bin_data <= num1 - bin_data; state <= 2; end
12 : begin bin_data <= num1 * bin_data; state <= 2; end
13 : begin bin_data <= num1 / bin_data; state <= 2; end
default : bin_data <= 0;
endcase
end
else
begin
state <= 1;
end
end
end
else
begin
state <= 1;
end
end
2 : begin
if (flag)
begin
if (key_data < 10)
begin
bin_data <= {16'd0,key_data};
state <= 0;
end
else
begin
if (key_data == 14)
begin
state <= 2;
end
else
begin
num1 <= bin_data;
opcode <= key_data;
bin_data <= 0;
state <=1;
end
end
end
else
begin
state <= 2;
end
end
endcase
end
end
endmodule
輸入部分代碼:
module key_board (clk, rst_n, row, col, data, valid, clk_1k);
input clk;
input rst_n;
input [3:0] row;
output reg [3:0] col;
output reg [3:0] data;
output reg valid;
output reg clk_1k;
reg [14:0] cnt;
parameter T1ms = 24999;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
clk_1k <= 1'b1;
cnt <= 15'd0;
end
else
begin
if (cnt < T1ms)
begin
cnt <= cnt + 15'd1;
end
else
begin
cnt <= 15'd0;
clk_1k <= ~clk_1k;
end
end
end
reg [7:0] row_col;
reg [1:0] state;
reg [4:0] count;
always @ (posedge clk_1k or negedge rst_n)
begin
if (!rst_n)
begin
col <= 4'b0000;
row_col <= 8'd0;
state <= 0;
valid <= 0;
count <= 0;
end
else
begin
case (state)
0 : begin
if (row == 4'b1111)
begin
col <= 4'b0000;
end
else
begin
state <= 1;
end
end
1 : begin
if (row == 4'b1111)
begin
state <= 0;
count <= 0;
end
else
begin
if (count < 19)
begin
count <= count + 1;
end
else
begin
count <= 0;
state <= 2;
col <= 4'b0111;
end
end
end
2 : begin
if (row == 4'b1111)
begin
col <= {col[2:0],col[3]};
state <= 2;
end
else
begin
row_col <= {row,col};
state <= 3;
valid <= 1;
end
end
3 : begin
if (row == 4'b1111)
begin
state <= 0;
valid <= 0;
end
else
begin
valid <= 0;
state <= 3;
end
end
default : state <= 0;
endcase
end
end
always @ (*)
begin
case (row_col)
8'b0111_0111 : data = 4'hf;
8'b0111_1011 : data = 4'he;
8'b0111_1101 : data = 4'hd;
8'b0111_1110 : data = 4'hc;
8'b1011_0111 : data = 4'hb;
8'b1011_1011 : data = 4'ha;
8'b1011_1101 : data = 4'h9;
8'b1011_1110 : data = 4'h8;
8'b1101_0111 : data = 4'h7;
8'b1101_1011 : data = 4'h6;
8'b1101_1101 : data = 4'h5;
8'b1101_1110 : data = 4'h4;
8'b1110_0111 : data = 4'h3;
8'b1110_1011 : data = 4'h2;
8'b1110_1101 : data = 4'h1;
8'b1110_1110 : data = 4'h0;
default : data = 4'h0;
endcase
end
endmodule
數(shù)碼管頂層代碼:
module seven_seg (clk, rst_n, data_in, sel, seg);
input clk;
input rst_n;
input [23:0] data_in;
output [2:0] sel;
output [7:0] seg;
wire clk_1k;
freq freq_dut(
.clk(clk),
.rst_n(rst_n),
.clk_1k(clk_1k)
);
sel_seg_encode sel_seg_encode_dut(
.clk(clk_1k),
.rst_n(rst_n),
.data_in(data_in),
.sel(sel),
.seg(seg)
);
endmodule
分頻部分代碼:
module freq (clk, rst_n, clk_1k);
input clk;
input rst_n;
output reg clk_1k;
reg [14:0] cnt;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
clk_1k <= 1;
cnt <= 0;
end
else
begin
if (cnt < 24_999)
begin
cnt <= cnt + 1;
end
else
begin
cnt <= 0;
clk_1k <= ~clk_1k;
end
end
end
endmodule
位選段選連接代碼:
module sel_seg_encode (clk, rst_n, data_in, sel, seg);
input clk;
input rst_n;
input [23:0] data_in;
output [2:0] sel;
output [7:0] seg;
wire [3:0] num;
seg_encode seg_encode_dut(
.rst_n(rst_n),
.num(num),
.seg(seg)
);
sel_encode sel_encode_dut(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in),
.num(num),
.sel(sel)
);
endmodule
段選部分代碼:
module seg_encode (rst_n, num, seg);
input rst_n;
input [3:0] num;
output reg [7:0] seg;
always @ (*)
begin
if (!rst_n)
begin
seg = 8'b0000_0000;
end
else
begin
case (num)
0 : seg = 8'b1100_0000;
1 : seg = 8'b1111_1001;
2 : seg = 8'b1010_0100;
3 : seg = 8'b1011_0000;
4 : seg = 8'b1001_1001;
5 : seg = 8'b1001_0010;
6 : seg = 8'b1000_0010;
7 : seg = 8'b1111_1000;
8 : seg = 8'b1000_0000;
9 : seg = 8'b1001_0000;
default : seg = 8'b0000_0000;
endcase
end
end
endmodule
位選部分代碼:
module sel_encode (clk, rst_n, data_in, num, sel);
input clk;
input rst_n;
input [23:0] data_in;
output reg [3:0] num;
output reg [2:0] sel;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
sel <= 0;
end
else
begin
if (sel < 5)
begin
sel <= sel + 1;
end
else
begin
sel <= 0;
end
end
end
always @ (*)
begin
if (!rst_n)
begin
num = 0;
end
else
begin
case (sel)
0 : num = data_in[23:20];
1 : num = data_in[19:16];
2 : num = data_in[15:12];
3 : num = data_in[11:8];
4 : num = data_in[7:4];
5 : num = data_in[3:0];
default : num = 0;
endcase
end
end
endmodule
本篇到此結(jié)束,各位大俠,有緣再見!