2014年3月30日 星期日

module介面訊號的收斂與發散的思考

在離散數學課程中,曾學到如何把一個發散的數學式子轉換到收斂的數學式子;其做法是把原來式子做整理(積分或是微分的處理),重新寫出新的數學式子,這樣子才可能把發散的條件轉換到收斂的條件,然後才能得到我們想要的結果。
同理,一個控制流程的很好的module(模組),它在介面訊號上,也會是一個收斂的。如何確保你的module是一個收斂的介面module
第一步: 選擇一個clock為主要的clock domain,所有的控制訊號都是在這個主要的clock domain下被控制、操作。
第二步: 把所有不同步的控制訊號處理同步到主clock domain。這種做法就是把原來發散條件轉換到收斂條件。以下是示意圖。

Fig1: Divergence and convergence









以下的波形圖是用來解釋上面圖形的。從波形圖中clockA有一個需求reqA,向clockBmodule提出。因為不相同頻率的訊號直接使用,會有meta stable問題,所以reqB_syn1就是來解決meta stable。之後再拿reqB_syn2reqB_syn3來操作,得到一個需求訊號reqB_getModule B用這個reqB_get是安全的。然後再產生reqB_clr去回覆module A 的需求。reqB_clr一樣,也是經過一連串的同步處理,最後,module A得到在clockA domain reqA_clrmodule A則reqA_clr來清除reqA訊號,這也是安全的。以下是波形圖。

Fig2: waveform of divergence and convergence










這樣子的做法,可解決大部份介面訊號發散的情況,也可以運用到所有的控制訊號的處理。目前我唯一遇過比較不同的是DDR PHY的控制訊號處理,它沒有辦法把所有的訊號線同步到相同的clock domain,而這是因為DDR PHY的設計上比較講究latency的長短以及它本身是clock的上升緣及下降緣都是資料處理的時間點,所以做法上更複雜,但是其基本精神也是沒有脫離上述的觀念。
在設計一個模組時,一定都要隨時隨地保有發散、收斂的觀念在心中,並確保每個控制訊號都是收斂的環境下操作,這樣子才可以確保每個IP都是收斂且穩定高的module 


2014年3月23日 星期日

恐龍版OS裏的哲學家問題的思考

在做controller時,常需要去思考一個問題,那就是權杖是由誰主導?一個好的controller就是把權杖的問題處理好,讓各個部份都能各司其職,也不會相突衝。這樣子說明,或許有許多人不明瞭,以下我舉一個例子。

PCIE的規格裏,有一個skip order set的機制,是被用來做在傳輸中補償機制。但是傳送skip order是由誰做,卻沒有明確的說明,但是這部份的描述是放在LTSSM章節。而PCIE大致上是被分為Tx, Rx, LTSSM三大部份。既然被寫在LTSSM章節,那應該由LTSSM做即可;但是LTSSM並沒有負責全部的流程機制,有部份是由Tx負責。一旦權杖沒有做好,就會造成溝通問題。

PCIEcontroller要操控性好、流暢,Tx, RX以及LTSSM都是重要的部份。Skip order set則應該算是其中會影響的重要螺絲。從LTSSMFSM來看,當進入L0時,權杖(Token)就已經不在LTSSM那一層,而是到TxDLP或是TLP。如果把skip order set只做在LTSSM那一層,而當Tx進入L0時,Tx已經拿到權杖,而當skip order set倒數時間到,需要發送skip封包時,因為Tx沒有做skip order set的機制,所以要把權杖還給LTSSMLTSSM需要把權杖搶走,送完Skip order set後再歸還權杖。此時Tx所需要做的事就是保證在未來的傳送skip order set的時間內,都不會有TLP或是DLP要傳送,靜待LTSSM 完成工作。這是我常看到的hand shake;但是常因hand shake時間溝通不清楚,進而影響了skip order set的傳送。

PCIE的規格書裏,說明進入L0後,就是屬於Tx的負責範圍,那為什麼還要要求 LTSSM做事?很多人都以為這只是hand shake機制沒有做好,做好後就不會發生問題。在我看來,這樣子的做法只是治標,不是治本。當你以後要增加新功能時,會不會受到影響?你還能確定你的hand shake還可以運作嗎?其實整個核心問題就是「權杖」,恐龍版的OS明確的說出,權杖拿到手,就要做事,不做事就會dead lock。為什麼Tx你已經拿到權杖,還要把skip order set的工作往外推出,叫LTSSM做?這和恐龍的觀念不符合。

換個角度想,拿到權杖的人負責做事,而且要把所有的事都做完。移出權杖的人,則是已經把該做的事情做完了,沒有任何責任。用這樣子的想法去架構你的control flow,簡單而且不太會出錯。尤其是用在數位和類比之間的溝通,其實還滿好用的。

之後,我也常常用這個方法去思考控制轉移的問題,簡化了不少複雜控制。再一次驗證了,經典真是不愧為經典。

註解:1. 恐龍版的書名應該是Operating System Concepts
      2. 作者: Abraham SilberschatzPeter B. GalvinGreg Gagne

2014年3月16日 星期日

case裏default中don't care的使用經驗

以上是有人發現的文章,然後和我討論,建議應該把” default: y=1’bx” 換成是” default: y=1’b0” 或是default: y=1’b1”。反正就是不應該是1’bx,不然會造成系統不穩,或是合成時,會有問題。

” default: y=1’bx” 真的會有問題嗎?
做為一個數位工程師,邏輯推理能力應該是我們自豪的。原英文描述是說在模擬(simulation)時,會有pre-synthesis simulation和post-synthesis simulation的結果不相同(mismatch),所以如果你是想要它相同的話,你應該是把1’bx換成是固定的值,這樣子,每次模擬時,就都會是一樣的。對於這樣子的建議,我同意的它的說法。但是,它的前面有個前提,你的1’bx是會被當成是”don’t care”來處理。我們都知道,don’t care就是不在乎它的結果,甚至每次都是不一樣也沒有關係。所以這樣子的”don’t care”當然會在不同的模擬過程,造成不同的結果。

我們都學過真值表(truth table)

A  fun   B
0
1
0
0
1
1
1
X


上面的truth table表示什麼?當A=1B=1時,我們不在乎它的值是0還是1。那你當然可以把它當成是0來做一個式子,你也可以用1來做另一個式子。那你也真的只是上面有1的結果來做你的式子。但不管哪一種,都會是你要的結果,都是不會錯的。因為會為1的等式必定成立。
上面的verilog 程式也是一樣的。如果這個don’t care是你真的想要的don’t care時,那模擬結果不同時,有差別嗎?答案是沒有;因為你已經把這個會發生的情形考慮清楚,做好所有的處理所以不會讓整個系統發生錯誤。
從上面的英文,都沒有描述到這樣子的做法會讓系統不穩定,或是合成時,會發生問題,以致於netlist是合錯的。
數位工程師最怕的模擬結果是mismatch,但是不是所有的mismatch都是錯誤。要從系統面和真值表中去了解設計的核心。不應該是怕mismatch,所以把所有的mismatch都是當成是錯誤的。這樣子的想法是不對的。

我再舉一個例子,請看下面的verilog的程式。

wire a;
reg [2:0] FSM, FSM_nxt;
always(posedge clki or negedge rstni)
begin
    if(~rstni)
        FSM <=3'b001;
    else
        FSM <= FSM_nxt;
end

always@(*)
begin
    case(FSM)
    3'b001:
        if(a)
            FSM_nxt = 3'b010;
        else
            FSM_nxt = FSM;
    3'b010:
        if(a)
            FSM_nxt = 3'b100;
        else
            FSM_nxt = FSM;
    3'b100:
        if(a)
            FSM_nxt = 3'b001;
        else
            FSM_nxt = FSM;
    default:
        FSM_nxt = 3'bxxx;
    endcase
end

同樣地,default都是有don’t care的描述,但是上面的don’t care並不會讓pre-post simulationpost-simulation產生 result mismatch的問題?原因你知道嗎?因為default 的情況並不會產生,因為FSM的路徑是001->010->100的循環,並不會到別的狀態(例如: 011,110,111,000…等等)。因為FSM不會到達don’t case的狀態,所以不會產生mismatch

那換另一個角度來思考,如果真的跑到don’t case的狀態,那又代表什麼?到目前為止,我遇到的都是表示你的這部份程式的timing violation產生。所以你應該再檢查一次你的synthesis的結果。或許你忽略了這部份的timing,亦或是你的synthesis constrain沒有設定正確,所以這部份的timing被忽視了。不管是哪一個情況,我們都知道don’t care是我們不想發生的情況,所以simulation看到xxx時,你可以很容易就警覺到問題,這對工程師是很有幫助的。

上述的英文讓我們了解到,如果你沒有把所有的情況考思清楚(有用的狀態沒有用的狀態),反而直觀地把所有沒有用的狀態都當成是don’t care時,這時會容易發生英文上所描述的事形發生,這時你就很容易被混淆,而誤會系統是不穩定的。

所以應該是,當你不知道要做什麼時,你不應該用don’t care的語法,因為這會讓你的系統發生你沒有預期的行為。而當你知道你真的是要用don’t care時,而你don’t care語法,這表示你已經考慮到所有的狀態,並讓系統清楚知道要做出什麼的反應和行為,此時,系統就不會發生任何錯誤。

別再為了mismatch而去反抗mismatch;真正去了解為什麼會mismatch,並清楚知道整個系統的運作,會讓你學到更多的事情。







2014年3月9日 星期日

FIFO是基本功


有很多剛出社會的工程師,被指派FIFO設計工作時,心裏面一定都會想,這個這麼簡單,有沒有更難的,我可不是來這邊做這種簡單的設計。我是來學更難的東西。

其實,一個基本功好的工程師,他的FIFO design也一定是很紮實。FIFO常被用來解決很多的問題,所以FIFO的設計也牽扯到很多的問題,例如:跨clock domain的處理?serialparallel問題?兩邊不同的Spec要怎麼溝通?兩個存取速度不同時,要怎麼溝通?這些問題看似不同,但是其實都是同一種的本質—FIFO兩邊的步調不同。既然核心問題只有一個,那解法不就是一種就可以了?那為什麼網路上FIFO的架構有那麼多?(當然,條條道路通羅馬。我不是表達這麼多種做法不對,而是所有的做法,其本質是只有一種。了解一種做法應該就夠了,其他的都是相似的道理。)

各位看官你可以細細看,這麼多不同架構的FIFO,大都是在探討一個問題,那就是訊號在跨clock domain的處理。如果你對跨clock domain訊號處理的觀念正確了,且了解你要解決的問題是什麼,也知道自己所處理的訊號是屬於哪一種的訊號(long-pulse signal or one-pulse signal)?是連續還是不連續的處理?這些如果你都有清楚知道的話,那麼我相信,你所設計出來的FIFO,相信一定可以解決你的需求。
從宏觀的角度來說,FIFO就好像是水管,而data就像是流水一樣。FIFO design像是設計水管的接法,直到出水口的速度和流量符合你想要的結果。設計水管時,我們所會遇到的問題是什麼?
1. 當水流又強又快時,你想放慢它,你會怎麼做?
2. 當水流又慢又多時,你想加快它,你會怎麼做?
第一題的做法應該是找更粗的水管慢慢地加大,直到你想要的流速及流量。第二題的做法應該是和第一題相反的做法。
FIFO的基本解法,也不外乎是這些做法。剩下來的就是實作經驗以及跨clock domain處理的觀念建立。

那麼FIFO可以用來解決哪些問題呢
FIFO可以用來解決兩邊不同interface不相容的問題。FIFO可以用來解決系統中write/read順序的問題(PCI ordering)FIFO可以用來解決producer&consumerwrite/read racing問題。FIFO可以用來做排程(scheduling)的處理。FIFO可以用來serialparallel,當然也可以parallelserialFIFO可以用來解決的問題這麼多。這樣子,你還會認為FIFO是簡單的設計嗎?

之前討論過,FIFO核心問題只有一個,當你了解到FIFO本質時,你就會知道怎麼做FIFO。很多人不了解跨clock domain和FIFO之間的本質,所以才會有很多種不同的想法、做法,甚至想要用reset來解決同步的問題。

其實認真處理跨clock domain訊號,認真設計一個實用的FIFO,將兩個合在一起,你就可以用這個架構一輩子。

2014年3月2日 星期日

gray code encode and decode(下)


上個星期提出如何將binday code 轉換成gray code。

今天就示範如何將gray code轉換成binary code. 

module gray2binary(
  gray
, bin
);

input [4:0] gray;
output [4:0] bin;

assign bin[4] = gray[4];
assign bin[3] = ^gray[4:3];
assign bin[2] = ^gray[4:2];
assign bin[1] = ^gray[4:1];
assign bin[0] = ^gray;

endmodule


有興趣的人可以試著推看看,是不是這樣子就可以將gray code還原成binary code. 

以上的gray code的encode和decode都是很簡單的做法。或許有些人已經知道原理,但是卻不知道怎麼做?亦或許已經有人都知道了。

不管怎麼樣,都希望能提供一個方法給大家參考! 如果有人的方法更好,歡迎大家來提出來討論。