《FPGA入(rù)門(mén)基礎 》-- 跨时(shí)鐘(zhōng)域处理技巧
1. 如(rú)何設計(jì)时(shí)鐘(zhōng)域
假如(rú)設計(jì)中(zhōng)所(suǒ)有(yǒu)的(de)觸發(fà)器都使用(yòng)一(yī)个(gè)全(quán)局(jú)网(wǎng)絡,比如(rú)FPGA的(de)主(zhǔ)时(shí)鐘(zhōng)輸入(rù),那(nà)麼(me)我(wǒ)们(men)说(shuō)这(zhè)个(gè)設計(jì)只(zhī)有(yǒu)一(yī)个(gè)时(shí)鐘(zhōng)域。假如(rú)設計(jì)有(yǒu)两(liǎng)个(gè)輸入(rù)时(shí)鐘(zhōng),如(rú)图(tú)1所(suǒ)示,一(yī)个(gè)时(shí)鐘(zhōng)給(gěi)接口(kǒu)1使用(yòng),另(lìng)一(yī)給(gěi)接口(kǒu)2使用(yòng),那(nà)麼(me)我(wǒ)们(men)说(shuō)这(zhè)个(gè)設計(jì)中(zhōng)有(yǒu)两(liǎng)个(gè)时(shí)鐘(zhōng)域。
2. 什麼(me)是(shì)亞稳态
觸發(fà)器的(de)建立时(shí)間(jiān)和(hé)保持(chí)时(shí)間(jiān)在(zài)时(shí)鐘(zhōng)上(shàng)升(shēng)沿左(zuǒ)右(yòu)定(dìng)義了(le)一(yī)个(gè)时(shí)間(jiān)窗(chuāng)口(kǒu),如(rú)果(guǒ)觸發(fà)器的(de)數據(jù)輸入(rù)端口(kǒu)上(shàng)數據(jù)在(zài)这(zhè)个(gè)时(shí)間(jiān)窗(chuāng)口(kǒu)內(nèi)發(fà)生(shēng)變(biàn)化(huà)(或(huò)者(zhě)數據(jù)更(gèng)新),那(nà)麼(me)就(jiù)会(huì)産生(shēng)时(shí)序違規。存在(zài)这(zhè)个(gè)时(shí)序違規是(shì)因(yīn)为(wèi)建立时(shí)間(jiān)要(yào)求和(hé)保持(chí)时(shí)間(jiān)要(yào)求被(bèi)違反(fǎn)了(le),此(cǐ)时(shí)觸發(fà)器內(nèi)部(bù)的(de)一(yī)个(gè)节(jié)點(diǎn)(或(huò)者(zhě)要(yào)輸出(chū)到(dào)外(wài)部(bù)的(de)节(jié)點(diǎn))可(kě)能(néng)会(huì)在(zài)一(yī)个(gè)電(diàn)壓範圍內(nèi)浮動(dòng),无法稳定(dìng)在(zài)邏輯0或(huò)者(zhě)邏輯1狀态。換句(jù)話(huà)说(shuō),如(rú)果(guǒ)數據(jù)在(zài)上(shàng)述窗(chuāng)口(kǒu)中(zhōng)被(bèi)采集,觸發(fà)器中(zhōng)的(de)晶體(tǐ)管(guǎn)不(bù)能(néng)可(kě)靠地(dì)設置为(wèi)邏輯0或(huò)者(zhě)邏輯1对(duì)應(yìng)的(de)電(diàn)平上(shàng)。所(suǒ)以(yǐ)此(cǐ)时(shí)的(de)晶體(tǐ)管(guǎn)并未处于(yú)飽和(hé)區(qū)对(duì)應(yìng)的(de)高(gāo)或(huò)者(zhě)低電(diàn)平,而(ér)是(shì)在(zài)稳定(dìng)到(dào)一(yī)个(gè)确定(dìng)電(diàn)平之前(qián),徘徊在(zài)一(yī)个(gè)中(zhōng)間(jiān)電(diàn)平狀态(这(zhè)个(gè)中(zhōng)間(jiān)電(diàn)平或(huò)许是(shì)一(yī)个(gè)正(zhèng)确值,也(yě)许不(bù)是(shì))。如(rú)图(tú)2所(suǒ)示,这(zhè)就(jiù)是(shì)所(suǒ)謂的(de)亞稳态。
处理信(xìn)号(hào)亞稳态有(yǒu)三(sān)種(zhǒng)方(fāng)法:
-
相位控制
相位控制技術(shù)可(kě)以(yǐ)在(zài)一(yī)个(gè)时(shí)鐘(zhōng)頻率是(shì)另(lìng)外(wài)一(yī)个(gè)时(shí)鐘(zhōng)的(de)數倍,并且其中(zhōng)一(yī)个(gè)时(shí)鐘(zhōng)可(kě)以(yǐ)由(yóu)FPGA 內(nèi)部(bù)PLL 或(huò)者(zhě)DLL 控制时(shí)使用(yòng)。 -
多(duō)級寄存器
一(yī)般針(zhēn)对(duì)單bit控制信(xìn)号(hào)跨越两(liǎng)个(gè)异(yì)步时(shí)鐘(zhōng)域傳輸,可(kě)以(yǐ)采用(yòng)多(duō)級寄存器,俗稱多(duō)打(dǎ)拍。同(tóng)步電(diàn)路(lù)中(zhōng)的(de)第(dì)一(yī)拍後(hòu)也(yě)许会(huì)産生(shēng)亞稳态,但是(shì)信(xìn)号(hào)有(yǒu)機(jī)会(huì)在(zài)其被(bèi)第(dì)二(èr)級寄存以(yǐ)及(jí)被(bèi)其它(tā)邏輯看(kàn)到(dào)之前(qián)稳定(dìng)下(xià)来(lái)。常用(yòng)的(de)就(jiù)是(shì)对(duì)單bit信(xìn)号(hào)打(dǎ)两(liǎng)拍,这(zhè)也(yě)是(shì)最(zuì)簡單、最(zuì)常見(jiàn)的(de)处理方(fāng)式。 -
异(yì)步FIFO緩存
一(yī)般用(yòng)于(yú)跨时(shí)鐘(zhōng)域傳輸數據(jù),写端和(hé)读(dú)端分(fēn)别对(duì)應(yìng)两(liǎng)个(gè)时(shí)鐘(zhōng)域,由(yóu)空/滿信(xìn)号(hào)控制着读(dú)写过(guò)程,实現(xiàn)數據(jù)的(de)跨域傳輸。
每種(zhǒng)方(fāng)法應(yìng)对(duì)的(de)情(qíng)況不(bù)同(tóng),下(xià)面(miàn)着重(zhòng)介紹最(zuì)常用(yòng)的(de)單bit信(xìn)号(hào)消除亞稳态的(de)方(fāng)法:多(duō)級觸發(fà)器法。
3. 多(duō)級寄存器处理辦(bàn)法
在(zài)全(quán)同(tóng)步設計(jì)中(zhōng),如(rú)果(guǒ)信(xìn)号(hào)来(lái)自(zì)同(tóng)一(yī)时(shí)鐘(zhōng)域,各(gè)模块(kuài)的(de)輸入(rù)不(bù)需要(yào)使用(yòng)寄存器来(lái)寄存。只(zhī)要(yào)滿足建立时(shí)間(jiān)和(hé)保持(chí)时(shí)間(jiān)的(de)約束(shù),可(kě)以(yǐ)保證在(zài)时(shí)鐘(zhōng)上(shàng)升(shēng)沿到(dào)来(lái)时(shí),輸入(rù)信(xìn)号(hào)已經(jīng)稳定(dìng),可(kě)以(yǐ)采樣(yàng)得到(dào)正(zhèng)确的(de)值。但是(shì)如(rú)果(guǒ)要(yào)采用(yòng)輸入(rù)信(xìn)号(hào)的(de)邊(biān)沿来(lái)觸發(fà)某一(yī)过(guò)程,則需要(yào)寄存来(lái)檢测上(shàng)升(shēng)沿,这(zhè)是(shì)另(lìng)外(wài)一(yī)个(gè)範疇的(de)問(wèn)題(tí)。
一(yī)般而(ér)言單bit信(xìn)号(hào)就(jiù)是(shì)我(wǒ)们(men)所(suǒ)用(yòng)到(dào)的(de)脈沖信(xìn)号(hào)或(huò)者(zhě)電(diàn)平信(xìn)号(hào)。假設A和(hé)B是(shì)两(liǎng)个(gè)时(shí)鐘(zhōng)域,各(gè)自(zì)的(de)頻率是(shì)clk_a和(hé)clk_b,clk_a的(de)頻率高(gāo)于(yú)clk_b(同(tóng)頻相位差稳定(dìng)的(de),不(bù)在(zài)讨論範圍內(nèi)),那(nà)麼(me)單bit信(xìn)号(hào)傳輸分(fēn)为(wèi)两(liǎng)種(zhǒng)情(qíng)況。
3.1 信(xìn)号(hào)從B到(dào)A(慢(màn)到(dào)快(kuài))
在(zài)时(shí)鐘(zhōng)域B下(xià)的(de)脈沖信(xìn)号(hào)pulse_b在(zài)时(shí)鐘(zhōng)域A看(kàn)来(lái),是(shì)一(yī)个(gè)很宽(kuān)的(de)“電(diàn)平”信(xìn)号(hào)会(huì),保持(chí)多(duō)个(gè)clk_a的(de)时(shí)鐘(zhōng)周期(qī),所(suǒ)以(yǐ)一(yī)定(dìng)能(néng)被(bèi)clk_a采到(dào)。經(jīng)验(yàn)設計(jì)采集过(guò)程必須寄存两(liǎng)拍。第(dì)一(yī)拍将輸入(rù)信(xìn)号(hào)同(tóng)步化(huà),同(tóng)步化(huà)後(hòu)的(de)輸出(chū)可(kě)能(néng)带(dài)来(lái)建立/保持(chí)时(shí)間(jiān)的(de)沖突,産生(shēng)亞稳态。需要(yào)再寄存一(yī)拍,減少(shǎo)亞稳态带(dài)来(lái)的(de)影響。一(yī)般来(lái)说(shuō)两(liǎng)級是(shì)最(zuì)基本(běn)要(yào)求,如(rú)果(guǒ)是(shì)高(gāo)頻率設計(jì),則需要(yào)增加寄存級數来(lái)大幅降低系(xì)統的(de)不(bù)稳定(dìng)性(xìng)。也(yě)就(jiù)是(shì)说(shuō)采用(yòng)多(duō)級觸發(fà)器来(lái)采樣(yàng)来(lái)自(zì)异(yì)步时(shí)鐘(zhōng)域的(de)信(xìn)号(hào),級數越多(duō),同(tóng)步过(guò)来(lái)的(de)信(xìn)号(hào)越稳定(dìng)。
特(tè)别需要(yào)強(qiáng)調的(de)是(shì),此(cǐ)时(shí)pulse_b必須是(shì)clk_b下(xià)的(de)寄存器信(xìn)号(hào),如(rú)果(guǒ)pulse_b是(shì)clk_b下(xià)的(de)組合邏輯信(xìn)号(hào),一(yī)定(dìng)要(yào)先(xiān)在(zài)clk_b先(xiān)用(yòng)D觸發(fà)器(DFF)抓一(yī)拍,再使用(yòng)两(liǎng)級DFF向(xiàng)clk_a傳遞。这(zhè)是(shì)因(yīn)为(wèi)clk_b下(xià)的(de)組合邏輯信(xìn)号(hào)会(huì)有(yǒu)毛(máo)刺,在(zài)clk_b下(xià)使用(yòng)时(shí)会(huì)由(yóu)setup/hold时(shí)間(jiān)保證毛(máo)刺不(bù)会(huì)被(bèi)clk_b采到(dào),但由(yóu)于(yú)异(yì)步相位不(bù)确定(dìng),組合邏輯的(de)毛(máo)刺卻极(jí)有(yǒu)可(kě)能(néng)被(bèi)clk_a采到(dào)。一(yī)般代(dài)碼設計(jì)如(rú)下(xià):
always @ (posedge clk_a or negedge rst_n) begin if (rst_n == 1'b0) begin pules_a_r1 <= 1'b0;
pules_a_r2 <= 1'b0;
pules_a_r3 <= 1'b0; end else begin //打(dǎ)3拍 pules_a_r1 <= pulse_b;
pules_a_r2 <= pules_a_r1;
pules_a_r3 <= pules_a_r2; end end assign pulse_a_pos = pules_a_r2 & (~pules_a_r3); //上(shàng)升(shēng)沿檢测 assign pulse_a_neg = pules_a_r3 & (~pules_a_r2); //下(xià)降沿檢测 assign pulse_a = pules_a_r2;
实際上(shàng),具體(tǐ)打(dǎ)幾(jǐ)拍背後(hòu)是(shì)有(yǒu)时(shí)序收(shōu)斂的(de)理論作支撐的(de),对(duì)于(yú)一(yī)般的(de)設計(jì)而(ér)言,打(dǎ)两(liǎng)三(sān)拍就(jiù)已經(jīng)足够了(le)。
3.2 信(xìn)号(hào)從A到(dào)B(快(kuài)到(dào)慢(màn))
如(rú)果(guǒ)單bit信(xìn)号(hào)從时(shí)鐘(zhōng)域A到(dào)时(shí)鐘(zhōng)域B,那(nà)麼(me)存在(zài)两(liǎng)種(zhǒng)不(bù)同(tóng)的(de)情(qíng)況,傳輸脈沖信(xìn)号(hào)pulse_a或(huò)傳輸電(diàn)平信(xìn)号(hào)level_a。实際上(shàng),在(zài)一(yī)般情(qíng)況下(xià)只(zhī)有(yǒu)電(diàn)平信(xìn)号(hào)level_a的(de)宽(kuān)度(dù)能(néng)被(bèi)clk_b采集到(dào)才可(kě)以(yǐ)保證系(xì)統正(zhèng)常工作。那(nà)麼(me)对(duì)于(yú)脈沖信(xìn)号(hào)pulse_a采取(qǔ)怎樣(yàng)的(de)处理方(fāng)法呢?可(kě)以(yǐ)用(yòng)一(yī)个(gè)展(zhǎn)宽(kuān)信(xìn)号(hào)来(lái)替代(dài)pulse_a实現(xiàn)垮时(shí)鐘(zhōng)域的(de)握手(shǒu)。
主(zhǔ)要(yào)原理就(jiù)是(shì)先(xiān)把脈沖信(xìn)号(hào)在(zài)clk_a下(xià)展(zhǎn)宽(kuān),變(biàn)成(chéng)電(diàn)平信(xìn)号(hào)signal_a,再向(xiàng)clk_b傳遞,當确認clk_b已經(jīng)“看(kàn)見(jiàn)”信(xìn)号(hào)同(tóng)步过(guò)去(qù)之後(hòu),再清(qīng)掉signal_a。代(dài)碼通(tòng)用(yòng)框架如(rú)下(xià):
module Sync_Pulse (
clk_a,
clk_b,
rst_n,
pulse_a_in,
pulse_b_out,
b_out
); /****************************************************/ input clk_a; input clk_b; input rst_n; input pulse_a; output pulse_b_out; output b_out; /****************************************************/ reg signal_a; reg signal_b; reg signal_b_r1; reg signal_b_r2; reg signal_b_a1; reg signal_b_a2; /****************************************************/ //在(zài)时(shí)鐘(zhōng)域clk_a下(xià),生(shēng)成(chéng)展(zhǎn)宽(kuān)信(xìn)号(hào)signal_a always @ (posedge clk_a or negedge rst_n) begin if (rst_n == 1'b0)
signal_a <= 1'b0; else if (pulse_a_in) //檢测到(dào)到(dào)輸入(rù)信(xìn)号(hào)pulse_a_in被(bèi)拉高(gāo),則拉高(gāo)signal_a signal_a <= 1'b1; else if (signal_b_a2) //檢测到(dào)signal_b1_a2被(bèi)拉高(gāo),則拉低signal_a signal_a <= 1'b0; else; end //在(zài)时(shí)鐘(zhōng)域clk_b下(xià),采集signal_a,生(shēng)成(chéng)signal_b always @ (posedge clk_b or negedge rst_n) begin if (rst_n == 1'b0)
signal_b <= 1'b0; else signal_b <= signal_a; end //多(duō)級觸發(fà)器处理 always @ (posedge clk_b or negedge rst_n) begin if (rst_n == 1'b0) begin signal_b_r1 <= 1'b0;
signal_b_r2 <= 1'b0; end else begin signal_b_r1 <= signal_b; //对(duì)signal_b打(dǎ)两(liǎng)拍 signal_b_r2 <= signal_b_r1; end end //在(zài)时(shí)鐘(zhōng)域clk_a下(xià),采集signal_b_r1,用(yòng)于(yú)反(fǎn)饋来(lái)拉低展(zhǎn)宽(kuān)信(xìn)号(hào)signal_a always @ (posedge clk_a or negedge rst_n) begin if (rst_n == 1'b0) begin signal_b_a1 <= 1'b0;
signal_b_a2 <= 1'b0; end else begin signal_b_a1 <= signal_b_r1; //对(duì)signal_b_r1打(dǎ)两(liǎng)拍,因(yīn)为(wèi)同(tóng)樣(yàng)涉及(jí)到(dào)跨时(shí)鐘(zhōng)域 signal_b_a2 <= signal_b_a1; end end assign pulse_b_out = signal_b_r1 & (~signal_b_r2); assign b_out = signal_b_r1; endmodule
这(zhè)樣(yàng)一(yī)来(lái),实際上(shàng)clk_a下(xià)的(de)脈沖信(xìn)号(hào)“作用(yòng)”到(dào)了(le)clk_b时(shí)鐘(zhōng)域下(xià),它(tā)对(duì)于(yú)clk_a與(yǔ)clk_b的(de)时(shí)鐘(zhōng)頻率關(guān)系(xì)沒(méi)有(yǒu)任何限制,快(kuài)到(dào)慢(màn),慢(màn)到(dào)快(kuài)就(jiù)都沒(méi)問(wèn)題(tí)了(le)。
總(zǒng)而(ér)言之,在(zài)設計(jì)中(zhōng)可(kě)以(yǐ)簡單的(de)牢記(jì)以(yǐ)下(xià)五(wǔ)条(tiáo)原則:(請谨記(jì))
1. 再全(quán)局(jú)时(shí)鐘(zhōng)的(de)跳變(biàn)沿最(zuì)可(kě)靠。
2. 来(lái)自(zì)异(yì)步时(shí)鐘(zhōng)域的(de)輸入(rù)需要(yào)寄存一(yī)次(cì)以(yǐ)同(tóng)步化(huà),再寄存一(yī)次(cì)以(yǐ)減少(shǎo)亞稳态带(dài)来(lái)的(de)影響。
3. 不(bù)需要(yào)用(yòng)到(dào)跳變(biàn)沿的(de)来(lái)自(zì)同(tóng)一(yī)时(shí)鐘(zhōng)域的(de)輸入(rù),沒(méi)有(yǒu)必要(yào)对(duì)信(xìn)号(hào)進(jìn)行寄存。
4. 需要(yào)用(yòng)到(dào)跳變(biàn)沿的(de)来(lái)自(zì)同(tóng)一(yī)时(shí)鐘(zhōng)域的(de)輸入(rù),寄存一(yī)次(cì)即可(kě)。
5. 需要(yào)用(yòng)到(dào)跳變(biàn)沿的(de)来(lái)自(zì)不(bù)同(tóng)时(shí)鐘(zhōng)域的(de)輸入(rù),需要(yào)用(yòng)到(dào)3个(gè)觸發(fà)器,前(qián)两(liǎng)个(gè)用(yòng)以(yǐ)同(tóng)步,第(dì)3个(gè)觸發(fà)器的(de)輸出(chū)和(hé)第(dì)2个(gè)的(de)輸出(chū)經(jīng)过(guò)邏輯門(mén)来(lái)判斷跳變(biàn)沿。
3.3 設計(jì)分(fēn)區(qū)同(tóng)步器模块(kuài)
在(zài)頂层为(wèi)設計(jì)分(fēn)區(qū)是(shì)一(yī)个(gè)好(hǎo)的(de)設計(jì)实踐行为(wèi),这(zhè)樣(yàng)任何功能(néng)模块(kuài)外(wài)面(miàn)都包(bāo)含一(yī)个(gè)独立的(de)同(tóng)步器模块(kuài)。这(zhè)樣(yàng)有(yǒu)利于(yú)在(zài)劃(huà)分(fēn)模块(kuài)的(de)基礎上(shàng)实現(xiàn)所(suǒ)謂的(de)理想(xiǎng)时(shí)鐘(zhōng)域情(qíng)況(即整个(gè)設計(jì)模块(kuài)只(zhī)有(yǒu)一(yī)个(gè)时(shí)鐘(zhōng)),如(rú)下(xià)图(tú)所(suǒ)示:
对(duì)設計(jì)進(jìn)行分(fēn)區(qū)有(yǒu)很多(duō)理由(yóu)。首先(xiān),对(duì)每个(gè)独立的(de)功能(néng)模块(kuài)進(jìn)行时(shí)序分(fēn)析變(biàn)得簡易,因(yīn)为(wèi)模块(kuài)都是(shì)完全(quán)的(de)同(tóng)步設計(jì)。其次(cì),整个(gè)同(tóng)步模块(kuài)中(zhōng)的(de)时(shí)序例外(wài)也(yě)很容易得到(dào)定(dìng)義。再次(cì),底层模块(kuài)的(de)同(tóng)步器加时(shí)序例外(wài)在(zài)代(dài)入(rù)到(dào)設計(jì)頂层时(shí),大大降低了(le)由(yóu)于(yú)人(rén)为(wèi)失誤造成(chéng)的(de)疏漏。所(suǒ)以(yǐ),同(tóng)步寄存器應(yìng)該在(zài)功能(néng)模块(kuài)外(wài)單独分(fēn)區(qū)。















