Verilog初級教程(4)Verilog中的標量與向量


寫在前面

上一篇博文就說到了Verilog的數據類型,其中就常用的就是reg類型以及wire類型,這兩種類型可以定義一位的變量也可以定義多位的變量,其中一位稱之爲標量,多位稱之爲向量,類似於數組。本篇博客主要講述對多位變量的一些操作。
例如:
Verilog 2001修訂版新增的bit位選擇語法:

[<start_bit> +: <width>]     // part-select increments from start-bit
[<start_bit> -: <width>]     // part-select decrements from start-bit
  • 個人微信公衆號: FPGA LAB

正文

標量與變量

Verilog需要表示單個位以及多個位的組。例如,一個單bit時序元件是一個觸發器。然而一個16位的時序元件是一個可以容納16位的寄存器。爲此,Verilog有標量和矢量網以及變量。
一個沒有指定範圍的net或reg聲明被認爲是1位寬,是一個標量。如果指定了範圍,那麼net或reg就變成了一個多比特的實體,稱爲向量。

標量與向量

  wire       o_nor;           // single bit scalar net
  wire [7:0]  o_flop;          // 8-bit vector net
  reg         parity;          // single bit scalar variable
  reg  [31:0] addr;            // 32 bit vector variable to store address

範圍提供了在一個向量中尋址單個位的能力。向量中最高位應該被指定爲範圍內的左手值,而向量中最低位應該被指定在右手邊。

  wire  [msb:lsb]   name;
  integer           my_msb;
 
  wire [15:0]        priority;      // msb = 15, lsb = 0
  wire [my_msb: 2]   prior;         // illegal

在上面的例子中,將創建一個16位寬的網,稱爲優先級。注意,msb和Isb應該是一個常量表達式,不能用變量代替。
注:msb以及lsb可以是任何整數值–正負或零,而且Isb的值可以大於、等於或小於msb的值。但爲了保持風格統一,也就是左邊的值要比右邊的值大,所以不建議lsb大於或等於msb.

位選擇

向量中的任意位都可以被單獨選擇,並且可以對其單獨賦值。
如:

  reg [7:0]      addr;         // 8-bit reg variable [7, 6, 5, 4, 3, 2, 1, 0]
 
  addr [0] = 1;                // assign 1 to bit 0 of addr
  addr [3] = 0;                // assign 0 to bit 3 of addr

操作後的示意圖:

單bit選擇

但不能超出向量索引範圍:

  addr [8] = 1;                // illegal : bit8  does not exist in addr

能單個位選擇,當然也能範圍選擇,也即連續選擇相鄰的多位進行賦值等操作。
例如:

reg [31:0]    addr;
 
  addr [23:16] = 8'h23;         // bits 23 to 16 will be replaced by the new value 'h23 -> constant part-select
 

多位選擇

上面多位選擇,採用的是常量作爲索引值。
還可以使用如下的方式:

[<start_bit> +: <width>]     // part-select increments from start-bit
[<start_bit> -: <width>]     // part-select decrements from start-bit

擁有一個可變的部分選擇,可以在循環中有效地使用它來選擇矢量的部分。雖然起始位可以改變,但寬度必須是恆定的。

例如:

module des;
  reg [31:0]  data;
  int         i;
 
  initial begin
    data = 32'hFACE_CAFE;
    for (i = 0; i < 4; i++) begin
      $display ("data[8*%0d +: 8] = 0x%0h", i, data[8*i +: 8]);
    end
 
    $display ("data[7:0]   = 0x%0h", data[7:0]);
    $display ("data[15:8]  = 0x%0h", data[15:8]);
    $display ("data[23:16] = 0x%0h", data[23:16]);
    $display ("data[31:24] = 0x%0h", data[31:24]);
  end
 
endmodule

仿真結果:

ncsim> run
data[8*0 +: 8] = 0xfe              // ~ data [8*0+8 : 8*0]
data[8*1 +: 8] = 0xca              // ~ data [8*1+8 : 8*1]
data[8*2 +: 8] = 0xce              // ~ data [8*2+8 : 8*2]
data[8*3 +: 8] = 0xfa              // ~ data [8*3+8 : 8*3]

data[7:0]   = 0xfe
data[15:8]  = 0xca
data[23:16] = 0xce
data[31:24] = 0xfa
ncsim: *W,RNQUIE: Simulation is complete.

常見錯誤

舉例:

module tb;
   reg [15:0]    data;
 
   initial begin
      $display ("data[0:9] = 0x%0h", data[0:9]);   // Error : Reversed part-select index expression ordering
   end
endmodule

這個常見的錯誤,就是混用msb以及lsb的風格導致的,再次強調,統一風格,msb在做,lsb在右!


參考資料


交個朋友

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章