2023年12月16日 星期六

@ in Verilog


可能我學習 Verilog 的網頁寫的不好?或是 @ 概念是在做板子測試時看到故沒有放到心裡去!

昨天下午在學 repeat 語法時,該範例的波形讓我一直百思不得其解,終於在睡覺前大概知道為什麼,但就差在不確定 @ 是否有等待的作用?

雖然從結果來看,就像是 wait?

下午外出回來洗完澡,用 "Verilog @ syntax" 關鍵字查詢,終於看到一個大學的 PDF 有描述到這個語法,但我還是想要看到更官方的資料(IEEE?)。

總之,我昨天犯了一個錯誤:

明明告訴你是 posedge clk,故接下來的 code 理論上應該已經離開了 posedge clk 那個點,先不論 @ 是否會 wait,本來就應該要到下一個 poedge clk 才會再被偵測到,也就是下一個 clock cycle。

所以 96 ns 時,雖然 j = 0,但要到下一個 clock,106 ns 時才會對 buffer0 設值。

我們可以簡單用這個小程式來觀察時間點,從時間單位 10 開始,每隔 20 單位依序印出 1 和 2 當下的時間。

reg clk = 0;

always begin
   #10;
   clk = ~clk;
end

always @ (posedge clk) begin
   $display("1", $time);
   @(posedge clk) begin
       $display("2", $time);
   end
end

整個 repeat example 如下:

`timescale 1ns/1ns

module study;
   initial begin
      $dumpfile("wave.vcd");
      $dumpvars(0, study);
   end

   reg [3:0]    counter3;
   initial begin
      counter3 = 'b0;
      repeat (11) begin
         #10;
         counter3 = counter3 + 1'b1;
      end
   end

   //(3)
   reg          clk;
   reg          rstn;
   reg          enable;
   reg [3:0]    buffer[7:0];
   reg [3:0]    buffer7, buffer6, buffer5, buffer4, buffer3, buffer2, buffer1, buffer0;
   integer      j;
   integer      i = 0;

   initial begin
      clk       = 0;
      rstn      = 1;
      enable    = 0;
      #3;
      rstn      = 0;
      #3;
      rstn      = 1;
      enable    = 1;
      forever begin
         clk <= ~clk;
         #5;
      end
   end

   always @(posedge clk or negedge rstn) begin
      j = 0;
      if (!rstn) begin
         repeat (8) begin
            buffer[j] <= 'b0;
            j = j + 1;
         end
         i = 1;
      end
      else if (enable) begin
         repeat (8) begin
            @(posedge clk) buffer[j] <= counter3;
            j = j + 1;
         end
      end
   end

   always @(buffer[7]) begin
        buffer7 <= buffer[7];
   end

   always @(buffer[6]) begin
        buffer6 <= buffer[6];
   end

   always @(buffer[5]) begin
        buffer5 <= buffer[5];
   end

   always @(buffer[4]) begin
        buffer4 <= buffer[4];
   end

   always @(buffer[3]) begin
        buffer3 <= buffer[3];
   end

   always @(buffer[2]) begin
        buffer2 <= buffer[2];
   end

   always @(buffer[1]) begin
        buffer1 <= buffer[1];
   end

   always @(buffer[0]) begin
        buffer0 <= buffer[0];
   end

   //stop the simulation
   always begin
      #10;
      if ($time >= 1000) $finish;
   end

endmodule

上面 buffer0 ~ buffer7 是為了接住 buffer[7:0] array 值用,可能是我還不會用 iverilog,無法在 GTKWave 中看到 array,故先用這種方式方便我看波形。

另一個很重要的概念是 = 雖然是阻塞賦值,可以控制流程先後順序,但這個操作應該是不佔時間,至少我從 wave 中看到,變數 i 的值是在 3 ns 時變成 1。

2023/12/18 更新

這應該是 Verilog - 2001 Standard 裡面關於 @ 的描述。


2023/12/26 更新

可以用 generate 語法來 mapping array,比宣告 buffer1 ~ buffer7 還方便。
buffer[0] 就是 test.array_buffer[0].buf。

genvar k;
generate
    for (k = 0; k < 8; k = k + 1) begin: array_buffer
    wire [3:0] buf;
    assign buf = buffer[k];
    end
endgenerate

沒有留言:

張貼留言