如何理解「一個always裡面只輸出一個信號,避免互相干擾」?

每個always都是同時發生的,那怎麼一個always輸出一個信號就避免互相干擾了?


這個關乎代碼風格,不會影響實際綜合結果。

有三種可能的代碼組織方式:

(1)每個always文只寫一個時序信號的邏輯。

(2)每個always文寫一組功能相關的時序信號的邏輯。

(3)所有時序信號的邏輯都寫在一個always文內。

優劣:

(1)和(2)都是我了解的日本半導體行業推薦的規範。之所以要按信號分開,是因為把相關的信號集中在一起編寫、閱讀、調試都比較方便。(1)粒度分太細也會造成代碼臃腫,所以個人推崇(2)。

(3)當然也可以。想想如果代碼多起來,比如某個信號可能會出現在25、80、300行處,閱讀、調試上不太便利。

至於按哪種方式編寫代碼,有的公司會有規範,有時候可以自己把握。

無論如何,一定要避免把一個信號的賦值寫在多個always文內,尤其always還包含了各種同步、非同步的觸發信號。


上面幾位說的挺好了。我們實驗室的代碼風格跟馮大 @馮敬堯的差不多,也結合了 @JonsonXP的第二種方法

組合邏輯寫在一組always @(*)塊中(此組合邏輯是阻塞賦值,不相關並行邏輯放到不同always 中,一組相關邏輯放到一個always塊中),實現具體的電路邏輯;時序邏輯寫到另一組always 塊中,主要就是將組合邏輯的值存入寄存器中,輸入到reg中。如下:

//信號定義
reg [3:0] reg_A, rin_A;
reg [3:0] reg_B, rin_B;

//時序邏輯,將組合邏輯的結果存入register中

always @(posedge clk or negedge rst)begin
if(! rst) begin
reg_A &<= 4"h0; reg_B &<= 4"h0; end else begin reg_A &<= rin_A; reg_B &<= rin_B; end end

//組合邏輯,實現具體的電路邏輯,相關信號放在一起,與此組信號並行的放在其他always中

always @(*)begin
//將寄存器存儲的內容作為初值
rin_A = reg_A;
rin_B = reg_B;
//具體邏輯實現
if(A)begin
rin_A = (reg_A+C)| B;
rin_B = rin_A+D+E;
end
end

這時就出現一個有趣的現象,雖然rin_A ,rin_B是reg型,但因為只是中間信號,綜合後成了一個wire線型信號。

PS.解釋下邏輯實現用組合邏輯寫的好處:因為組合邏輯採用阻塞賦值,是順序執行,更容易理解控制;而時序邏輯並行執行控制起來比較麻煩。


沒看到題主所說的代碼,猜想你看到的可能是一下兩種之一

1. 一個reg只在一個always中被賦值

2. always中不要對敏感列表中的變數賦值


無所謂的吧,只是比較清楚、修改方便,可以避免把其他的輸出值改壞掉


這個是胡扯。一個always只輸出一個信號,是一種非常噁心的coding風格。最好的coding風格應該在一個module把所有的非阻塞賦值一個always寫完。組合邏輯集中寫在一塊,時序邏輯集中寫在一塊,並且時序邏輯只做最簡單的wire到reg的賦值。所有的寄存器以reg做後綴,與寄存器做賦值的以nxt做後綴,類似這種:

//----------以下是組合邏輯,所有的邏輯都在這裡實現

assign A_nxt = B ? C : A_reg;

assign D_nxt = E ? F : H ? G : D_reg;

assign K=L M;

//----------以下為時序邏輯,只做nxt給reg賦值,不包含任何邏輯。

always @(posedge clk or negedge rst_)

begin

if(! rst_)

begin

A_reg &<= xx"h0;

D_reg &<= xx"h0;

else

begin

A_reg &<= A_nxt;

D_reg &<= D_nxt;

end

end


百度一下三段式狀態機怎麼寫吧,按那樣寫就行。


我說一句「有1000個信號,就要寫1000個always塊嗎?」

也許沒人說你錯,但肯定有人說你笨。

這不是一個好的coding style,代碼臃腫難看,放眼望去全是always,而且敲起來費勁不

個人比較推崇的是,首先組合邏輯和時序邏輯一定要分開;其次,具有相同行為的一組信號放在一起;最後,學知乎,用好分割線,稍微注釋下,避免信號太多時自己邏輯混亂


我想這句話的意思應該是 一個信號只能由在一個always賦值吧?

沒有說明敏感表就說每個always都是同時發生,我想題主應該還對邏輯設計接觸不深吧。

其實題主所說的是一種注重對電路的描述,這種方法的好處是,如果給你一段代碼,你照著代碼可以直接畫出對應的電路圖,反之亦然,簡單明了。

這種方式在小量級的邏輯中是可行而且方便的,例如基於ram的fifo啦,用cpld控制十幾個上電和複位信號啦。

但是一旦涉及到較複雜的邏輯,這種方式寫出來的代碼就會變得無比龐大,如果沒有詳細的設計文檔和注釋,簡直就是要命。

PS 其實碼代碼只佔了邏輯設計工作不到10分之1,更多的時候,是無休無止的方案設計和調試。如果遇到了性能上的瓶頸,優化起來才真是一種折磨。


這明顯是一個 程序員效率vs程序效率 的問題:

1:如果你有無限的時間(這是在過去),每個模塊都在心中/visio中畫好。然後每個pipline的data信號寫一塊,clockgating信號寫一塊,flipflop寫一塊。注意,是per pipeline。這樣保證做出來就是你想要的。

2:因為compiler越來越智能,所以現在我的準則基本是比較相關的logic寫一塊。所有同clock下的flipflop寫一塊:

always @(clk):

if nblock_foo1:

foo1_0 &<= foo0_next;

.....

if nblock_foo2:

foo12&<= foo0_next;

.....

3:未來我準備flipflop都不寫了。就是寫成c語言那樣。因為基本上看來compiler確實很聰明了。RTL會變得越來越軟。用諸如:

always @(clk):

if nblock_foo1:

foo1_0 &<= foo1_0 * foo1_0 + a *c - d + c ;

這種寫法。

反思自己最近太過於追求程序效率了。得到的類似30%效率提升其實等一代scaling就可以。所以不是數量級的差別不必太在乎。關鍵在於新functionality。未來大家應該會從RTL中解放出來吧,目前的c-RTL compiler已經做得不錯了。


看了那麼多答案,自己也來答一下。

為什麼會有一個「always裡面只輸出一個信號,避免互相干擾」這樣的說法?因為在很早的時候,綜合器功能還不是很健全,把多個信號寫在一個always塊里,可能會得到與你期待不同的結果。而將每個信號單獨寫在一個always塊里,綜合器可以比較容易識別,得到你想要的結果。

但是,現在不一樣的了,綜合器已經十分智能。所以,在always里寫多個信號也是可以的,但是需要注意,組合邏輯和時序邏輯最好分開,另外不能用程序化的思維去思考。

既然always既可以描述組合邏輯,又可以描述時序邏輯,那麼這就造成了一個讓初學者迷惑的現象。

下面是一個簡單的計數器,在這裡reg型的a,被綜合成了觸發器,實現了時序電路(可以存儲狀態)。注意這裡一定要使用"&<=",而不是"=",去描述一個時序邏輯。

reg [7:0] a;
always @(posedge clk) begin
if(rst) begin
a &<= 8"b0; end else begin a &<= a + 8"b1 end end

而下面一段代碼,實現了一個簡單的加法器。實際上,這段邏輯的綜合結果沒有任何觸發器,僅僅是靠組合邏輯實現。對a的reg定義,只是為了滿足Verilog的語法。注意這裡一定要使用"=",而不是"&<=",去描述一個組合邏輯。

reg [7:0] a;
always @(*) begin
a = A + B;
end

所以Verilog提供了另外的wire 型,使用連續賦值,也可以同樣實現上述邏輯

wire [7:0] a;
assign a = A + B;

最好不要"&<=" 和 "=" 混用,那樣的邏輯不夠清晰。

另外說一下用always描述組合邏輯很容易犯錯的地方。

reg [7:0] a;
always @(*) begin
if(c) begin
a = A + B;
end
end

上述代碼的綜合結果會產生一個鎖存器,因為上述代碼沒有完整的給出所有條件,實際效果跟下面代碼是一樣的,這樣的代碼可以說在FPGA邏輯設計中是極不推薦的。

reg [7:0] a;
always @(*) begin
if(c) begin
a = A + B;
end
else begin
a = a;
end

這也說明了一點,如 @玉慶所說,敏感信號不要出現在always塊內賦值語句的左側。

永遠記得將所有case,所有else條件列全,這是一個良好的習慣。

而System Verilog祭出了大招。

  1. 使用always_comb和always_ff取代普通的always,直接告訴綜合器你的意圖,這也間接說明了不希望你在一個always塊里同時描述組合邏輯和時序邏輯。

  2. 使用logic數據類型將wire和reg合為一體,讓綜合器去識別去吧。


寫hdl代碼就是在畫電路圖。用結構話語言的形式,而非圖畫圖形。越多的輸出寫在一起,就是把更多的與非門畫在一張圖紙上,太多了,不易後期維護,容易出錯(可能寫出綜合器不理解,誤解的東西)。每個模塊只寫一個輸出,就好比沒張圖紙上只做一個與非門。我了個去,這得寫到哪輩子啊。。。


還有這要求?


其實你好好寫一個FSM就知道了。。裡面包含了組合邏輯和時序邏輯。。。

根據state的控制輸出信號(無時序關係),在一個always(*)中描述邏輯。

根據state變換的控制輸出信號(state dependent),單獨在一個always(posedge clk)中描述

根據state變換的FSM自身state, 單獨在一個always(posedge clk)中描述。

我之前因為不太care代碼的清晰程度。。。結果現在自己回去看自己寫的代碼就斯巴達了。。。


我覺得原來提問的代碼你不要刪掉


避免干擾自己思路吧~


反正我們做些小工程絕對不會這樣寫的

我們是怎麼舒服怎麼寫

沒啥參考價值,啊~~

大公司里的不了解~~


推薦閱讀:

如何評價復旦大學VIP實驗室范益波教授團隊發布開源H.265視頻編碼IP核?

TAG:現場可編輯邏輯門陣列FPGA | 數字電路 | Verilog | ASIC | 數字IC設計 |