組存儲(chǔ)器實(shí)驗(yàn):FPGA上實(shí)現(xiàn)CPU與lpm_ROM連接)
1. 項(xiàng)目概述這不是一次普通實(shí)驗(yàn)而是理解計(jì)算機(jī)底層運(yùn)行邏輯的“開(kāi)光儀式”西電計(jì)組實(shí)驗(yàn)一 存儲(chǔ)器實(shí)驗(yàn)這個(gè)名字聽(tīng)起來(lái)平平無(wú)奇但對(duì)西安電子科技大學(xué)計(jì)算機(jī)學(xué)院的學(xué)生來(lái)說(shuō)它幾乎是整個(gè)《計(jì)算機(jī)組成原理》課程的“第一道門(mén)檻”。我?guī)н^(guò)三屆計(jì)科和軟工專(zhuān)業(yè)的實(shí)驗(yàn)課每年開(kāi)學(xué)第一周實(shí)驗(yàn)室里最常聽(tīng)到的不是“老師這個(gè)波形不對(duì)”而是“老師ROM地址線接反了CPU怎么就跑飛了”——這恰恰說(shuō)明這個(gè)實(shí)驗(yàn)遠(yuǎn)不止是“把lpm_ROM模塊例化一下、連幾根線”那么簡(jiǎn)單。它本質(zhì)上是一次微型的硬件系統(tǒng)構(gòu)建實(shí)踐核心是存儲(chǔ)器與CPU的連接而載體是FPGA開(kāi)發(fā)板通常是Altera/Intel Cyclone系列比如DE2-115或類(lèi)似平臺(tái)。實(shí)驗(yàn)中用到的lpm_ROM是Quartus II或新版Intel Quartus Prime提供的參數(shù)化宏功能模塊它不是一塊物理芯片而是一個(gè)可配置的、固化數(shù)據(jù)的邏輯單元其行為完全由你寫(xiě)入的.mifMemory Initialization File文件決定。這意味著你寫(xiě)的每一行匯編指令、每一個(gè)數(shù)據(jù)字節(jié)都會(huì)直接映射到FPGA內(nèi)部的查找表LUT資源上最終變成可被CPU取指、讀數(shù)的“真實(shí)”存儲(chǔ)空間。所以這個(gè)實(shí)驗(yàn)解決的不是“能不能點(diǎn)亮LED”的問(wèn)題而是“指令如何從存儲(chǔ)器流向控制器、數(shù)據(jù)如何在總線上傳輸、時(shí)序如何保證不沖突”這一整套底層機(jī)制。它適合所有剛接觸硬件描述語(yǔ)言Verilog/VHDL和數(shù)字電路設(shè)計(jì)的本科生尤其適合那些在課堂上聽(tīng)懂了“MAR、MDR、PC、IR”卻始終無(wú)法在腦中構(gòu)建出它們之間物理連接的同學(xué)。如果你正為西電計(jì)組課設(shè)發(fā)愁或者想搞懂“以存儲(chǔ)器為中心的雙總線結(jié)構(gòu)CPU能不能通過(guò)系統(tǒng)總線和內(nèi)存直接交換數(shù)據(jù)”這類(lèi)問(wèn)題那么這個(gè)實(shí)驗(yàn)就是你親手拆解CPU工作流程的第一把螺絲刀。2. 整體設(shè)計(jì)思路與方案選型為什么必須用FPGA而不是仿真軟件2.1 為什么選擇FPGA作為實(shí)驗(yàn)平臺(tái)很多人會(huì)疑惑既然只是做存儲(chǔ)器實(shí)驗(yàn)用ModelSim仿真不就完事了何必折騰FPGA答案藏在“真實(shí)感”三個(gè)字里。仿真軟件如ModelSim能完美驗(yàn)證你的Verilog代碼邏輯是否正確但它永遠(yuǎn)無(wú)法模擬出信號(hào)在真實(shí)PCB走線上產(chǎn)生的延時(shí)、驅(qū)動(dòng)能力不足導(dǎo)致的波形畸變、電源噪聲對(duì)靜態(tài)時(shí)序的影響。舉個(gè)最典型的例子在仿真里你給ROM的地址線賦值addr 4b0001下一個(gè)時(shí)鐘沿?cái)?shù)據(jù)線q就立刻輸出對(duì)應(yīng)值。但在FPGA上如果地址線布線過(guò)長(zhǎng)、扇出過(guò)大或者你沒(méi)加適當(dāng)?shù)腎O約束實(shí)際到達(dá)ROM模塊輸入端的addr信號(hào)可能比時(shí)鐘晚幾個(gè)納秒這就導(dǎo)致“讀取錯(cuò)地址”的硬傷。而這個(gè)錯(cuò)誤在仿真里根本不會(huì)出現(xiàn)。西電計(jì)組實(shí)驗(yàn)強(qiáng)調(diào)“硬件思維”就是要你直面這些物理世界的限制。FPGA開(kāi)發(fā)環(huán)境Quartus DE2-115板卡提供了完整的“設(shè)計(jì)—綜合—布局布線—下載—調(diào)試”閉環(huán)讓你第一次體會(huì)到代碼寫(xiě)得再漂亮如果時(shí)序不滿(mǎn)足Timing Violation板子就是不工作。這正是工業(yè)界硬件工程師每天面對(duì)的真實(shí)戰(zhàn)場(chǎng)。所以這個(gè)實(shí)驗(yàn)的設(shè)計(jì)起點(diǎn)就是放棄“純邏輯正確”的幻想擁抱“物理可實(shí)現(xiàn)”的現(xiàn)實(shí)。2.2 為什么選用lpm_ROM而非自建ROMlpm_ROM是Intel FPGA工具鏈提供的一個(gè)高度優(yōu)化的IP核。它的優(yōu)勢(shì)在于“開(kāi)箱即用”和“資源可控”。你不需要從零開(kāi)始用寄存器堆Register File或分布式RAMDistributed RAM去搭建一個(gè)ROM只需在Quartus中調(diào)用lpm_ROM宏設(shè)置好數(shù)據(jù)位寬data_width、地址位寬address_width和初始化文件.mif工具就會(huì)自動(dòng)為你生成最優(yōu)的硬件實(shí)現(xiàn)——小容量用LUT實(shí)現(xiàn)大容量則自動(dòng)映射到片上Block RAM。更重要的是lpm_ROM的接口極其簡(jiǎn)潔只有address、q輸出數(shù)據(jù)和clk可選同步使能三根關(guān)鍵信號(hào)。這極大地降低了初學(xué)者的入門(mén)門(mén)檻讓你能把全部精力聚焦在“CPU如何訪問(wèn)它”這個(gè)核心問(wèn)題上而不是被復(fù)雜的存儲(chǔ)器控制邏輯如WE#寫(xiě)使能、OE#輸出使能所淹沒(méi)。當(dāng)然它的局限性也很明顯內(nèi)容是只讀的、不可在線修改。但這恰恰符合“程序存儲(chǔ)器”的本質(zhì)——指令一旦燒錄就不該被運(yùn)行時(shí)篡改。如果你后續(xù)要做西電計(jì)組課設(shè)基本模型機(jī)你會(huì)發(fā)現(xiàn)所有指令都固化在lpm_ROM里CPU的PC程序計(jì)數(shù)器就像一個(gè)指針在這個(gè)ROM空間里順序跳轉(zhuǎn)這才是馮·諾依曼體系最本真的模樣。2.3 整體架構(gòu)一個(gè)極簡(jiǎn)但完整的“CPU-存儲(chǔ)器”系統(tǒng)整個(gè)實(shí)驗(yàn)的頂層框圖可以濃縮為三個(gè)核心模塊CPU控制器、lpm_ROM存儲(chǔ)器和總線互連網(wǎng)絡(luò)。這里的“CPU控制器”并非一個(gè)完整的CPU而是一個(gè)精簡(jiǎn)版的有限狀態(tài)機(jī)FSM它負(fù)責(zé)產(chǎn)生讀取存儲(chǔ)器所需的全部控制信號(hào)MEMR存儲(chǔ)器讀、ADDR地址總線、DATA_IN數(shù)據(jù)輸入總線用于接收ROM返回的數(shù)據(jù)。lpm_ROM則扮演“被動(dòng)響應(yīng)者”的角色它只認(rèn)address和clk當(dāng)address有效且穩(wěn)定后在下一個(gè)時(shí)鐘沿將對(duì)應(yīng)地址的數(shù)據(jù)送到q輸出端。而“總線互連網(wǎng)絡(luò)”則是整個(gè)系統(tǒng)的血脈它由三組并行總線構(gòu)成地址總線Address Bus、數(shù)據(jù)總線Data Bus和控制總線Control Bus。地址總線寬度決定了你能訪問(wèn)多大的存儲(chǔ)空間例如8位地址線256字節(jié)數(shù)據(jù)總線寬度決定了每次能讀/寫(xiě)多少位數(shù)據(jù)通常為8位或16位控制總線則傳遞MEMR等關(guān)鍵命令。這個(gè)架構(gòu)看似簡(jiǎn)單但它已經(jīng)完整復(fù)現(xiàn)了“以存儲(chǔ)器為中心的雙總線結(jié)構(gòu)CPU”的雛形CPU通過(guò)地址總線發(fā)出請(qǐng)求通過(guò)控制總線發(fā)出讀命令存儲(chǔ)器通過(guò)數(shù)據(jù)總線返回結(jié)果。所有信號(hào)都在嚴(yán)格的時(shí)序約束下協(xié)同工作任何一根線接錯(cuò)、任何一個(gè)時(shí)序參數(shù)設(shè)錯(cuò)整個(gè)系統(tǒng)就會(huì)癱瘓。這正是西電計(jì)組實(shí)驗(yàn)的精髓所在——它用最小的硬件代價(jià)逼你建立起對(duì)“時(shí)序”和“接口協(xié)議”的敬畏之心。3. 核心細(xì)節(jié)解析與實(shí)操要點(diǎn)從.mif文件到引腳約束每一步都是坑3.1 .mif文件存儲(chǔ)器的“靈魂”格式與內(nèi)容必須零容錯(cuò).mifMemory Initialization File文件是lpm_ROM的“食譜”它定義了ROM里每個(gè)地址存放什么數(shù)據(jù)。它的語(yǔ)法非常嚴(yán)格稍有不慎Quartus就會(huì)報(bào)錯(cuò)而且錯(cuò)誤提示往往晦澀難懂。一個(gè)標(biāo)準(zhǔn)的.mif文件包含四個(gè)關(guān)鍵部分DEPTH深度即地址數(shù)量、WIDTH寬度即數(shù)據(jù)位寬、ADDRESS_RADIX地址進(jìn)制和DATA_RADIX數(shù)據(jù)進(jìn)制最后是CONTENT BEGIN ... END塊。例如一個(gè)8位寬、16個(gè)地址的ROM其.mif文件開(kāi)頭必須是DEPTH 16; WIDTH 8; ADDRESS_RADIX HEX; DATA_RADIX HEX; CONTENT BEGIN 00 : 0A; -- 地址0x00存放數(shù)據(jù)0x0A 01 : 1B; -- 地址0x01存放數(shù)據(jù)0x1B ... END;提示ADDRESS_RADIX和DATA_RADIX必須明確指定不能省略。很多同學(xué)習(xí)慣用十進(jìn)制寫(xiě)地址但Quartus默認(rèn)是HEX如果不聲明會(huì)導(dǎo)致地址映射完全錯(cuò)亂。更隱蔽的坑是空格和分號(hào)00 : 0A后面必須有分號(hào)CONTENT BEGIN和END必須頂格寫(xiě)前面不能有任何空格或Tab。我見(jiàn)過(guò)太多人因?yàn)閺?fù)制粘貼時(shí)帶入了不可見(jiàn)的Unicode字符如全角空格導(dǎo)致綜合失敗查了兩小時(shí)才發(fā)現(xiàn)問(wèn)題出在編輯器的編碼格式上。3.2 lpm_ROM模塊例化參數(shù)配置是成敗的關(guān)鍵在Verilog中例化lpm_ROM絕不是簡(jiǎn)單地復(fù)制粘貼一個(gè)模板。最關(guān)鍵的參數(shù)是.lpm_widthad()地址位寬和.lpm_width()數(shù)據(jù)位寬它們必須與你的.mif文件中的DEPTH和WIDTH嚴(yán)格一致。計(jì)算公式是lpm_widthad log2(DEPTH)。例如DEPTH16則lpm_widthad4DEPTH256則lpm_widthad8。如果這里填錯(cuò)比如把lpm_widthad4寫(xiě)成lpm_widthad3那么ROM只會(huì)識(shí)別低3位地址高1位被忽略導(dǎo)致所有地址0x00-0x07和0x08-0x0F讀取到相同的數(shù)據(jù)整個(gè)存儲(chǔ)空間就“折疊”了。另一個(gè)易錯(cuò)點(diǎn)是.lpm_file()參數(shù)它指向.mif文件的路徑。這個(gè)路徑必須是相對(duì)于當(dāng)前工程文件.qpf的相對(duì)路徑且不能包含中文或空格。最佳實(shí)踐是把.mif文件放在工程根目錄下然后寫(xiě)成.lpm_file(rom_init.mif)。此外q輸出數(shù)據(jù)信號(hào)的位寬必須與.lpm_width()完全匹配否則在頂層模塊連接時(shí)會(huì)報(bào)“位寬不匹配”的錯(cuò)誤而這個(gè)錯(cuò)誤有時(shí)會(huì)被綜合器靜默忽略導(dǎo)致功能異常。3.3 引腳約束Pin Assignment讓FPGA“認(rèn)識(shí)”你的物理按鍵和LED這是FPGA開(kāi)發(fā)中最容易被忽視卻最致命的一環(huán)。Quartus綜合出來(lái)的邏輯只是一個(gè)抽象的網(wǎng)表它不知道哪個(gè)KEY[0]信號(hào)對(duì)應(yīng)板子上的SW0撥碼開(kāi)關(guān)也不知道哪個(gè)LED[7:0]對(duì)應(yīng)D8-D1這排LED。這一切都靠引腳約束文件.qsf來(lái)告訴工具。西電常用的DE2-115板卡其用戶(hù)手冊(cè)User Manual里有一張?jiān)敱M的“Pin Table”列出了每個(gè)物理引腳對(duì)應(yīng)的信號(hào)名如KEY[0]對(duì)應(yīng)PIN_W15。你必須在.qsf文件中用set_location_assignment命令將你的Verilog信號(hào)名精確地綁定到這些物理引腳上。例如set_location_assignment PIN_W15 -to KEY[0] set_location_assignment PIN_V16 -to LED[0]注意-to后面跟的是你在Verilog里定義的信號(hào)名不是端口名。如果你在頂層模塊里把按鍵信號(hào)命名為sw_in那么這里就必須寫(xiě)-to sw_in。一個(gè)常見(jiàn)的錯(cuò)誤是把KEY[0]直接當(dāng)成信號(hào)名寫(xiě)進(jìn)約束而忽略了自己代碼里的命名。此外IO標(biāo)準(zhǔn)IO Standard也必須設(shè)置正確比如3.3-V LVTTL否則即使引腳連對(duì)了電平也不匹配LED就是不亮。我建議新手先用板卡自帶的“Hello World”例程如按鍵控制LED成功跑通后再移植自己的存儲(chǔ)器邏輯這樣可以排除引腳約束本身的干擾。4. 實(shí)操過(guò)程與核心環(huán)節(jié)實(shí)現(xiàn)手把手帶你完成從零到點(diǎn)亮的全過(guò)程4.1 環(huán)境準(zhǔn)備與工程創(chuàng)建避開(kāi)Quartus版本陷阱西電實(shí)驗(yàn)室普遍使用Quartus II 13.0 SP1或更新的Quartus Prime Lite Edition。這里有個(gè)關(guān)鍵提醒不要用最新版Quartus Prime去打開(kāi)老版本的工程文件.qpf。新版本工具會(huì)對(duì)舊工程進(jìn)行“升級(jí)”這個(gè)過(guò)程不可逆且升級(jí)后的工程在老版本Quartus上無(wú)法打開(kāi)。如果你從學(xué)長(zhǎng)那里拿到一個(gè)基于Quartus II 13.0的工程務(wù)必用同版本軟件打開(kāi)。創(chuàng)建新工程的步驟如下1File → New Project Wizard2選擇工程路徑強(qiáng)烈建議路徑全英文、無(wú)空格、無(wú)中文3在“Device Family”中選擇Cyclone IV E對(duì)應(yīng)DE2-1154在“Available Devices”中選擇具體型號(hào)EP4CE115F23C75完成向?qū)?。?chuàng)建完成后立即在Project菜單下點(diǎn)擊“Add New File”添加一個(gè)Verilog HDL File命名為top.v這就是你的頂層模塊。記住頂層模塊的端口列表必須與你將要使用的開(kāi)發(fā)板的物理接口完全一致包括KEY、SW、LED、HEX0等一個(gè)都不能少哪怕你暫時(shí)不用。4.2 頂層模塊設(shè)計(jì)總線信號(hào)的“翻譯官”頂層模塊top.v的核心任務(wù)是充當(dāng)CPU控制器和lpm_ROM之間的“翻譯官”。它接收來(lái)自CPU控制器的狀態(tài)信號(hào)如state根據(jù)當(dāng)前狀態(tài)生成ROM所需的address和memr信號(hào)并將ROM返回的q數(shù)據(jù)打包成CPU能理解的data_out。一個(gè)典型的頂層結(jié)構(gòu)如下module top( input clk, input rst_n, input [3:0] state, // CPU狀態(tài)機(jī)狀態(tài) output reg [7:0] data_out, // CPU數(shù)據(jù)總線輸出 output reg [3:0] addr_out, // ROM地址總線輸出 output reg memr // ROM讀使能 ); wire [7:0] rom_q; // 實(shí)例化lpm_ROM lpm_rom_1 uut_rom ( .address(addr_out), .q(rom_q), .clock(clk) ); // 根據(jù)state生成addr_out和memr always (posedge clk or negedge rst_n) begin if (!rst_n) begin addr_out 4h0; memr 1b0; end else begin case (state) 4b0001: begin // 取指階段 addr_out pc_reg; // PC寄存器值作為地址 memr 1b1; // 發(fā)起讀請(qǐng)求 end 4b0010: begin // 執(zhí)行階段 addr_out 4h0; // 可能讀取數(shù)據(jù)區(qū) memr 1b1; end default: begin addr_out 4h0; memr 1b0; end endcase end end // 將ROM數(shù)據(jù)輸出到CPU總線 assign data_out rom_q; endmodule這段代碼的關(guān)鍵在于always塊里的case語(yǔ)句。它清晰地展示了CPU狀態(tài)機(jī)如何驅(qū)動(dòng)存儲(chǔ)器訪問(wèn)在“取指”狀態(tài)4b0001addr_out被賦予程序計(jì)數(shù)器pc_reg的值同時(shí)拉高memr告訴ROM“我要讀指令”在“執(zhí)行”狀態(tài)4b0010addr_out可能切換到數(shù)據(jù)區(qū)地址再次發(fā)起讀操作。data_out則直接連接rom_q完成了數(shù)據(jù)的“搬運(yùn)”。這個(gè)設(shè)計(jì)就是“存儲(chǔ)器與cpu的連接”最直觀的體現(xiàn)。4.3 時(shí)序約束與Timing Analysis讓系統(tǒng)真正“跑起來(lái)”FPGA開(kāi)發(fā)的終極考驗(yàn)不是功能正確而是時(shí)序收斂。當(dāng)你點(diǎn)擊“Start Compilation”后Quartus會(huì)進(jìn)行“Timing Analysis”。如果報(bào)告里出現(xiàn)紅色的“Critical Warning: Setup Time Violation”那就意味著你的設(shè)計(jì)在目標(biāo)頻率下無(wú)法穩(wěn)定工作。對(duì)于存儲(chǔ)器實(shí)驗(yàn)最常見(jiàn)的時(shí)序問(wèn)題是address信號(hào)到達(dá)ROM輸入端的時(shí)間晚于clk信號(hào)的上升沿。解決方案有兩個(gè)1降低系統(tǒng)時(shí)鐘頻率。在Assignment → Settings → Device → Clock Settings中將主時(shí)鐘如CLOCK_50的頻率從50MHz改為10MHz這能大幅緩解時(shí)序壓力2添加IO約束。在.qsf文件中為addr_out信號(hào)添加輸出延遲約束set_output_delay -max 2.0 -clock clk [get_ports {addr_out[3:0]}]這條命令告訴工具“addr_out信號(hào)的最晚有效時(shí)間不能超過(guò)clk上升沿后2納秒”。這相當(dāng)于給信號(hào)傳輸預(yù)留了緩沖時(shí)間。實(shí)測(cè)下來(lái)對(duì)于DE2-115板卡將時(shí)鐘降至10MHz并為關(guān)鍵總線添加±1ns的IO約束就能讓絕大多數(shù)存儲(chǔ)器實(shí)驗(yàn)穩(wěn)定運(yùn)行。記住時(shí)序分析不是可選項(xiàng)而是必選項(xiàng)。一個(gè)沒(méi)有通過(guò)Timing Analysis的設(shè)計(jì)就像一輛沒(méi)有經(jīng)過(guò)碰撞測(cè)試的汽車(chē)外表完好但上路就是風(fēng)險(xiǎn)。4.4 下載與調(diào)試用SignalTap II抓取“看不見(jiàn)”的信號(hào)代碼編譯通過(guò)不代表板子就能工作。此時(shí)你需要用SignalTap II Logic Analyzer集成在Quartus中來(lái)“看見(jiàn)”FPGA內(nèi)部的信號(hào)。它的原理是在FPGA布局布線時(shí)悄悄地在你指定的信號(hào)路徑上插入一個(gè)小型的采樣邏輯單元將信號(hào)波形實(shí)時(shí)捕獲并傳回PC。這對(duì)于調(diào)試存儲(chǔ)器實(shí)驗(yàn)至關(guān)重要。例如當(dāng)你發(fā)現(xiàn)LED不按預(yù)期亮起可以同時(shí)抓取addr_out、memr和rom_q三個(gè)信號(hào)。如果addr_out一直在變化但rom_q始終為0那問(wèn)題一定出在.mif文件或lpm_ROM例化上如果addr_out和memr都正常但rom_q沒(méi)有變化那就要檢查rom_q是否被正確連接到頂層的data_out或者data_out的引腳約束是否正確。SignalTap II的采樣深度有限通常為16K點(diǎn)所以要合理設(shè)置觸發(fā)條件比如設(shè)置memr的上升沿為觸發(fā)這樣就能精準(zhǔn)捕獲每一次讀操作的全過(guò)程。這是我?guī)W(xué)生時(shí)反復(fù)強(qiáng)調(diào)的不要靠猜要用儀器看。一個(gè)合格的硬件工程師必須熟練掌握SignalTap II、Chip Planner查看資源分布和TimeQuest深入分析時(shí)序路徑這三大神器。5. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄那些年我們踩過(guò)的“經(jīng)典”深坑5.1 “ROM讀出來(lái)全是0”初始化文件與例化的雙重校驗(yàn)這個(gè)問(wèn)題堪稱(chēng)西電計(jì)組實(shí)驗(yàn)的“頭號(hào)殺手”?,F(xiàn)象是無(wú)論addr_out怎么變r(jià)om_q輸出永遠(yuǎn)是0。排查步驟必須按順序進(jìn)行1檢查.mif文件用記事本打開(kāi)確認(rèn)CONTENT BEGIN塊里確實(shí)有非零數(shù)據(jù)且地址范圍覆蓋了你的addr_out最大值2檢查lpm_ROM例化參數(shù)確認(rèn).lpm_file()路徑正確.lpm_widthad()和.lpm_width()與.mif文件的DEPTH和WIDTH完全匹配3檢查Quartus Messages窗口在Compilation Report里找到“Analysis Synthesis”部分看是否有“Warning: Cannot find file xxx.mif”之類(lèi)的提示這說(shuō)明路徑錯(cuò)了4終極驗(yàn)證在Quartus中右鍵點(diǎn)擊lpm_ROM實(shí)例 → “Properties” → “Simulation” → “Read MIF File”如果彈出對(duì)話(huà)框顯示“Successfully read mif file”說(shuō)明文件被正確加載。我曾經(jīng)幫一個(gè)學(xué)生debug發(fā)現(xiàn)他的.mif文件里DATA_RADIX BIN但數(shù)據(jù)卻寫(xiě)了0A十六進(jìn)制導(dǎo)致所有數(shù)據(jù)都被解釋為二進(jìn)制00001010也就是十進(jìn)制10看起來(lái)像0。根源在于進(jìn)制聲明不一致。5.2 “LED閃爍無(wú)規(guī)律”時(shí)序沖突與異步復(fù)位的陷阱現(xiàn)象是LED隨機(jī)亮滅毫無(wú)邏輯。這幾乎100%是異步復(fù)位rst_n未正確同步導(dǎo)致的。FPGA內(nèi)部的寄存器對(duì)復(fù)位信號(hào)的建立/保持時(shí)間Setup/Hold Time有嚴(yán)格要求。如果rst_n信號(hào)直接來(lái)自板載按鍵機(jī)械開(kāi)關(guān)其抖動(dòng)Bounce會(huì)產(chǎn)生多個(gè)窄脈沖這些脈沖在不同時(shí)鐘域下被采樣就會(huì)導(dǎo)致部分寄存器復(fù)位、部分不復(fù)位整個(gè)狀態(tài)機(jī)陷入混亂。解決方案是在頂層模塊里對(duì)rst_n進(jìn)行兩級(jí)同步。代碼如下reg rst_sync0, rst_sync1; always (posedge clk) begin rst_sync0 !KEY[0]; // 按鍵按下為低電平 rst_sync1 rst_sync0; end assign rst_n rst_sync1; // 同步后的復(fù)位信號(hào)這段代碼利用了兩個(gè)寄存器的級(jí)聯(lián)將原始的、毛刺滿(mǎn)滿(mǎn)的按鍵信號(hào)變成了一個(gè)干凈、穩(wěn)定的、與時(shí)鐘邊沿對(duì)齊的復(fù)位信號(hào)。這是數(shù)字電路設(shè)計(jì)的黃金法則也是西電A測(cè)中高頻考點(diǎn)。任何涉及外部按鍵、傳感器輸入的設(shè)計(jì)都必須做同步處理。5.3 “下載失敗JTAG鏈路錯(cuò)誤”硬件連接與驅(qū)動(dòng)的“玄學(xué)”排查現(xiàn)象是Quartus點(diǎn)擊“Programmer”選擇好.sof文件點(diǎn)擊“Start”進(jìn)度條不動(dòng)報(bào)錯(cuò)“Cant access JTAG chain”。這通常與硬件有關(guān)。排查清單如下1檢查USB線必須使用帶屏蔽層的數(shù)據(jù)線普通充電線不行2檢查USB端口換一個(gè)USB 2.0端口避免USB 3.0端口的兼容性問(wèn)題3檢查驅(qū)動(dòng)在設(shè)備管理器里看是否有“USB-Blaster”設(shè)備如果有黃色感嘆號(hào)說(shuō)明驅(qū)動(dòng)未裝好需重新安裝Quartus自帶的驅(qū)動(dòng)位于quartus\drivers\usb-blaster4檢查板卡供電DE2-115需要外接12V電源適配器僅靠USB供電是不夠的5檢查JTAG模式跳線板卡背面有一個(gè)JTAG/SWD跳線帽必須確保它插在JTAG位置。有一次一個(gè)學(xué)生折騰了整整一天最后發(fā)現(xiàn)是跳線帽松動(dòng)了輕輕一按問(wèn)題迎刃而解。硬件世界有時(shí)候就是這么樸實(shí)無(wú)華。5.4 “ModelSim仿真波形與板子行為不一致”仿真與綜合的鴻溝這是所有FPGA新手的必經(jīng)之痛。仿真里一切完美下載到板子上就出錯(cuò)。根本原因在于仿真器ModelSim只模擬邏輯功能而綜合器Quartus會(huì)將邏輯映射到真實(shí)的硬件資源上并施加嚴(yán)格的時(shí)序約束。一個(gè)典型的例子是“鎖存器Latch推斷”。如果你在Verilog中寫(xiě)了不完整的if-else語(yǔ)句比如always (a or b) begin if (a) y 1b1; // 缺少 else 分支 endModelSim會(huì)忠實(shí)地模擬出y在a為0時(shí)保持原值的行為即鎖存但Quartus綜合時(shí)會(huì)推斷出一個(gè)鎖存器而鎖存器在FPGA中是資源黑洞且極易引發(fā)時(shí)序問(wèn)題。解決方案是在編寫(xiě)組合邏輯時(shí)永遠(yuǎn)確保always塊內(nèi)所有分支都有明確的賦值或者直接使用always (*)并養(yǎng)成else兜底的習(xí)慣。另一個(gè)常見(jiàn)原因是未考慮信號(hào)傳播延時(shí)。仿真里a變b就立刻變但現(xiàn)實(shí)中b會(huì)滯后幾個(gè)納秒。因此在關(guān)鍵路徑上必須加入顯式的#1延遲僅用于仿真并在綜合時(shí)用(* syn_encoding none *)等屬性加以區(qū)分。記住仿真只是你的“草稿紙”真正的考場(chǎng)永遠(yuǎn)是那塊FPGA開(kāi)發(fā)板。6. 進(jìn)階思考與延伸方向從實(shí)驗(yàn)一到西電計(jì)組課設(shè)的躍遷路徑完成了存儲(chǔ)器實(shí)驗(yàn)?zāi)阒皇悄玫搅诉M(jìn)入西電計(jì)組世界的“入門(mén)券”。接下來(lái)的挑戰(zhàn)是如何把這個(gè)孤立的ROM模塊嵌入到一個(gè)更宏大的“基本模型機(jī)”中。這個(gè)躍遷需要你主動(dòng)思考三個(gè)維度擴(kuò)展性、交互性與復(fù)雜性。首先擴(kuò)展性意味著不能再滿(mǎn)足于一個(gè)靜態(tài)的ROM。你需要引入RAM如lpm_RAM_DQ讓它既能讀也能寫(xiě)從而支持變量存儲(chǔ)和棧操作。這時(shí)“存儲(chǔ)器與cpu的連接”就從單向讀取變成了雙向讀寫(xiě)控制總線必須增加MEMW存儲(chǔ)器寫(xiě)信號(hào)地址總線和數(shù)據(jù)總線也需要支持雙向驅(qū)動(dòng)。其次交互性意味著不能只靠預(yù)設(shè)的.mif文件啟動(dòng)。你需要設(shè)計(jì)一個(gè)簡(jiǎn)單的“監(jiān)控程序”Monitor通過(guò)串口UART接收PC發(fā)來(lái)的指令動(dòng)態(tài)修改RAM中的數(shù)據(jù)甚至在線修改ROM中的程序雖然物理上不可能但可以通過(guò)重載.mif文件并重新綜合來(lái)模擬。這會(huì)讓你深刻理解“虛擬存儲(chǔ)器管理c語(yǔ)言”背后的操作系統(tǒng)思想。最后復(fù)雜性意味著要打破“以存儲(chǔ)器為中心的雙總線結(jié)構(gòu)CPU”的簡(jiǎn)單模型。你可以嘗試設(shè)計(jì)一個(gè)“哈佛結(jié)構(gòu)”即指令和數(shù)據(jù)分別存放在獨(dú)立的ROM和RAM中擁有各自的地址總線和數(shù)據(jù)總線這能極大提升CPU的吞吐率也是現(xiàn)代處理器如ARM Cortex-M的標(biāo)配。當(dāng)你能獨(dú)立完成這些設(shè)計(jì)時(shí)西電計(jì)組課設(shè)就不再是恐懼的源頭而成了你展示硬件設(shè)計(jì)能力的舞臺(tái)。我個(gè)人在實(shí)際指導(dǎo)中發(fā)現(xiàn)那些能在實(shí)驗(yàn)一就主動(dòng)思考“這個(gè)ROM以后怎么和ALU、寄存器堆連在一起”的學(xué)生最終的課設(shè)作品往往能做出一個(gè)可運(yùn)行簡(jiǎn)單C語(yǔ)言小程序的微處理器。這才是西電計(jì)組實(shí)驗(yàn)想要傳遞的真正價(jià)值它不是一個(gè)終點(diǎn)而是一把鑰匙開(kāi)啟你通往計(jì)算機(jī)硬件世界的大門(mén)。