적극적 생각/FPGA

FPGA BRAM에 데이터 저장 (2) 주소문제 해결하기 (2)

무말랭이 2022. 7. 23. 22:10

Schematic을 통해 Register에 대해 관찰하는 작업은 수행했으니 / C 코드 상에서 과거 버전 이슈 해결에 이용했던 CMake 라던가, BASE_ADDR 포인터라던가 이 부분을 조금 더 자세히 파보도록 하자.

 

내가 지금 궁금한것은 그래서 내가 사용하는 BRAM의 첫번지와 마지막번지가 어딘가? 라는 점은 잊지 말자. 

(사실 첫번지 = BASE_ADDR 일 것 같고, BASE_ADDR + 36K 처럼 하면 마지막번지일 것 같기는 하다. 다만, 디테일의 영역일듯)

 

=====

 

지금 이 코드에서

이 변수가 어디서 온 얘인지를 판다.

 

XPAR_LAB01_0_BASEADDR

 

//////////////////////////////////////////////////////////////////////////////////
// Company: Personal
// Engineer: Matbi / Austin
//
// Create Date:
// Design Name:
// Project Name:
// Target Devices:
// Tool Versions:
// Description: test read and write in bram using AXI4-Lite
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
 
#include <stdio.h>
#include "xparameters.h"
#include "xil_io.h"
#include "xtime_l.h"  // To measure of processing time
#include <stdlib.h>	  // To generate rand value

#define WRITE 1
#define READ 2
#define AXI_DATA_BYTE 4
 
#define IDLE 1
#define RUN 1 << 1
#define DONE 1 << 2

#define CTRL_REG 0
#define STATUS_REG 1
#define MEM0_ADDR_REG 2
#define MEM0_DATA_REG 3

//#define FSM_COUNTER // (lab10)

#define MEM_DEPTH 4

int main() {
    int data;
    int read_data;
    int reg_num;
    XTime tStart, tEnd;
	int i;
	int write_buf[MEM_DEPTH];
	int read_buf[MEM_DEPTH];
    while (1) {
    	printf("======= Hello Lab13 Matbi ======\n");
    	printf("plz input run mode\n");
    	printf("1. write (CTRL) \n");
    	printf("2. read (REG) \n");
    	scanf("%d",&data);

    	if(data == WRITE){
#ifdef FSM_COUNTER
    		Xil_Out32((XPAR_LAB01_0_BASEADDR) + (CTRL_REG*AXI_DATA_BYTE), (u32)(0x00000000)); // Clear
    		printf("plz input Value 31bit. MSB is the run signal\n");
    		scanf("%d",&data);

    		printf("Test SW uSleep\n");
    		XTime_GetTime(&tStart);
    		usleep(data/100);
    		XTime_GetTime(&tEnd);
    		printf("Output took %llu clock cycles.\n", 2*(tEnd - tStart));
    		printf("Output took %.2f us.\n",
    		       1.0 * (tEnd - tStart) / (COUNTS_PER_SECOND/1000000));

    		// check IDLE
    		do{
    			read_data = Xil_In32((XPAR_LAB01_0_BASEADDR) + (STATUS_REG*AXI_DATA_BYTE));
    		} while( (read_data & IDLE) != IDLE);
    		// start core
    		printf("LAB13_MATBI_0 Start\n");
    		Xil_Out32((XPAR_LAB01_0_BASEADDR) + (CTRL_REG*AXI_DATA_BYTE), (u32)(data | 0x80000000)); // MSB run
    		XTime_GetTime(&tStart);
    		// wait done
    		do{
    			read_data = Xil_In32((XPAR_LAB01_0_BASEADDR) + (STATUS_REG*AXI_DATA_BYTE));
    		} while( (read_data & DONE) != DONE );
    		XTime_GetTime(&tEnd);
    		printf("LAB13_MATBI_0 Done\n");
    		printf("Output took %llu clock cycles.\n", 2*(tEnd - tStart));
    		printf("Output took %.2f us.\n",
    		       1.0 * (tEnd - tStart) / (COUNTS_PER_SECOND/1000000));
#endif
			// (lab13 Memory Test)
    		Xil_Out32((XPAR_LAB01_0_BASEADDR) + (MEM0_ADDR_REG*AXI_DATA_BYTE), (u32)(0x00000000)); // Clear
    		printf("plz input srand value.\n");
    		scanf("%d",&data);
			srand(data);
			for(i=0; i< MEM_DEPTH ; i++){
				write_buf[i] = i;
    			Xil_Out32((XPAR_LAB01_0_BASEADDR) + (MEM0_DATA_REG*AXI_DATA_BYTE), write_buf[i]); // Clear
			}
    	} else if (data == READ){
#ifdef FSM_COUNTER
    		printf("plz input READ reg number (0~3)\n");
    		scanf("%d",&reg_num);
    		read_data = Xil_In32((XPAR_LAB01_0_BASEADDR) + (reg_num*AXI_DATA_BYTE));
    		printf("LAB13_MATBI_0 REG read done reg_number (%d), value : %d\n", reg_num, read_data & 0x7FFFFFFF); // no check run value
#endif
			// (lab13 Memory Test)
    		Xil_Out32((XPAR_LAB01_0_BASEADDR) + (MEM0_ADDR_REG*AXI_DATA_BYTE), (u32)(0x00000000)); // Clear
			for(i=0; i< MEM_DEPTH ; i++){
    			read_data = Xil_In32((XPAR_LAB01_0_BASEADDR) + (MEM0_DATA_REG*AXI_DATA_BYTE));
				if(read_data != write_buf[i]){  // Check Read Result
					printf("Matbi!! Mismatch!! plz contact me. idx : %d, Write_data : %d, Read_data : %d\n", i, write_buf[i], read_data);
				}
			}
			printf("Matbi!! Success Test Program.\n");
    	} else {
    		// no operation, exit
    		//break;
    	}
    }
    return 0;
}

 

뻥치지마

 

아마 여기 있을듯하다.

 

찾았다~

 

#define XPAR_LAB01_0_BASEADDR 0x40000000
#define XPAR_LAB01_0_HIGHADDR 0x40000FFF

 

즉 여기(0x40000000)서부터 여기까지(0x40000FFF) 모두 저장하면 되는데

여기서 비트 바이트 및 진법 표시 관련되어 혼동되는 부분만 정리하면 된다.

 

-----

 

이 램은 36Kb의 크기를 가진다.

 

36Kb

0x40000000 (16=hex)

= 01000000000000000000000000000000 (2=bin)

= 1073741824 (10=dec)

0x40000FFF (16)

= 01000000000000000000111111111111 (2)

= 1073745919 (10)

 

1073745919 - 1073741824 = 4,095 = 2^12

 

 

111111111111 = 12bits

 

즉 

 

000000000000 부터

000000000001

000000000010

...

111111111110

111111111111 까지

 

=====

 

헷갈린다.

 

물리적 구조와 Mapping 시키기 위하여

16x8 ram을 보자.

 

The internal structure of a 16x8 RAM. 

https://www.researchgate.net/figure/The-internal-structure-of-a-16x8-RAM_fig20_319203501

 

이것도 개념은 아니다.

개념을 보자.

 

 

오키 이쪽을 보다보니

addr에 대해 decode해서 펼치는 개념을 잊었었다.

 

16(=2^4)*8 ram이라는 것은 

이런 모양이라는 뜻이다.

 

0000 레지스터

0000 레지스터

0000 레지스터

0000 레지스터

0000 레지스터

0000 레지스터

0000 레지스터

0000 레지스터

 

=====

 

자 그럼 다시 돌아와서,

정보가 부족한 것 같으니

 

얘의 datasheet를 찾자.

RAMB18E1

 

이건 코드

https://github.com/awersatos/AD/blob/master/Library/HDL%20Simulation/Xilinx%20ISE%2012.1%20Verilog%20Libraries/ovi_unisim/src/RAMB18E1.v

 

GitHub - awersatos/AD: Altium Desinger

Altium Desinger. Contribute to awersatos/AD development by creating an account on GitHub.

github.com

 

이건 datasheet는 아닌데 그에 버금가게 작성되어있고

https://blog.csdn.net/shuchangsc/article/details/102542799

 

xilinx RAMB36E1 使用介绍_zzyaoguai的博客-CSDN博客

软件版本 vivado 2017.4 代码示例 RAMB36E1 #( .SIM_DEVICE("7SERIES"), .RDADDR_COLLISION_HWCONFIG( "DELAYED_WRITE" ), .DOA_REG(1), // Optional output registers on A port (0 or 1) .DOB_REG(1), // Optional output registers on B port (0 or 1) .INIT_A(36'

blog.csdn.net

 

찾았다 datasheet(?! memory resource guideline)

https://docs.xilinx.com/v/u/en-US/ug473_7Series_Memory_Resources

 

7 Series FPGAs Memory Resources User Guide(UG473)

 

docs.xilinx.com

 

위의 3가지 자료를 종합해본 결과

현재 분석해야 하는 핵심적인 정보는 다음과 같다.

 

 

=====

 

이 정보중에서 필요해보이는 것만 더 추려보면 다음과 같다.

 

//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: Austin
//
// Create Date: 2021.04.29
// Design Name: 
// Module Name: dpbram_from_hls
// Project Name:
// Target Devices:
// Tool Versions:
// Description: synthesible true dpbram from vivado hls
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////

`timescale 1 ns / 1 ps
module true_sync_dpbram (
	clk, 
	addr0, 
	ce0, 
	we0, 
	q0, 
	d0, 
	addr1, 
	ce1, 
	we1,
	q1, 
	d1
);

parameter DWIDTH = 16;
parameter AWIDTH = 12;
parameter MEM_SIZE = 3840;

input clk;

input[AWIDTH-1:0] addr0;
input ce0;
input we0;
output reg[DWIDTH-1:0] q0;
input[DWIDTH-1:0] d0;

input[AWIDTH-1:0] addr1;
input ce1;
input we1;
output reg[DWIDTH-1:0] q1;
input[DWIDTH-1:0] d1;

(* ram_style = "block" *)reg [DWIDTH-1:0] ram[0:MEM_SIZE-1];

always @(posedge clk)  
begin 
    if (ce0) begin
        if (we0) 
            ram[addr0] <= d0;
		else
        	q0 <= ram[addr0];
    end
end

always @(posedge clk)  
begin 
    if (ce1) begin
        if (we1) 
            ram[addr1] <= d1;
		else
        	q1 <= ram[addr1];
    end
end

endmodule

 

자 필요한 정보를 종합하는 것을 완료했다.

이 모든 자료를 장악한다는 것은 현재 불가능하고.

우리가 이해해야하는 컨셉들을 이해하기 위해 사용해보도록 하자.

 

여기서부터는 내일 다시 ...