적극적 생각/FPGA

FPGA BRAM에 데이터 저장.

무말랭이 2022. 7. 23. 11:21

자 단순하게 간단한 작업을 해보자.

BRAM 하나의 용량만큼 1을 저장해보자.

 

예를들어 BRAM이 4x4 사이즈라고 치면

[1,1,1,1,

1,1,1,1,

1,1,1,1,

1,1,1,1]

으로 저장하는 것이다. 

 

시작해보자.

실습 워크플로우에서 참고할때는 이 글의 lab13을 참고한다.

https://learn-future.tistory.com/3515

 

(중요) 0721 - 섹션4 - AXI4Lite 이용해 BRAM에 RW

이론 BRAM 지금까지는 Register에 --- 코드리뷰 Write Read Addr --- 실습 MYIP를 Replace할건데 코드 수정시에도 VIP 모듈이 연결되어있는 것을 유념 이쪽 파일을 실습 파일로 변경해줄건데 edit i..

aidenkang.me

 

당연히 다음 workflow대로 진행할 것이다.

[1.ip생성 - 2. Vivado HW - 3. Vitis SW - 4. FPGA]

 

[1.ip생성]

 

vivado proj 생성

lab13_matbi 환경을 불러와서 lab01 로 커스텀해준 후

01_bram_ip폴더에 ip를 패키징해준다.

 

 

[2.Vivado SW]

 

vivado proj 생성

생성한 ip 그리고 zynq ip를 호출 + axi ila 추가 (지금은 공부목적이니 추가하는데, 빼면 훨씬 라이트해질듯)

wrapper

bitstream (참 시간 오래 걸린다. 마치 딥러닝 학습과정 에폭처럼.)

hw export

 

[3.Vitis SW]

 

create project

customize (XPAR_LAB13_MATBI_0_BASEADDR -> XPAR_LAB01_0_BASEADDR)

 

[4.FPGA]

 

그러고나서, 기존 C코드의 프로그램이 정상 동작하는 것을 확인했다.

 

---

 

자 이제부터 시작이다. 

 

(1)

프로그램은 원래 다음과 같았다.

'srand seed값을 입력받아, random생성을 하여 

그 값을 저장한다.'

이 프로그램을

'srand seed값을 1로 하여, random생성을 하여

그 값을 저장한다.'

로 간단하게 베이스라인 수정을 해주었고 

문구를 몇가지 바꾸어주었다.

 

 

(2)

지금은 random값을 저장하는 상태라서 vitis hw manager에서는 다음과 같이 확인된다.

이 프로그램을 1을 저장하게끔 바꾸어보았다.

잘 된 것으로 보인다. 하지만 여기서 짧게 확인할 부분이 있는데, 여기는 왜 0일까?

또한 현재 vivado에서 sample을 1024번밖에 못하니

이 노이즈를 빼고 보기 위하여

MEM_DEPTH 만큼 저장하던 것도 4로 우선 바꿔두자.

데이터는 4번 모두 1로 잘 저장된다.

 

---

 

위에서 확인하고자했던 앞에서 0이 등장하는 것은

WDATA 신호가 0으로 초기화되는 작업으로 추측되는데 이를 확인해보자.

SW 코드를 확인했다. 당연히 관련 부분은 나오지 않는다.

HW 코드를 확인했다. 여기서 나올줄 알았는데 나오지 않는다.

왜 없을까 생각해보았더니, 지금 저 waveform이 만들어지는 것은 simulation 즉 tb의 영역이다.

ILA와 관련된 원본 리소스를 확인해주어야 한다.

 

ILA에 대한 리소스를 찾았다.

ILA = Integrated Logic Analyzer

https://www.xilinx.com/support/documentation/ip_documentation/ila/v6_2/pg172-ila.pdf

https://wikidocs.net/157033#:~:text=Multiple%20ILA%20Instance-,ILA%20(Integrated%20Logic%20Analyzer),%ED%95%9C%20%ED%9B%84%20%EC%82%AC%EC%9A%A9%ED%95%A0%20%EC%88%98%20%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4. 

 

하지만 본 문서에서는 그러한 부분까지를 다루지는 않는다.

이 부분을 찾는것을 생략할 수도 있지만 유의미하다고 생각하기에 조금 더 찾아본다.

 

xil_io.h 의 Xil_Out32 함수

 

다시 HW Source Code 추적

ex. slv_reg_wren

mem0_addr_cnt

 

음 우선 이 부분을 파악하기는 해야한다.

왜냐하면 내가 지금 다루고자 하는 논리가

일종의 memory controller 이기 때문에

addr 관련 정보를 정확히 파악해야 한다.

 

하지만 어떤 논리가 전개될지 약간 예상은 되어도

잘 찾아지지 않는데, 이건 우리가 할 작업에 충실하다 보면 찾아질 것 같다고 예상된다.

 

---

 

다시 원래 흐름으로 돌아온다.

자 이제 1을 4번 저장하는 것에 성공했다.

MEM_DEPTH = 512 만큼 다시 저장하자.

 

 

왜 'MEM_DEPTH = 512' 인가? 점검하자.

Resource Utilization for Block Memory Generator v8.4

https://www.xilinx.com/htmldocs/ip_docs/pru_files/blk-mem-gen.html

 

Resource Utilization for Block Memory Generator v8.4

Register_PortB_Output_of_Memory_Primitives

www.xilinx.com

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=ansdbtls4067&logNo=221281079043 

 

[FPGA 강의] 31강 - RAM 설계 따라하기

0. 들어가며...지난 시간 ROM 설계 따라하기에 이어서 이번 포스팅에서는 RAM 설계 따라하기 강의를 ...

blog.naver.com

 

현재 우리의 확인 대상물은 본 BRAM Tile이다.

 

우리가 잡은 값인건데 32b*512 = 16,384b, 

36b*1024 = 36,864b

즉 우리가 쓰는 BRAM은 36Kb 까지 제공하는데 우리가 Depth를 512로 잡아서 그 중 16KB 정도를 사용하고 있다.

 

그럼 Depth를 1024로 잡으면 문제가 발생하지 않을 것이고 (32KB) 1536 or 2048로 잡으면 문제가 발생할 것이다.

문제가 SW적으로 HW적으로 발생하는지를 확인하고, 적당한 치유를 해주자.

 

 

우선 WIDTH=4로 줄이고나서

printf 로 log 측정을 붙혔다.

 

 

음 다시 에러가 나는 상황인데 

확인해보자.

(설마 2048을 한번 WRITE 하는 과정에서 HW적으로 에러났나?

근데 그럼 다시 Program 시키는 과정에서 덮여야 하는 것 아닌가...)

 

 

BASEADDR을 기준으로 8씩 증가시킨다.

 

아 여기서 위에서 찾던 초기화의 정체도 찾았다. 여기서 이뤄졌었구나.

 

그리고 메모하자면 현재 우리는 BRAM을 HW적으로 3% Utilization 하고있다.

 

여기에 영향을 주는곳은 이쪽(ip)이다.

 

 

음 근데 에러가 해소가 안되길래, 

lab13-main.c로 다시 데려와서 해봤는데, 그래도 안된다.

 

vivado & vitis 껐다 켜본다.

 

그래도 안된다. ...

 

음 우선 여기서 한번 끊고 넘어가자.

뭐가 문제일까 ...

 

몇시간후에 다시 시도중인데

그럼에도 불구하고 잘 안된다.

 

한번 정상적으로 실행되었을때의 타이밍 다이어그램과 값을 비교해보자.

현재 직관적으로 느껴지는 이슈의 가능성이 '주소'에 문제가 있는 것 같다.

 

 

이게 그나마 멀쩡했을 때의 상태인데

여기에서도 'A'채널에 대해 실수로 열어두지 않아서 추적이 안된다.

 

=====

 

아~ 해결의 실마리를 찾았다.

지금 트리거링을 통한 시뮬레이션에서 문제가 있다.

 

우선 지금 잘 되는 경우가 왜 잘되는지를 언어로 표현해서 이해해보자.

그래야 내가 지금 왜 안되는지를 해결할 수 있다.

 

-----

 

[1] Run Trigger를 1회 실행한다. 

Vitis Serial Terminal에서 1.write를 입력한다.

다음과 같은 시뮬레이션 결과가 나온다.

 

[2] 자 여기서 다시 Run Trigger를 2번째로 실행한다. 

Vitis Serial Terminal에서 srand seed값을 입력한다.

다음과 같은 시뮬레이션 결과가 나온다.

 

-----

 

위의 끊어줌을 활용하여 

원래 에러가 나던 A코드를 B코드와 같이 바꾸었다.

 

[A코드]

//////////////////////////////////////////////////////////////////////////////////
// Company: Personal
// Engineer: Matbi / Austin / Aiden
//
// 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

#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 512

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 Lab 01 ======\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("LAB01_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("LAB01_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
			//for(i=0; i<MEM_DEPTH ; i++){
			for(i=0; i<4 ; i++){
				write_buf[i] = 1;
    			Xil_Out32((XPAR_LAB01_0_BASEADDR) + (MEM0_DATA_REG*AXI_DATA_BYTE), write_buf[i]); // Clear
    			printf("%d, %d\n",(XPAR_LAB01_0_BASEADDR) + (MEM0_DATA_REG*AXI_DATA_BYTE), write_buf[i]);
			}
			printf("Success/Write\n");
    	} 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("LAB01_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++){
			for(i=0; i<4 ; 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("Mismatch!! plz contact me. idx : %d, Write_data : %d, Read_data : %d\n", i, write_buf[i], read_data);
				}
			}
			printf("Success/Read\n");
    	} else {
    		// no operation, exit
    		//break;
    	}
    }
    return 0;
}

[B코드]

//////////////////////////////////////////////////////////////////////////////////
// Company: Personal
// Engineer: Matbi / Austin / Aiden
//
// 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

#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 512

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 Lab 01 ======\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("LAB01_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("LAB01_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("Initialize Done. plz enter any int value.\n");
    		scanf("%d",&data);
			for(i=0; i<MEM_DEPTH ; i++){
			//for(i=0; i<4 ; i++){
				write_buf[i] = i;
    			Xil_Out32((XPAR_LAB01_0_BASEADDR) + (MEM0_DATA_REG*AXI_DATA_BYTE), write_buf[i]); // Clear
    			printf("%d, %d\n",(XPAR_LAB01_0_BASEADDR) + (MEM0_DATA_REG*AXI_DATA_BYTE), write_buf[i]);
			}
			printf("Success/Write\n");
    	} 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("LAB01_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++){
			//for(i=0; i<4 ; 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("Mismatch!! plz contact me. idx : %d, Write_data : %d, Read_data : %d\n", i, write_buf[i], read_data);
				}
			}
			printf("Success/Read\n");
    	} else {
    		// no operation, exit
    		//break;
    	}
    }
    return 0;
}

음 근데 이래도 안된다.

- Initialize 이전의 waveform

- Burst Write 이후의 waveform

두 이미지를 비교한 사진

 

자 그럼 한번 더 보자.

잘 되던 코드랑. 지금 내 코드랑 뭐가 차이나지?

 

딱 

write_buf[i] = rand(); 

대신에

write_buf[i] = i;

넣어주니깐

잘된다.

 

이거 왜 잘되지.

잘 되는게 더 마음에 안드는데.

 

 

자 이 코드를 기준으로 해서 

내 코드랑 다시 비교해보자.

어떤 개념을 잘못 접근했는지에 대하여.

 

//////////////////////////////////////////////////////////////////////////////////
// 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 512

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;
}

 

아~ printf 가 문제였는데

주소와 관련된 연산을 1사이클 해야할 것을 2사이클 한듯하다.

 

 

어 근데 코드를 이렇게 수정하면 되어야 하는데 

아직도 되지 않는다.

그럼 뭐가 문제라는거지 

아직 문제를 해결하지는 못했다.

 

//////////////////////////////////////////////////////////////////////////////////
// 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 512

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];
	int addr; // Added
    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; // Changed
				addr = (XPAR_LAB01_0_BASEADDR) + (MEM0_DATA_REG*AXI_DATA_BYTE); // Added
    			Xil_Out32(addr, write_buf[i]); // Clear
    			printf("%d, %d\n",addr, write_buf[i]); // Added
			}
    	} 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++){
				addr = (XPAR_LAB01_0_BASEADDR) + (MEM0_DATA_REG*AXI_DATA_BYTE);
    			read_data = Xil_In32(addr);
    			printf("%d, %d\n",addr, read_data); // Added
				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;
}

 

Xil_Out32() 함수에서

Addr는 int가 아니라 UINTPTR이다.

 

UINTPTR Usage by Xilinx

내가 지금 쓰는 C는 C가 아니라 

Xilinx가 쓰는 C라는 것도 인식해야함.

(자세히는 모르겠는데 뭔가 조금은 다름)

 

https://support.xilinx.com/s/question/0D52E00006hpUztSAE/uintptr-usage?language=en_US 

 

UINTPTR usage

 

support.xilinx.com

https://docs.oracle.com/cd/E19253-01/817-6223/chp-typeopexpr-2/index.html

 

https://docs.oracle.com/cd/E19253-01/817-6223/chp-typeopexpr-2/index.html

Data Types and Sizes D provides fundamental data types for integers and floating-point constants. Arithmetic may only be performed on integers in D programs. Floating-point constants may be used to initialize data structures, but floating-point arithmetic

docs.oracle.com

 

해당 자료형이 특수한 포인터임을 감안하여

다음과 같은 수정을 가해주었는데 

그래도 에러가 동일히 발생한다.

 

프로그램이 돌아가버리는 주소관련 에러가 가장 무서운법

경고메시지를 조금 더 들여다보자.

 

음 ... 

이것도 잠시 넘어가자. 

현재 console에 print를 해주는 것이 목적이었기 때문에 

지금으로서는 아주 중요하지 않으며, 

또한 다음번에 보면 더 잘 풀릴 수 있을 것 같다.

 

=====

 

 

그럼 여기 기준으로 

512번 또는 1024번이 아닌

2048번을 넣을때 

보드가 뻑나는지 보자.

 

1024는 정상 동작한다.

 

2048은 

이상하게 정상작동 하면서도 : 왜 돌아가지

중간에 이상한 불균형지점이 생긴다. : 저건 뭐지

 

왜 돌아가지~

확인할 방법이 현재로서는 없다.

 

왜냐면 '보드내의 BRAM의 주소값'을 출력해주는 로그콘솔이 없어서인데

(위에서 못 해결한 문제와도 간접적 연관)

 

이 부분을 확인하기 위해서 BASE_ADDR을 파보아야겠다.

보드 내부를 자유자재로 다루기 위해서는 여기서 주소를 잘 다뤄야 한다.