官术网_书友最值得收藏!

1.1 可編程邏輯基本設計原則

可編程邏輯設計有許多內在規律可循,總結并掌握這些規律對于較深刻地理解可編程邏輯設計技術非常重要。本章從FPGA/CPLD的基本概念出發,總結出4個基本設計原則,這些指導原則范疇非常廣,希望讀者不僅僅是學習它們,更重要的是理解它們,并在今后的工作實踐中充實、完善它們。

(1)面積和速度的平衡與互換原則。提出了FPGA/CPLD設計的兩個基本目標,并探討了這兩個目標對立統一的矛盾關系。

(2)硬件原則。重點在于提醒讀者轉化軟件設計的思路,理解HDL語言設計的本質。

(3)系統原則。希望讀者能夠通過從全局、整體上把握設計,從而提高設計質量,優化設計效果。

(4)同步設計原則。設計時序穩定的基本要求,也是高速PLD設計的通用法則。

1.1.1 面積和速度的平衡與互換原則

這里的“面積”是指一個設計所消耗FPGA/CPLD的邏輯資源數量:對于FPGA,可以用所消耗的觸發器(FF)和查找表(LUT)來衡量;對于CPLD,常用宏單元(MC)衡量。用設計所占用的等價邏輯門數來衡量設計所消耗FPGA/CPLD的邏輯資源數量也是一種常見的衡量方式?!八俣取敝冈O計在芯片上穩定運行時所能夠達到的最高頻率,這個頻率由設計的時序狀況決定,與設計滿足的時鐘周期、PAD to PAD Time、Clock Setup Time、Clock Hold Time和Clock-to-Output Delay等眾多時序特征量密切相關。面積(Area)和速度(Speed)這兩個指標貫穿著FPGA/CPLD設計的始終,是設計質量評價的終極標準。這里我們就討論一下設計中關于面積和速度的基本原則:面積和速度的平衡與互換。

面積和速度是一對對立統一的矛盾體。要求一個設計同時具備設計面積最小,運行頻率最高,這是不現實的??茖W的設計目標應該是在滿足設計時序要求(包含對設計最高頻率的要求)的前提下,占用最小的芯片面積,或者在所規定的面積下,使設計的時序余量更大,頻率更高。這兩種目標充分體現了面積和速度的平衡思想。關于面積和速度的要求,我們不應該簡單地理解為工程師水平的提高和設計完美性的追求,而應該認識到它們是與產品的質量和成本直接相關的。如果設計的時序余量比較大,運行的頻率比較高,則意味著設計的健壯性更強,整個系統的質量更有保證;另一方面,設計所消耗的面積更小,則意味著在單位芯片上實現的功能模塊更多,需要的芯片數量更少,整個系統的成本也隨之大幅度削減。

作為矛盾的兩個組成部分,面積和速度的地位是不一樣的。相比之下,滿足時序、工作頻率的要求更重要一些,當兩者沖突時,采用速度優先的準則。

面積和速度的互換是FPGA/CPLD設計的一個重要思想。從理論上講,一個設計如果時序余量較大,所能跑的頻率遠遠高于設計要求,那么就能通過功能模塊復用減少整個設計消耗的芯片面積,這就是用速度的優勢換面積的節約;反之,如果一個設計的時序要求很高,普通方法達不到設計頻率,那么一般可以通過將數據流串并轉換,并行復制多個操作模塊,對整個設計采取“乒乓操作”和“串并轉換”的思想進行處理,在芯片輸出模塊處再對數據進行“并串轉換”。從宏觀上看,整個芯片滿足了處理速度的要求,這相當于用面積復制換取速度的提高。面積和速度互換的具體操作技巧很多,如“模塊復用”“乒乓操作”“串并轉換”等,需要大家在日后工作中不斷積累。下面舉例說明如何使用“速度換面積”和“面積換速度”。

【例1-1】如何使用“速度的優勢換取面積的節約”?

在WCDMA(寬帶碼分多址)系統中,使用到了快速哈達碼(FHT)運算,如圖1-1所示。

圖1-1 FHT原理圖

FHT的單步算法如下。

Out[2i]=In[2i]+In[2i+8];i=0-7;

Out[2i+1]=In[2i+1]-In[2i+1+8];i=0-7

考慮流水線式數據處理的要求,最自然的設計方法就是設計不同端口寬度的4個單步FHT,并將這4個單步模塊串聯起來,從而完成數據流的流水線處理。該FHT實現方式的代碼如下。

  //該模塊是FHT的頂層,調用4個不同端口寬度的單步FHT模塊,完成整個FHT算法
  module
fhtpart(Clk,Reset,FhtStarOne,FhtStarTwo,FhtStarThree,FhtStarFour,
             I0,I1,I2,I3,I4,I5,I6,I7,I8,
             I9,I10,I11,I12,I13,I14,I15,
             Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7,Out8,
             Out9,Out10,Out11,Out12,Out13,Out14,Out15);
  input Clk;    //設計的主時鐘
  input Reset;   //異步復位
  input FhtStarOne,FhtStarTwo,FhtStarThree,FhtStarFour; //4 個單步算法的時
序控制信號
  input [11:0] I0,I1,I2,I3,I4,I5,I6,I7,I8;
  input [11:0] I9,I10,I11,I12,I13,I14,I15;                //FHT的16個輸入
  output [15:0] Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7;
  output [15:0] Out8,Out9,Out10,Out11,Out12,Out13,Out14,Out15;  //FHT的
16個輸出
  
  //第1次FHT單步運算的輸出
  wire [12:0] m0,m1,m2,m3,m4,m5,m6,m7,m8,m9;
  wire [12:0] m10,m11,m12,m13,m14,m15;
  
  //第2次FHT單步運算的輸出
  wire [13:0] mm0,mm1,mm2,mm3,mm4,mm5,mm6,mm7,mm8,mm9;
  wire [13:0] mm10,mm11,mm12,mm13,mm14,mm15;
  
  //第3次FHT單步運算的輸出
  wire [14:0] mmm0,mmm1,mmm2,mmm3,mmm4,mmm5,mmm6,mmm7,mmm8,mmm9;
  wire [14:0] mmm10,mmm11,mmm12,mmm13,mmm14,mmm15;
  
  //第4次FHT單步運算的輸出
  wire [15:0] Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7,Out8,Out9;
  wire [15:0] Out10,Out11,Out12,Out13,Out14,Out15;
  //第1次FHT單步運算
  fht_unit1 fht_unit1(Clk,Reset,FhtStarOne,
             I0,I1,I2,I3,I4,I5,I6,I7,I8,
             I9,I10,I11,I12,I13,I14,I15,
             m0,m1,m2,m3,m4,m5,m6,m7,m8,
             m9,m10,m11,m12,m13,m14,m15
             );
  
  //第2次FHT單步運算
  fht_unit2 fht_unit2(Clk,Reset,FhtStarTwo,
             m0,m1,m2,m3,m4,m5,m6,m7,m8,
             m9,m10,m11,m12,m13,m14,m15,
             mm0,mm1,mm2,mm3,mm4,mm5,mm6,mm7,mm8,
             mm9,mm10,mm11,mm12,mm13,mm14,mm15
             );
  //第3次FHT單步運算
  fht_unit3 fht_unit3(Clk,Reset,FhtStarThree,
             mm0,mm1,mm2,mm3,mm4,mm5,mm6,mm7,mm8,
             mm9,mm10,mm11,mm12,mm13,mm14,mm15,
             mmm0,mmm1,mmm2,mmm3,mmm4,mmm5,mmm6,mmm7,mmm8,
             mmm9,mmm10,mmm11,mmm12,mmm13,mmm14,mmm15
             );
  //第4次FHT單步運算
  fht_unit4 fht_unit4(Clk,Reset,FhtStarFour,
             mmm0,mmm1,mmm2,mmm3,mmm4,mmm5,mmm6,mmm7,mmm8,
             mmm9,mmm10,mmm11,mmm12,mmm13,mmm14,mmm15,
             Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7,Out8,
             Out9,Out10,Out11,Out12,Out13,Out14,Out15
             );
  endmodule

單步FHT運算如下(僅僅舉例第4步的模塊)。

  module fht_unit4(Clk,Reset,FhtStar,
             In0,In1,In2,In3,In4,In5,In6,In7,In8,
             In9,In10,In11,In12,In13,In14,In15,
             Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7,Out8,
             Out9,Out10,Out11,Out12,Out13,Out14,Out15
             );
  
  input Clk;          //設計的主時鐘
  input Reset;       //異步復位
  input FhtStar;     //單步FHT運算控制信號
  input [14:0] In0,In1,In2,In3,In4,In5,In6,In7,In8,In9;
  input [14:0] In10,In11,In12,In13,In14,In15;           //單步FHT運算輸入
  output [15:0] Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7,Out8,Out9;
  output [15:0] Out10,Out11,Out12,Out13,Out14,Out15;  //單步FHT運算輸出
  
  //Single FHT calculation
  reg [15:0] Out0,Out1,Out2,Out3,Out4,Out5;
  reg [15:0] Out6,Out7,Out8,Out9,Out10,Out11;
  reg [15:0] Out12,Out13,Out14,Out15;
  //補碼運算
  wire [14:0] In8Co =~In8+1;
  wire [14:0] In9Co =~In9+1;
  wire [14:0] In10Co=~In10+1;
  wire [14:0] In11Co=~In11+1;
  wire [14:0] In12Co=~In12+1;
  wire [14:0] In13Co=~In13+1;
  wire [14:0] In14Co=~In14+1;
  wire [14:0] In15Co=~In15+1;
  
  always @(posedge Clk or negedge Reset)
  begin
    if(!Reset)
    begin
      Out0<=0;Out1<=0;Out2<=0;Out3<=0;
      Out4<=0;Out5<=0;Out6<=0;Out7<=0;
      Out8<=0;Out9<=0;Out10<=0;Out11<=0;
      Out12<=0;Out13<=0;Out14<=0;Out15<=0;
    end
    else
    begin
      if(FhtStar)
      begin
      Out0<={In0[14],In0 }+{In8[14],In8 };
      Out1<={In0[14],In0 }+{In8Co[14],In8Co };
      Out2<={In1[14],In1 }+{In9[14],In9 };
      Out3<={In1[14],In1 }+{In9Co[14],In9Co };
      Out4<={In2[14],In2 }+{In10[14],In10 };
      Out5<={In2[14],In2 }+{In10Co[14],In10Co };
      Out6<={In3[14],In3 }+{In11[14],In11 };
      Out7<={In3[14],In3 }+{In11Co[14],In11Co };
      Out8<={In4[14],In4 }+{In12[14],In12 };
      Out9<={In4[14],In4 }+{In12Co[14],In12Co };
      Out10<={In5[14],In5 }+{In13[14],In13 };
      Out11<={In5[14],In5 }+{In13Co[14],In13Co };
      Out12<={In6[14],In6 }+{In14[14],In14 };
      Out13<={In6[14],In6 }+{In14Co[14],In14Co };
      Out14<={In7[14],In7 }+{In15[14],In15 };
      Out15<={In7[14],In7 }+{In15Co[14],In15Co };
      end
    end
  end
  endmodule

評估一下系統的流水線時間余量后,發現整個流水線有16個時鐘周期,而FHT模塊的頻率很高,加法本身僅僅消耗1個時鐘周期,加上數據的選擇和分配所消耗的時間,也完全能滿足系統頻率要求,所以將單步FHT運算復用4次,就能大幅度節約所消耗的資源。這種復用單步算法的FHT實現框圖如圖1-2所示。它由輸入選擇寄存、單步FHT運算模塊、輸出選擇寄存和計數器構成。

圖1-2 FHT運算復用結構圖

代碼如下。

  //復用單步算法的FHT運算模塊
  module wch_fht(Clk,Reset,
             PreFhtStar,
             In0,In1,In2,In3,In4,In5,In6,In7,
             In8,In9,In10,In11,In12,In13,In14,In15,
             Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7,Out8,
             Out9,Out10,Out11,Out12,Out13,Out14,Out15
             );
  input Clk;            //設計的主時鐘
  input Reset;         //異步復位信號
  input PreFhtStar;   //FHT運算指示信號,和上級模塊運算關聯
  input [11:0] In0,In1,In2,In3,In4,In5,In6,In7;
  input [11:0] In8,In9,In10,In11,In12,In13,In14,In15;    //FHT的16個輸入
  output [15:0] Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7;
  output [15:0] Out8,Out9,Out10,Out11,Out12,Out13,Out14,Out15; //FHT的
16個輸出
  
  //FHT輸出寄存信號
  reg [15:0] Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7;
  reg [15:0] Out8,Out9,Out10,Out11,Out12,Out13,Out14,Out15;
  //FHT的中間結果
  wire [15:0] Temp0,Temp1,Temp2,Temp3,Temp4,Temp5,Temp6,Temp7;
  wire [15:0] Temp8,Temp9,Temp10,Temp11,Temp12,Temp13,Temp14,Temp15;
  
  //FHT運算控制計數器,和前一級流水線模塊配合
  reg [2:0] Cnt3;//count from 0 to 4,when Reset Cnt3=7;
  reg FhtEn;//Enable fht culculate
  
  always @(posedge Clk or negedge Reset)
  begin
     if (!Reset)
        Cnt3<= #1 3'b111;
     else
     begin
         if(PreFhtStar)
         Cnt3<= #1 3'b100;
         else
         Cnt3<= #1 Cnt3-1;
     end
  end
  always @(posedge Clk or negedge Reset)
  if (!Reset)
     FhtEn<= #1 0;
  else
  begin
       if (PreFhtStar)
       FhtEn<= #1 1;
       if  (Cnt3==1)
       FhtEn<= #1 0;
  end
  
  //補碼運算,復制符號位
          assign Temp0=(Cnt3==4)?{4{In0[11]},In0}:Out0;
          assign Temp1=(Cnt3==4)?{4{In1[11]},In1}:Out1;
          assign Temp2=(Cnt3==4)?{4{In2[11]},In2}:Out2;
          assign Temp3=(Cnt3==4)?{4{In3[11]},In3}:Out3;
          assign Temp4=(Cnt3==4)?{4{In4[11]},In4}:Out4;
          assign Temp5=(Cnt3==4)?{4{In5[11]},In5}:Out5;
          assign Temp6=(Cnt3==4)?{4{In6[11]},In6}:Out6;
          assign Temp7=(Cnt3==4)?{4{In7[11]},In7}:Out7;
          assign Temp8=(Cnt3==4)?{4{In8[11]},In8}:Out8;
          assign Temp9=(Cnt3==4)?{4{In9[11]},In9}:Out9;
          assign Temp10=(Cnt3==4)?{4{In10[11]},In10}:Out10;
          assign Temp11=(Cnt3==4)?{4{In11[11]},In11}:Out11;
          assign Temp12=(Cnt3==4)?{4{In12[11]},In12}:Out12;
          assign Temp13=(Cnt3==4)?{4{In13[11]},In13}:Out13;
          assign Temp14=(Cnt3==4)?{4{In14[11]},In14}:Out14;
          assign Temp15=(Cnt3==4)?{4{In15[11]},In15}:Out15;
  
  always @(posedge Clk or negedge Reset)
  begin
  if (!Reset)
  begin
      Out0<=0;Out1<=0;Out2<=0;Out3<=0;
      Out4<=0;Out5<=0;Out6<=0;Out7<=0;
      Out8<=0;Out9<=0;Out10<=0;Out11<=0;
      Out12<=0;Out13<=0;Out14<=0;Out15<=0;
  end
  else
  begin
    if ((Cnt3<=4) && Cnt3>=0 && FhtEn)
      begin
      Out0[15:0]<= #1 Temp0[15:0]+Temp8[15:0];
      Out1[15:0]<= #1 Temp0[15:0]-Temp8[15:0];
      Out2[15:0]<= #1 Temp1[15:0]+Temp9[15:0];
      Out3[15:0]<= #1 Temp1[15:0]-Temp9[15:0];
      Out4[15:0]<= #1 Temp2[15:0]+Temp10[15:0];
      Out5[15:0]<= #1 Temp2[15:0]-Temp10[15:0];
      Out6[15:0]<= #1 Temp3[15:0]+Temp11[15:0];
      Out7[15:0]<= #1 Temp3[15:0]-Temp11[15:0];
      Out8[15:0]<= #1 Temp4[15:0]+Temp12[15:0];
      Out9[15:0]<= #1 Temp4[15:0]-Temp12[15:0];
      Out10[15:0]<= #1 Temp5[15:0]+Temp13[15:0];
      Out11[15:0]<= #1 Temp5[15:0]-Temp13[15:0];
      Out12[15:0]<= #1 Temp6[15:0]+Temp14[15:0];
      Out13[15:0]<= #1 Temp6[15:0]-Temp14[15:0];
      Out14[15:0]<= #1 Temp7[15:0]+Temp15[15:0];
      Out15[15:0]<= #1 Temp7[15:0]-Temp15[15:0];
      end
  
  end
  end
  endmodule

為了便于對比兩種實現方式的資源消耗,在Synplify Pro中對兩種實現方法分別做了綜合。兩次綜合選用的參數完全一致,出于僅僅考察設計所消耗的寄存器和邏輯資源,Enable“Disable I/O Insertion”選項,不插入IO,取消Synplify Pro中諸如“FSM Compiler”“FSM Explorer”“Resource Sharing”“Retiming”“Pipelining”等綜合優化選項。兩次綜合的結果如圖1-3和圖1-4所示。

圖1-3 未采用復用方案的“fhtpart”模塊綜合所消耗的資源

圖1-4 采用復用方案的“wch_fht”模塊綜合所消耗的資源

通過對比可以清晰地觀察到,采用復用實現方案所占面積約為原方案的1/4,而得到這個好處的代價是,完成整個FHT運算的周期為原來的4倍。這個例子通過運算周期的加長,換取了消耗芯片面積的減少,是前面所述的用頻率換面積的一種體現。本例所述“頻率換面積”的前提是FHT模塊頻率較高,運算周期的余量較大,采用4步復用后,仍然能夠滿足系統流水線設計的要求。如果流水線時序允許,FHT運算甚至可以采用1bit全串行方案實現,該方案所消耗的芯片面積資源更少。

【例1-2】如何使用“面積復制換速度提高”?

舉一個路由器設計的例子。假設輸入數據流的速率是450Mbit/s,而FPGA上設計的數據處理模塊的處理速度最大為150Mbit/s,由于處理模塊的數據吞吐量滿足不了要求,看來直接在FPGA上實現是一個“不可能完成的任務”。這種情況下,就應該利用“面積換速度”的思想,至少復制3個處理模塊,首先將輸入數據進行串并轉換,然后利用這3個模塊并行處理分配的數據,最后將處理結果“并串轉換”,完成數據速率的要求。我們在整個處理模塊的兩端看,數據速率是450Mbit/s,而在FPGA的內部看,每個子模塊處理的數據速率是150Mbit/s,其實整個數據的吞吐量的保障是依賴于3個子模塊并行處理完成的,也就是說利用占用更多的芯片面積,實現了高速處理,通過“面積的復制換取處理速度的提高”的思想實現了設計。設計的示意框圖如圖1-5所示。

圖1-5 “面積換速度”示意圖

上面僅僅是對“面積換速度”思想的一個簡單的舉例,其實具體操作過程中還涉及很多的方法和技巧,例如,對高速數據流進行串并轉換,采用“乒乓操作”方法提高數據處理速率等,希望讀者通過平時的應用進一步積累。

1.1.2 硬件原則

硬件原則主要針對HDL代碼編寫而言。首先應該明確FPGA/CPLD、ASIC的邏輯設計所采用的硬件描述語言(HDL)同軟件語言(如C、C++等)是有本質區別的。以Verilog語言為例,雖然Verilog很多語法規則和C語言相似,但是Verilog作為硬件描述語言,它的本質作用在于描述硬件。應該認識到Verilog是采用了C語言形式的硬件的抽象,它的最終實現結果是芯片內部的實際電路,所以評判一段HDL代碼的優劣的最終標準是其描述并實現的硬件電路的性能(包括面積和速度兩個方面)。評價一個設計的代碼水平較高,僅僅是說這個設計由硬件向HDL代碼這種表現形式轉換得更流暢、合理。而一個設計的最終性能,在更大程度上取決于設計工程師所構想的硬件實現方案的效率及合理性。

初學者,特別是由軟件轉行的初學者,片面追求代碼的整潔、簡短,這是錯誤的,是與評價HDL的標準背道而馳的。正確的編碼方法是,首先要做到對所需實現的硬件電路“胸有成竹”,對該部分硬件的結構與連接十分清楚,然后用適當的HDL語句表達出來即可。

硬件原則的另外一個重要理解是“并行”和“串行”的概念。大家知道,一般來說硬件系統比軟件系統速度快、實時性高,其中一個重要原因就是硬件系統中各個單元的運算是獨立的,信號流是并行的。而C語言編譯后,其機器指令在CPU的高速緩沖隊列中基本是順序執行的,即使有一些并行處理的技術,在一定程度上也是十分有限的。所以在寫HDL代碼的時候,應該充分理解硬件系統的并行處理特點,合理安排數據流的時序,提高整個設計的效率。

另外,Verilog作為一種HDL語言,對系統行為的建模方式是分層次的。比較重要的層次有系統(System)級、算法(Algorithm)級、寄存器傳輸(RTL)級、邏輯(Logic)級、門(Gate)級和電路開關(Switch)級等。系統級和算法級與C語言更相似,可用的語法和表現形式也更豐富。自RTL級以后,HDL語言的功能就越來越側重于硬件電路的描述,可用的語法和表現形式的局限性也越大。相比之下,C語言與系統級和算法級Verilog描述更相近一些,而與RTL級、Gate級、Switch級描述從描述目標和表現形式上都有較大的差異。

【例1-3】舉例說明RTL級Verilog描述語法和C語言描述語法的區別。

在C語言的描述中,為了使代碼執行效率高,表述簡潔,經常用到下面的for循環語句。

  for (i=0; i<16; i++)
      DoSomething();

在實際工作中,除了描述仿真測試激勵(Testbench)時使用for循環語句外,極少在RTL級編碼中使用for循環。其原因是for循環會被綜合器展開為所有變量情況的執行語句,每個變量獨立占用寄存器資源,每條執行語句并不能有效地復用硬件邏輯資源,造成巨大的資源浪費。在RTL硬件描述中,遇到類似算法,推薦的方式是先搞清楚設計的時序要求,做一個reg型計數器。在每個時鐘沿累加,并在每個時鐘沿判斷計數器情況,做相應的處理,能復用的處理模塊盡量復用,即使所有操作都不能復用,也采用case語句展開處理。代碼如下。

  reg [3:0] counter;
  always @ (posedge clk)
  if (syn_rst)
      counter <= 4'b0;
  else
      counter <= counter+1;
  always @ (posedge clk)
      begin
           case (counter)
                 4'b0000:
                 4'b0001:
                 ...    ...
                 default:
           endcase
      end

另外,在C語句描述中有if…else和switch條件判斷語句,其語法如下。

  if (flag)  // 表示flag為真
  …
  else
  …

switch語句的基本格式如下。

  switch (variable)
  {
  case value1 :   …
  break;
  case value2 :   …
  break;
   …
   default :   …
  break;
  }

兩者之間的區別主要在于switch是多分支選擇語句,而if語句只有兩個分支可供選擇。雖然可以用嵌套的if語句來實現多分支選擇,但那樣的程序冗長難讀。

對應Verilog也有if…else語句和case語句,if語句的語法與C語言相似,case語句的語法如下。

  case (var)
        var_value1:
        var_value1:
        ...    ...
        default:
  endcase

姑且不論casex和casez的作用(這兩個語句的應用一定要小心,要注意是否可綜合),case語句和if…else嵌套描述結構就有很大的區別。在Verilog語法中,if…else if…else語句是有優先級的,一般來說第一個if的優先級最高,最后一個else的優先級最低。如果描述一個編碼器,在有些綜合器的參數中就有關于優先級編碼器硬件原語的選項Priority Encoder Extraction。而case語句是“平行”的結構,所有的case的條件和執行都沒有“優先級”。而建立優先級結構(優先級樹)會消耗大量的組合邏輯,所以能夠使用case語句的地方盡量用case替換if...else結構。

關于這點簡單地引申兩點:第一,也可以用if...;if…;的結構描述出不帶優先級的“平行”條件判斷語;第二,隨著現在綜合工具的優化能力越來越強,大多數情況下可以將不必要的優先級樹優化掉。關于if和case語句的更詳細的闡釋,見后面關于Coding Style的討論。

1.1.3 系統原則

系統原則包含兩個層次的含義:從更高層面上看,是一個硬件系統,一塊單板如何進行模塊劃分與任務分配,什么樣的算法和功能適合放在傳統FPGA里面實現,什么樣的算法和功能適合放在DSP、CPU里面實現,或者在使用內嵌CPU和DSP Block的FPGA中如何劃分軟硬件功能,以及FPGA的規模估算數據接口設計等;具體到FPGA設計,就要求對設計的全局有個宏觀上的合理安排,比如時鐘域、模塊復用、約束、面積和速度等問題。要知道在系統上復用模塊節省的面積遠比在代碼上“小打小鬧”來的實惠多。

一般來說,實時性要求高、頻率快的功能模塊適合使用FPGA/CPLD實現。而FPGA和CPLD相比,更適合實現規模較大、頻率較高、寄存器資源使用較多的設計。使用FPGA/CPLD設計時,應該對芯片內部的各種底層硬件資源和可用的設計資源有一個較深刻的認識。比如FPGA一般觸發器資源比較豐富,而CPLD組合邏輯資源更豐富一些,這一點直接影響著兩者使用的編碼風格。

FPGA基本由可編程輸入/輸出單元、基本可編程邏輯單元、嵌入式塊RAM、豐富的布線資源、底層嵌入功能單元和內嵌專用硬核6部分組成。CPLD的結構相對比較簡單,主要由可編程I/O單元、基本邏輯單元、布線池和其他輔助功能模塊構成。把握系統原則就要求設計者根據設計類型與資源評估合理地完成器件選型,然后充分發揮所選器件的各個部分的最大性能,對器件整體上有個優化的組合與配置方案。

(1)存儲器資源的使用。

存儲器資源使用的基本原則是根據設計中用到多少RAM或ROM,確定所選器件的嵌入式Block RAM的容量,并合理配置每塊RAM的深度和寬度。特別值得一提的是,Altera的基于20nm工藝的Arria10 器件和基于28nm工藝的高端器件StratixV包含MLAB(640bit)和M20K(20kbit)RAM結構,而基于28nm工藝的中低端器件ArriaV和CycloneV包含MLAB(640bit)和M10K(10kbit)RAM結構。其中,MLAB適合做一些靈活的小塊Buffer、FIFO、DPRAM、SPRAM、ROM等;M20K/M10K適用于一般的需求和做大塊數據的緩沖區,如在通信的SDH/SONET傳輸領域,有一些900kbit的大數據包,用M20K/M10K實現其緩沖結構非常方便。不同大小的RAM結構靈活配置,不僅方便了用戶,并可以達到最佳的Block RAM利用效率。對于Xilinx和Lattice器件的RAM應用,除了需要掌握其Block RAM的結構,還需注意Xilinx和Lattice FPGA中的LUT可以靈活配置成小的RAM、ROM、FIFO等存儲結構,這種技術被稱為分布式RAM(Distributed RAM),分布式RAM在實現多塊、小容量存儲結構時有一定的優勢。

(2)硬核的使用。

《Intel FPGA/CPLD設計(基礎篇)》第1章中提到未來FPGA的一個發展趨勢是越來越多的FPGA產品將包含DSP或CPU等處理核,FPGA將由傳統的硬件設計手段逐步過渡為系統級設計工具。例如,當前Altera的StratixV、ArriaV、CycloneV、Arria10等器件族內部集成了DSP Core,而且ArriaV SX系列和Arria10還集成了雙核ARM CortexA9處理器。這就為系統設計和單板設計提供了新的解決方案,傳統的軟硬件聯合設計方案中軟件部分在某些適當的情況下可以使用內嵌DSP和CPU Block的FPGA取代通用DSP和FPGA,從而簡化了單板設計難點,節約了單板面積,提高了單板可靠性。

必須強調的是,目前這類內嵌在FPGA之中的DSP或CPU處理模塊的硬件主要由一些加、乘、快速進位鏈、Pipelining、Mux等結構組成,加上用邏輯資源和塊RAM實現的軟核部分并不具備傳統DSP和CPU的各種譯碼機制、復雜的通信總線、靈活的中斷和調度機制等硬件結構,所以還不是真正意義上的DSP或CPU。在對這類DSP或CPU Block應用時應該注意其結構特點,揚長避短,注意選擇合適的應用場合。這種DSP或CPU Block比較適合應用于運算密集的FIR濾波器、編碼解碼、FFT(快速傅立葉變換)等操作。對于某些應用,通過在FPGA內部實現多個DSP或CPU運算單元并行運算,其工作效率可以達到傳統DSP和CPU的幾百倍。

FPGA內部嵌入CPU或DSP等處理器,使FPGA在一定程度上具備了實現軟硬件聯合系統的能力,FPGA正逐步成為SOPC(System On Programmable Chip)的高效設計平臺。

(3)串行收發器的使用。

很多高端FPGA內嵌了SERDES以完成高速串行信號的收發。SERDES是SERializer和DESerializer的英文縮寫,即串行收發器,顧名思義,它由兩部分構成:發端是串行發送單元SERializer,用高速時鐘調制編碼數據流;接收端為串行接收單元DESerializer,其主要作用是從數據流中恢復出時鐘信號,并解調還原數據,根據其功能,接收單元還有一個名稱叫時鐘數據恢復器(CDR,Clock and Data Recovery)。

目前三大FPGA生產商Altera、Xilinx、Lattice的高端FPGA產品都包含有高速串行收發器的硬核,提供高達3Gbit/s的傳輸速率,并提供易于使用的設計軟件和IP核,使高速傳輸電路的設計變得簡便、可靠。當前Altera Arria10器件含有豐富的serdes硬核資源,片到片連接可以支持到28.03Gbit/s,而過背板連接可以支持到17.4Gbit/s。

SERDES技術的應用很好地解決了高速系統數據傳輸的瓶頸,節約了單板面積,提高了系統的穩定性,是高速系統設計的強有力支撐。SERDES在高速系統中的應用請參考后面章節“SERDES與高速系統設計”的論述。

(4)其他結構的使用。

其他常用結構的使用大家應該都非常熟悉了,在此僅簡單介紹。對于可編程I/O資源,需要根據系統要求合理配置。通常選擇I/O的標準有功耗、傳輸距離、抗干擾性和EMI等。根據設計的速度要求,要合理選擇器件的速度等級,并在設計中正確地分頻不同速度等級的布線資源與時鐘資源。需要提醒讀者的是,選擇高等級的器件和改善布線資源分配僅僅是提高芯片工作速度的輔助手段,設計速度主要由電路的整體結構、代碼的Coding Style等因素決定。善用芯片內部的PLL或DLL資源完成時鐘的分頻、倍頻、移相等操作不僅簡化了設計,并且能有效地提高系統的精度和工作穩定性。

《Intel FPGA/CPLD設計(基礎篇)》第1章介紹了完整的FPGA/CPLD通用設計流程,這里我們強調一下FPGA系統的規劃流程,FPGA系統規劃的簡化流程如圖1-6所示。

圖1-6 系統規劃的簡化流程

對設計整體意義上的模塊復用應該在系統功能定義后就初步考慮,并對模塊的劃分起指導性作用。模塊劃分非常重要,除了關系到是否最大程度上發揮項目成員的協同設計能力,而且直接決定著設計的綜合、實現效果和相關的操作時間,模塊劃分的具體方法請參考本章1.3節“Altera推薦的Coding Style”中關于模塊劃分技巧的論述。

對于系統原則做一點引申,簡單談談模塊化設計方法。模塊化設計是系統原則的一個很好的體現,它不僅僅是一種設計工具,它更是一種設計思路、設計方法,它是由頂向下、模塊劃分、分工協作設計思路的集中體現,是當代大型復雜系統的推薦設計方法。目前很多的EDA廠商都提高了模塊化設計工具,如Altera Quartus II內嵌的LogicLock,Xilinx ISE的Modular Design工具等。通過這類工具劃分每個模塊的設計區域,然后單獨設計和優化每個模塊,最后將每個模塊融合到頂層設計中,從而實現了團隊協作、并行設計的模塊化設計方法。LogicLock支持模塊化設計流程、增量設計流程和團隊設計流程等設計方法。合理地使用這些方法,能在最大程度上繼承以往設計成果,并行分工協作,有效利用開發資源,縮短開發周期。

【例1-4】在系統層次復用模塊。

有些文章介紹利用“可編程匹配濾波器”實現WCDMA基站的方案,其核心是在合理規劃系統的基礎上,合理劃分模塊并安排操作時序,提高單元模塊的復用率,從而大大降低硬件消耗,其設計思想是系統原則的集中體現??删幊唐ヅ錇V波器原理框圖如圖1-7所示。

圖1-7 可編程匹配濾波器原理框圖

其設計思想是:利用信道固有特點(如信道pilot導頻、信道結構等),應用現代可編程數字信號處理的技術(如DSP、FPGA等),采取反饋與控制匹配濾波方式,實現對某信道的已擴信息的自動解擴、解擾。該可編程MF的主要組成部分為本地碼發生器、可編程信號MF(S MF)、幀匹配濾波器(FRAME MF)和控制器。本地碼發生器可生成各種所需的擴頻、加擾序列,可接收控制器的指示脈沖,產生規定的本地解擴、解擾序列,作為S MF的參考序列;S MF是完成匹配濾波的主體,可接收控制器的指示脈沖,將自己的匹配狀態切換到下一匹配狀態;F MF完成對導頻信號等特殊信號(信息比特待選集有限)的檢測,生成指示相關峰,通知控制器將S MF切換到下一匹配狀態;控制器統一協調各部分工作。這種可編程濾波器可以在如越區切換、同步、CPCH收發信機等多方面應用,如果適當安排時序流程,可以在較大程度上節約硬件資源。

1.1.4 同步設計原則

同步時序設計是FPGA/CPLD設計的重要原則之一。本節在闡述為什么在PLD設計中要采用同步時序設計的基礎上重點論述同步時序設計的要點。

一、異步時序設計與同步時序設計

簡單比較一下異步電路和同步電路的異同。

(1)異步電路。

?電路的核心邏輯用組合電路實現,比如異步的FIFO/RAM讀寫信號、地址譯碼等電路。

?電路的主要信號、輸出信號等并不依賴于任何一個時鐘性信號,不是由時鐘信號驅動FF產生的。

?異步時序電路的最大缺點是容易產生毛刺,在布局布線后仿真和用高分辨率邏輯分析儀觀測實際信號時,這種毛刺尤其明顯。

?不利于器件移植,這包括器件族之間的移植和從FPGA向結構化ASIC的移植。

?不利于靜態時序分析(STA)、驗證設計時序性能。

(2)同步時序電路。

?電路的核心邏輯用各種各樣的觸發器實現。

?電路的主要信號、輸出信號等都是由某個時鐘沿驅動觸發器產生的。

?同步時序電路可以很好地避免毛刺,布局布線后仿真和用高速邏輯分析儀采樣實際工作信號皆無毛刺。

?利于器件移植,這包括器件族之間的移植和從FPGA向結構化ASIC的移植。

?有利于靜態時序分析(STA)、驗證設計時序性能。

早期PLD設計經常使用行波計數器(Ripple Counters)或異步脈沖生成器等典型的異步邏輯設計方式以節約設計所消耗的面積資源。異步邏輯設計的時序正確性完全依賴于每個邏輯元件和布線的延遲,所以其時序約束相對繁雜而困難,并且極易產生亞穩態、毛刺等,造成設計穩定性下降和設計頻率不高。我們在《Intel FPGA/CPLD設計(基礎篇)》中提到,今后FPGA/CPLD的一個顯著發展趨勢是低成本器件大行其道,隨著FPGA/CPLD的不斷經濟化,器件資源已經不再成為設計的主要矛盾,而同步時序電路對全面提高設計的頻率和穩定性至關重要,從這個層面上講,盡量使用同步時序電路更加重要。

另一方面,隨著FPGA/CPLD的邏輯規模不斷擴大,在FPGA/CPLD中完成復雜且質量優良的異步時序設計過于費時費力,其所需調整的時序路徑和需要附加的相關約束相當繁瑣,異步時序方法是和可編程設計理念背道而馳的。

隨著EDA工具的發展,大規模設計的綜合、實現的優化效果越來越強。目前大多數綜合、實現等EDA工具都是基于時序驅動(Timing Driven)優化策略的。異步時序電路增加了時序分析的難度,需要確定最佳時序路徑所需的計算量超出想像,所需時序約束相當繁瑣,而且對于異步電路來說,很多綜合、實現工具的編譯會帶來歧義。而對于同步時序設計則恰恰相反,其時序路徑清晰,相關時序約束簡單明了,綜合、實現優化容易,布局布線計算量小。所以目前的可編程邏輯的EDA工具都推薦使用同步時序設計。

綜上所述,現代PLD設計推薦采用同步時序設計方式。

二、同步時序設計的注意事項

同步時序設計的基本原則是使用時鐘沿觸發所有的操作。如果所有寄存器的時序要求(Setup、Hold時間等指標)都能夠滿足,則同步時序設計與異步時序設計相比,在不同的PVT條件下能獲得更佳的系統穩定性與可靠性。

同步設計中,穩定可靠的數據采樣必須遵從以下兩個基本原則。

?在有效時鐘沿到達前,數據輸入至少已經穩定了采樣寄存器的Setup時間之久,這條原則簡稱滿足Setup時間原則。

?在有效時鐘沿到達后,數據輸入至少還將穩定保持采樣寄存器的Hold時間之久,這條原則簡稱滿足Hold時間原則。

同步時序設計有以下幾個注意事項。

?異步時鐘域的數據轉換。詳見本章1.2.4小節“異步時鐘域數據同步”。

?組合邏輯電路的設計方法。詳見本章1.3.4小節“組合邏輯的注意事項”。

?同步時序電路的時鐘設計。詳見本章1.3.5小節“時鐘設計的注意事項”。

?同步時序電路的延遲。同步時序設計中電路延遲最常用的設計方法是用分頻或倍頻的時鐘或同步計數器完成所需延遲。換句話說,同步時序電路的延時被當作一個電路邏輯來設計。對于比較大的和特殊定時要求的延時,一般用高速時鐘產生一個計數器,根據計數器的計數,控制延時;對于比較小的延時,可以用D觸發器打一下,這種做法不僅僅使信號延時了一個時鐘周期,而且完成了信號與時鐘的初次同步,在輸入信號采樣和增加時序約束余量中使用。另外許多初學者用行為級(Behavioral Level)方法描述延時,如“#5 a<=4'b0101;”這種行為級描述方法常用于仿真測試激勵,但是在電路綜合時會被忽略,并不能起到延時作用。

?Verilog定義為reg型,不一定綜合成寄存器。這點主要是針對一些Verilog初學者而言的,在Verilog代碼中最常用的兩種數據類型是wire和reg,一般來說,wire型指定的數據和網線通過組合邏輯實現,而reg型指定的數據不一定就是用寄存器實現的。下面的例子就是一個純組合邏輯的譯碼器。請大家注意,代碼中將輸出信號Dout定義為reg型,但是綜合與實現結果卻沒有使用FF,這個電路是一個純組合邏輯設計。

  module reg_cmb(Reset,
                 CS,
                 Din,
                 Addr,
                 Dout);
  input Reset;           //Asynchronous reset
  input CS;              //Chip select, low effect
  input [7:0] Din;     //Data in
  input [1:0] Addr;    //Address
  output [1:0] Dout;   //Data out
  reg [1:0] Dout;
  always @(Reset or CS or Addr or Din )
  if (Reset)
       Dout = 0;
   else if (!CS)
       begin
            case (Addr)
                  2'b00: Dout = Din[1:0];
                  2'b01: Dout = Din[3:2];
                  2'b10: Dout = Din[5:4];
                default: Dout = Din[7:6];
            endcase
       end
  else
       Dout = 2'bzz;
  endmodule
主站蜘蛛池模板: 察雅县| 铜山县| 神池县| 淮南市| 广灵县| 清新县| 美姑县| 汝州市| 化德县| 进贤县| 来宾市| 都江堰市| 灵丘县| 阿图什市| 师宗县| 德钦县| 湘潭市| 龙南县| 准格尔旗| 南阳市| 乌兰浩特市| 舒城县| 玛沁县| 尼勒克县| 仁寿县| 虞城县| 祁连县| 绥阳县| 西乌珠穆沁旗| 越西县| 晋州市| 弋阳县| 正阳县| 偏关县| 当涂县| 汶川县| 台中县| 蚌埠市| 滨海县| 青州市| 祁东县|