• 카테고리

    질문 & 답변
  • 세부 분야

    반도체

  • 해결 여부

    해결됨

Verilog Module argument에 대해 질문이 있습니다.

23.06.14 13:26 작성 조회수 797

1

안녕하세요.

Vivado Xilinx에서 찾을 수 있는 'xilinx_true_dual_port_no_change_2_clock_ram'의 Verilog 코드를 분석하다가 막힌 부분이 있어서 질문을 드립니다.

이해가 되지 않는 부분은 모듈의 인자값 addra, addrb의 정의부분입니다.

해당코드는 메모리를 정의해주는 코드이기에 메모리의 Depth길이에 따라서 input으로 받는 Address의 길이를 모듈내에 정의된 함수 'clogb2'로 설정합니다.

궁금한것은 모듈내부에 정의된 함수로 모듈 인자값을 설정할 수 있는 것이 궁금합니다.

무엇보다 본 코드는 Xilinx에서 제공한 것인데, RTL코드를 Block Design 모듈로 불러올때 함수를 사용하는 부분에서 Error가 나옵니다.(단, clogb2(RAM_PEPTH-1)를 다른 숫자로 치환하면 Error는 없음)

 

module xilinx_true_dual_port_no_change_2_clock_ram #(
  parameter RAM_WIDTH = 18,                       // Specify RAM data width
  parameter RAM_DEPTH = 2048,                     // Specify RAM depth (number of entries)
  parameter RAM_PERFORMANCE = "HIGH_PERFORMANCE", // Select "HIGH_PERFORMANCE" or "LOW_LATENCY" 
  parameter INIT_FILE = ""                        // Specify name/location of RAM initialization file if using one (leave blank if not)
) (
  input [clogb2(RAM_DEPTH-1)-1:0] addra,  // Port A address bus, width determined from RAM_DEPTH
  input [clogb2(RAM_DEPTH-1)-1:0] addrb,  // Port B address bus, width determined from RAM_DEPTH
  input [RAM_WIDTH-1:0] dina,           // Port A RAM input data
  input [RAM_WIDTH-1:0] dinb,           // Port B RAM input data
  input clka,                           // Port A clock
  input clkb,                           // Port B clock
  input wea,                            // Port A write enable
  input web,                            // Port B write enable
  input ena,                            // Port A RAM Enable, for additional power savings, disable port when not in use
  input enb,                            // Port B RAM Enable, for additional power savings, disable port when not in use
  input rsta,                           // Port A output reset (does not affect memory contents)
  input rstb,                           // Port B output reset (does not affect memory contents)
  input regcea,                         // Port A output register enable
  input regceb,                         // Port B output register enable
  output [RAM_WIDTH-1:0] douta,         // Port A RAM output data
  output [RAM_WIDTH-1:0] doutb          // Port B RAM output data
);

  reg [RAM_WIDTH-1:0] BRAM [RAM_DEPTH-1:0];
  reg [RAM_WIDTH-1:0] ram_data_a = {RAM_WIDTH{1'b0}};
  reg [RAM_WIDTH-1:0] ram_data_b = {RAM_WIDTH{1'b0}};

  // The following code either initializes the memory values to a specified file or to all zeros to match hardware
  generate
    if (INIT_FILE != "") begin: use_init_file
      initial
        $readmemh(INIT_FILE, BRAM, 0, RAM_DEPTH-1);
    end else begin: init_bram_to_zero
      integer ram_index;
      initial
        for (ram_index = 0; ram_index < RAM_DEPTH; ram_index = ram_index + 1)
          BRAM[ram_index] = {RAM_WIDTH{1'b0}};
    end
  endgenerate

  always @(posedge clka)
    if (ena)
      if (wea)
        BRAM[addra] <= dina;
      else
        ram_data_a <= BRAM[addra];

  always @(posedge clkb)
    if (enb)
      if (web)
        BRAM[addrb] <= dinb;
      else
        ram_data_b <= BRAM[addrb];

  //  The following code generates HIGH_PERFORMANCE (use output register) or LOW_LATENCY (no output register)
  generate
    if (RAM_PERFORMANCE == "LOW_LATENCY") begin: no_output_register

      // The following is a 1 clock cycle read latency at the cost of a longer clock-to-out timing
       assign douta = ram_data_a;
       assign doutb = ram_data_b;

    end else begin: output_register

      // The following is a 2 clock cycle read latency with improve clock-to-out timing

      reg [RAM_WIDTH-1:0] douta_reg = {RAM_WIDTH{1'b0}};
      reg [RAM_WIDTH-1:0] doutb_reg = {RAM_WIDTH{1'b0}};

      always @(posedge clka)
        if (rsta)
          douta_reg <= {RAM_WIDTH{1'b0}};
        else if (regcea)
          douta_reg <= ram_data_a;

      always @(posedge clkb)
        if (rstb)
          doutb_reg <= {RAM_WIDTH{1'b0}};
        else if (regceb)
          doutb_reg <= ram_data_b;

      assign douta = douta_reg;
      assign doutb = doutb_reg;

    end
  endgenerate

  //  The following function calculates the address width based on specified RAM depth
  function integer clogb2;
    input integer depth;
      for (clogb2=0; depth>0; clogb2=clogb2+1)
        depth = depth >> 1;
  endfunction

endmodule

답변 2

·

답변을 작성해보세요.

1

안녕하세요 :)

질문 주신 부분은 저도 헷갈려서 찾아보았습니다.

저는 실제로 저렇게 function 을 만들어서 쓰기보다는 $clog2() 를 사용합니다.

결론부터 말씀드리면 합성 가능해보입니다.

Vivado 내에서 저 코드를 사용하는 방법에 대해서는 질문자 님께서 찾아보셔야 할 것 같습니다. (Xilinx 가 안되는 코드를 만들진 않았겠죠)

https://community.intel.com/t5/Intel-Quartus-Prime-Software/Determine-address-width-in-Verilog-HDL-with-clog2/td-p/26790?profile.language=ko

https://www.edaboard.com/threads/can-someone-explain-how-clogb2-function-works.311036/

즐공하세요 :)

0

https://groups.google.com/g/comp.lang.verilog/c/3eVwKLoh1lg

Verilog LRM 에 $clog2 가 있는데, tool 에서 지원을 안하는 경우가 있나보네요.

저런 방법을 꽤나? 쓰는 것 같습니다. (저는 처음봅니다.)

채널톡 아이콘