[文檔].艾米電子 – 編碼器與解碼器,Verilog

來源:互聯網
上載者:User
文章目錄
  • 1 編碼器
  •  
  •  
  • 2 解碼器
  • 3 碼型轉換器
  • 4 小結
對讀者的假設

已經掌握:

  • 可程式化邏輯基礎
  • Verilog HDL基礎
  • 使用Verilog設計的Quartus II入門指南
  • 使用Verilog設計的ModelSIm入門指南
 內容1 編碼器1.1 二進位編碼器

二進位編碼器,即把來自2^n條輸入線路的資訊,編碼轉換成二進位碼。其輸入為獨熱碼,輸出為二進位碼。此處以4~2編碼器為例。

 

表1 4~2編碼器的真值表

 

代碼1.1.1 使用case語句描述的4~2編碼器(可綜合)

module encoder(  input      [3:0] iA,  output reg [1:0] oQ);always @ (*)  case(iA)    4'b0001 : oQ = 2'b00;    4'b0010 : oQ = 2'b01;    4'b0100 : oQ = 2'b10;    4'b1000 : oQ = 2'b11;    default : oQ = 2'b00;  endcaseendmodule

 

由於輸入的選項並沒有優先順序,因此第6~7行,採用case語句來描述編碼器。如前文所述,對於不完全的case選項,為了避免前後模擬不一致及鎖存器的產生,第12行加入了deflaut語句賦初值。實際上在這種情況下,在敏感列表之後賦初值的效果是一樣的。

 

always @ (*)  case(iA)    4'b0001 : oQ = 2'b00;    4'b0010 : oQ = 2'b01;    4'b0100 : oQ = 2'b10;    4'b1000 : oQ = 2'b11;    default : oQ = 2'b00;  endcase
 

圖1.1.1 4~2編碼器的RTL視圖

 

代碼1.1.2 4~2編碼器的testbench(不可綜合,僅用於模擬)

`timescale 1ns/1nsmodule encoder_tb;reg [3:0] i_a;wire [1:0] o_q;initialbegin  i_a = 4'b0000;  #20 i_a = 4'b0001;  #20 i_a = 4'b0010;  #20 i_a = 4'b0100;  #20 i_a = 4'b1000;  #20 $stop;end   encoder encoder_inst(  .iA(i_a),  .oQ(o_q));    endmodule

 

圖1.1.2 使用case語句描述的4~2編碼器的功能模擬波形

 

1.2 優先編碼器

如表2所示,優先順序分別為:i3 > i2 > i1 > i0;對於這種有優先順序的編碼器,我們可以採用casez語句來描述。

 

表2.1 4~2優先編碼器的真值表

 

代碼1.2.1 使用case語句描述的4~2優先編碼器(可綜合)

module encoder(  input      [3:0] iA,  output reg [1:0] oQ);always @ (*)  casez(iA)    4'b0001 : oQ = 2'b00;    4'b001? : oQ = 2'b01;    4'b01?? : oQ = 2'b10;    4'b1??? : oQ = 2'b11;    default : oQ = 2'b00;  endcaseendmodule

 

第6~13行,採用casez來描述優先編碼器。注意:對於無關項輸入的描述,使用“?”描述優於使用“x”,詳情見參考1;在可綜合的代碼中,不要使用casex。

always @ (*)  casez(iA)    4'b0001 : oQ = 2'b00;    4'b001? : oQ = 2'b01;    4'b01?? : oQ = 2'b10;    4'b1??? : oQ = 2'b11;    default : oQ = 2'b00;  endcase

圖1.2.1 使用case語句描述的4~2優先編碼器RTL視圖

 

代碼1.2.2 使用if-else-if語句描述的4~2優先編碼器(可綜合)

module encoder(  input      [3:0] iA,  output reg [1:0] oQ);always @ (*)  if (iA[3])    oQ = 2'b11;  else if (iA[2])    oQ = 2'b10;  else if (iA[1])    oQ = 2'b01;  else if (iA[0])    oQ = 2'b00;  else    oQ = 2'b00;    endmodule

 

對於帶優先順序的電路,使用if-else-if來描述,應該是輕而易舉事情。注意:優先順序高的,放在前面描述;else不要丟。

always @ (*)  if (iA[3])    oQ = 2'b11;  else if (iA[2])    oQ = 2'b10;  else if (iA[1])    oQ = 2'b01;  else if (iA[0])    oQ = 2'b00;  else    oQ = 2'b00;

 

圖1.2.2 使用if-else-if語句描述的4~2優先編碼器

 

代碼1.2.3 4~2優先編碼器的testbench(不可綜合,僅用於模擬)

`timescale 1ns/1nsmodule encoder_tb;reg [3:0] i_a;wire [1:0] o_q;initialbegin  i_a = 4'b0;  forever  begin    if (i_a<16)      #20 i_a <= i_a + 1'b1;    else      #20 i_a <= 4'b0;  endendinitial #330 $stop;    encoder encoder_inst(  .iA(i_a),  .oQ(o_q));    endmodule

圖1.2.3 使用case語句描述的4~2優先編碼器的功能模擬波形

 

圖1.2.4 使用if-else-if語句描述的4~2優先編碼器的功能模擬波形

 

圖1.2.3和圖1.2.4的波形一致,說明兩種描述方式雖然RTL視圖有所不同,但其功能上是一致的。

 2 解碼器

解碼器剛好與編碼器相反,即輸入二進位碼,輸出獨熱碼。此處以2~4解碼器為例。

 

代碼2.1 使用case語句描述的解碼器(可綜合)

module decoder(  input [1:0] iD,  output reg [3:0] oQ);always @ (*)begin    oQ = 4'b0000;  case(iD)    2'b00: oQ = 4'b0001;    2'b01: oQ = 4'b0010;    2'b10: oQ = 4'b0100;    2'b11: oQ = 4'b1000;  endcaseendendmodule

 

第6~15行,由於輸入剛好是2^n個選項,因此沒有加入default語句(沒有其他選項可能出現),而在敏感列表之後給輸出寄存器賦初值(避免產生鎖存器)這一良好的代碼風格一定要提現出來。

always @ (*)begin    oQ = 4'b0000;  case(iD)    2'b00: oQ = 4'b0001;    2'b01: oQ = 4'b0010;    2'b10: oQ = 4'b0100;    2'b11: oQ = 4'b1000;  endcaseend

 

圖2.1 使用case語句描述的解碼器的RTL視圖

 

代碼2.2 使用case語句描述的解碼器的testbench(不可綜合,僅用於模擬)

`timescale 1ns/1nsmodule decoder_tb;reg [1:0] i_d;wire [3:0] o_q;initialbegin  i_d = 2'b00;  #20 i_d = 2'b01;  #20 i_d = 2'b10;  #20 i_d = 2'b11;  #20 $stop;end   decoder decoder_inst(  .iD(i_d),  .oQ(o_q));endmodule

 

圖2.2 使用case語句描述的解碼器的功能模擬波形

 

3 碼型轉換器

有了編碼器和解碼器的基礎,下面我們舉一小例來討論一下碼型轉換器。此處以共陽的七段數位管段碼尋找表為例。

 

 

圖3.1 七段數位管

 

表3.1 七段數位管段碼尋找表

 

 

代碼3.1 七段數位管段碼尋找表(可綜合)

module seg_transcoder(  input [3:0] iNum,  output reg [7:0] oSeg);always @ (*)begin  case(iNum)    4'h0    : oSeg = 8'hC0;    4'h1    : oSeg = 8'hF9;    4'h2    : oSeg = 8'hA4;    4'h3    : oSeg = 8'hB0;    4'h4    : oSeg = 8'h99;    4'h5    : oSeg = 8'h92;    4'h6    : oSeg = 8'h82;    4'h7    : oSeg = 8'hF8;    4'h8    : oSeg = 8'h80;    4'h9    : oSeg = 8'h90;    4'hA    : oSeg = 8'h88;    4'hB    : oSeg = 8'h83;    4'hC    : oSeg = 8'hC6;    4'hD    : oSeg = 8'hA1;    4'hE    : oSeg = 8'h86;    4'hF    : oSeg = 8'h8E;    default : oSeg = 8'hFF;  endcaseendendmodule

 

圖3.1 七段數位管段碼尋找表的RTL視圖

 

代碼3.2 七段數位管段碼尋找表的testbench(不可綜合,僅用於模擬)

`timescale 1ns/1nsmodule seg_transcoder_tb;reg [3:0] i_num;wire [7:0] o_seg;initial begin  i_num = 4'h0;  for(i_num=0; i_num<4'hF; i_num=i_num+1'b1)        #20 ;endinitial #330 $stop;  seg_transcoder seg_transcoder_inst(  .iNum(i_num),  .oSeg(o_seg));endmodule

 

第8~9行,使用for語句來產生激勵資料。注意for內不能沒有運算式喲。for語句主要用作複製電路,沒有語句,就像此處一樣,用“;”表示無需複製電路。

  for(i_num=0; i_num<4'hF; i_num=i_num+1'b1)        #20 ;

 

右鍵所需觀察的訊號,選擇Radix>Hexadecimal,以十六進位形式查看訊號值。3.2所示。

 

圖3.2 以十六進位形式查看訊號值

 

圖3.3 七段數位管段碼尋找表的功能模擬波形

 

4 小結

經過上面的討論,我們發現,一般情況下,可綜合的代碼僅僅使用了if-else-if和case語句,幾乎涉及不到其他語句。由於可用綜合的語句較少,因此描述起來也比較靈活,這就使得代碼風格顯得尤為重要。然而,好的代碼風格需要長時間方能練就,作為初學者,我們不僅要經常比對自己所描述電路綜合和模擬效果是否和想法一致,還需要多讀一些官方推薦的文檔及一些大師的論文,因為我們個人的能力畢竟有限,我們要善於借鑒已有的經驗以消化利用。所謂心中有點路,此話應當這樣理解,心中本無電路,練得多了,電路才能紮根於我們的思維中,彼時我們才能遊刃有餘地來描述所需電路。

 

輔助閱讀

1. Altera.Recommended HDL Coding Styles

 

參考

1. Cliff Cummings' Award-Winning Verilog & SystemVerilog Papers. "full_case parallel_case", the Evil Twins of Verilog Synthesis

2. Wikipedia.Seven-segment display

 

另見

[與艾米一起學FPGA/SOPC].[邏輯實驗文檔連載計劃]

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.