본문 바로가기

FPGA 는 내부의 램을 필요한 만큼 만들어 쓸수 있는 장점이 있다.

기본적인 1 포트 램을 만들어서 써보자. 일단 데이터시트에서 동작도를 확인할 필요가 있다.

 

Xilinx Parameterized Macros 페이지에 가면 기본적인 RAM에 대한 정보가 있다.

https://docs.xilinx.com/r/en-US/ug953-vivado-7series-libraries/XPM_MEMORY_SPRAM

 

XPM_MEMORY_SPRAM - 2023.2 English

Specify the reset value of the port A final output register stage in response to rsta input port is assertion. Since this parameter is a string, you must specify the hex values inside double quotes. For example, If the read data width is 8, then specify RE

docs.xilinx.com

DPRAM, ROM, Distributed 등등 원하는대로 읽어보고 사용하면 될듯, 제일 간단한 SPRAM만 한번 보자.

SPRAM 구조

몇몇 상수를 정하는 것을 제외하고는 그냥 활용하면 된다.

일반 램으로 사용할 것이므로, 부가적인 기능은 그냥 기본값으로 지정하면 될 듯

Xilinx SPRAM 구조

injectsxxxx, sbiterraxxx, sleep,... 등의 고급기능은 일단 disable 모드로 활용

 

SPRAM 동작 파형

쓰는 동작을 기반으로 하는 동작 파형은 아래 그림과 같다.

레이턴시에 따라 주소에 들은 값을 읽어서 내보내는 시점이 달라지긴 하네

SPRAM 동작파형

SPRAM 테스트 코드 예제

테스트 벤치에 사용한 예제를 만들어 봤는데, 내가 쓴 코드는 아래와 같다.

8비트로 바꾸고 2KByte 램을 만들어 봤다. 

데이터 너비는 8비트, 어드레스는 12 비트 맞나? 암튼 아래 코드 참고해서 인스턴스 만들어서 돌려볼 수 있다.

  • READ_LATENCY_B 는 1로 줘서 최대한 빨리 나오도록
  • WRITE_MODE_A 는 "read_first", "no_change", "write_first" 로 지정할 수 있는데 "write_first" 로 지정
  • sleep mode 며, ECC며 그냥 왠만하면 안쓰는 모드로 지정했다. 그냥 램이다.
  • 초기화 값 추가, MEMORY_INIT_PARAM = "AB,CD,EF,1,2,34,56,78" Where "AB" is the 0th location and "78" is the 7th location.
//  <-----Cut code below this line---->
   // xpm_memory_spram: Single Port RAM
   // Xilinx Parameterized Macro, version 2023.2
    xpm_memory_spram #(
      .ADDR_WIDTH_A(11),              // DECIMAL
      .AUTO_SLEEP_TIME(0),           // DECIMAL
      .BYTE_WRITE_WIDTH_A(8),       // DECIMAL
      .CASCADE_HEIGHT(0),            // DECIMAL
      .ECC_BIT_RANGE("7:0"),         // String
      .ECC_MODE("no_ecc"),           // String
      .ECC_TYPE("none"),             // String
      .IGNORE_INIT_SYNTH(0),         // DECIMAL
      .MEMORY_INIT_FILE("none"),     // String
      .MEMORY_INIT_PARAM("0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,0"),       // String
      .MEMORY_OPTIMIZATION("true"),  // String
      .MEMORY_PRIMITIVE("auto"),     // String
      .MEMORY_SIZE(2048),            // DECIMAL
      .MESSAGE_CONTROL(0),           // DECIMAL
      .RAM_DECOMP("auto"),           // String
      .READ_DATA_WIDTH_A(8),        // DECIMAL
      .READ_LATENCY_A(1),            // DECIMAL
      .READ_RESET_VALUE_A("0"),      // String
      .RST_MODE_A("SYNC"),           // String
      .SIM_ASSERT_CHK(0),            // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
      .USE_MEM_INIT(1),              // DECIMAL
      .USE_MEM_INIT_MMI(0),          // DECIMAL
      .WAKEUP_TIME("disable_sleep"), // String
      .WRITE_DATA_WIDTH_A(8),       // DECIMAL
      .WRITE_MODE_A("write_first"),   // String
      .WRITE_PROTECT(1)              // DECIMAL
    ) 
    xpm_memory_spram_inst (
      .dbiterra(dbiterra),             // 1-bit output: Status signal to indicate double bit error occurrence
                                       // on the data output of port A.

      .douta(douta),                   // READ_DATA_WIDTH_A-bit output: Data output for port A read operations.
      .sbiterra(sbiterra),             // 1-bit output: Status signal to indicate single bit error occurrence
                                       // on the data output of port A.

      .addra(addra),                   // ADDR_WIDTH_A-bit input: Address for port A write and read operations.
      .clka(CLK100MHZ),                     // 1-bit input: Clock signal for port A.
      .dina(dina),                     // WRITE_DATA_WIDTH_A-bit input: Data input for port A write operations.
      .ena(ena),                       // 1-bit input: Memory enable signal for port A. Must be high on clock
                                       // cycles when read or write operations are initiated. Pipelined
                                       // internally.

      .injectdbiterra(1'b0), // 1-bit input: Controls double bit error injection on input data when
                                       // ECC enabled (Error injection capability is not available in
                                       // "decode_only" mode).

      .injectsbiterra(1'b0), // 1-bit input: Controls single bit error injection on input data when
                                       // ECC enabled (Error injection capability is not available in
                                       // "decode_only" mode).

      .regcea(1'b1),                 // 1-bit input: Clock Enable for the last register stage on the output
                                       // data path.

      .rsta(1'b0),                // 1-bit input: Reset signal for the final port A output register stage.
                                       // Synchronously resets output port douta to the value specified by
                                       // parameter READ_RESET_VALUE_A.

      .sleep(1'b0),                   // 1-bit input: sleep signal to enable the dynamic power saving feature.
      .wea(wea)                        // WRITE_DATA_WIDTH_A/BYTE_WRITE_WIDTH_A-bit input: Write enable vector
                                       // for port A input data port dina. 1 bit wide when word-wide writes are
                                       // used. In byte-wide write configurations, each bit controls the
                                       // writing one byte of dina to address addra. For example, to
                                       // synchronously write only bits [15-8] of dina when WRITE_DATA_WIDTH_A
                                       // is 32, wea would be 4'b0010.

    );
   // End of xpm_memory_spram_inst instantiation

 

참고로 위의 템플릿 코드는 Vivado 툴에서도 복사해 볼 수 있다.

"Language Template" 메뉴를 클릭하고,

팝업 창에서 필요한 component 이름을 검색하고, 알맞은 것을 찾아서 클릭하면

Preview 창에 샘플 코드가 나타난다. 

일단 이것을 복사해서 활용하면 된다.

Vivado Language Template

 

간단하게 Xilinx Vivado 툴에서 사용가능한 SPRAM 에 대해 정리해 보았다. 추가적으로 더 보강할 시간이 있으면 좋겠네요 :)

B로그0간

개발 관련 글과 유용한 정보를 공유하는 공간입니다.