적극적 생각/FPGA

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

무말랭이 2022. 7. 24. 07:36

지난 시간까지를 통해 RAM과 관련된 (1)물리적구조 (2)논리적구조에 대해 어느정도 파악을 했다.

이제부터는 다시 원 궤도로 돌아와서 문제를 해결할 시간이다.(파악이 필요한 개념이 너무 많다.)

 

---

 

최소 데이터 단위를 첫주소인 BASE_ADDR에 저장하자. 

그리고 그때 그 데이터의 값과 주소를 확인할 수 있는 로깅을 하자.

그리고 최소 데이터 한개부터 최대 데이터까지 확장해보자.

 

---

 

16개 write

 

Handshake 발생시점 기준으로 주소정보는 다음과 같음.

0c, 10, 0c, 10, 0c, ...

 

주소를 이렇게 제어하는것은 어디에서 일어나는 동작인가?

 

0c(16)

= 1100(2)

= 12(10)

 

10(16)

= 00010000(2)

= 16(10)

 

vivado 말고 vitis에서 비교관찰할 수 있게 하기 위하여 얘(=XPAR_LAB01_0_BASEADDR)한테 log를 찍자. 

 

hex형으로 출력할때는 %h가 아니고 %x다.

 

출력이 되었다!

hex랑 친해지자.

 

이렇게 했을때도 

동일한 값이 나온다.

CTRL_REG = 0

AXI_DATA_BYTE = 4

 

그리고

MEM0_ADDR_REG = 2

AXI_DATA_BYTE = 4

 

-----

 

자 그럼 로그 프린트 할 수 있는 환경이 되었는데 

해당 시뮬레이션에서 주소제어가 어떻게 이뤄지는거지? 트랙킹하자.

 

MEM0_ADDR_REG = 3

AXI_DATA_BYTE = 4

 

00(BASE) - 04(+1) - 08(+2) - 0c(+3)

이래서 vivado에서는 0c번지라고 표현되는거다. 

 

 

그럼다시 10번지로 돌리는 조작은?

write동작에서 필요한 값은 없기에 don't care라고 해도

00(BASE) - 04(+1) - 08(+2) - 0c(+3) - 10(+4) 

누군가 1을 더 더해주고 있는건데?

 

그 이유는 얘가 cnt counter로 만들어졌기 때문에 그렇다.

ip가 설계될 때.

 

이건 write condition인데

we == 1 이고 주소값이 올바른정보이면 write hit 한다.

 

오케이. 

그럼 현재 내가 쓰고있는 하드웨어는, 

write hit 발생하면 주소 +1(= +4)를 시키므로 

(=포인터를 생각하면 편하다.)

이 환경을 응용해서 프로그래밍하면 되며,

혹시 이 상황 자체에 대한 변경이 필요하다면

ip를 바꾸어주면된다.

 

-----

 

여기서 지난 시간의 메모를 가져오면

36Kb

0x40000000 (16=hex)

= 01000000000000000000000000000000 (2=bin)

= 1073741824 (10=dec)

0x40000FFF (16)

= 01000000000000000000111111111111 (2)

= 1073745919 (10)

 

이므로

0x40000000 부터 0x40000FFF 까지를 

차근히 저장하기만 하면 될 것 같은데 

 

정작 활용하고 있는 곳은

0x40000000 부터 0x40000010 까지만이고

0x4000000c 로 보낸 데이터를 다른곳(mem)으로 보내고 있다.

 

mem0_addr_cnt 로

 

그럼 다시 그 주소는

mem0_addr1로 보내진다.

 

---

 

RTL Schematic을 보자.

wiring 관계를 보아야겠다.

 

근데 여기서 지금 파악이 힘든게

논리적 주소에 대해서는 이해가 가는데

물리적 주소에 대해는 다르게 되어있다.

 

 

여기서 0c로만 보낸 주소를

어떻게 mem 내부에서 차곡히 쌓아주는지에 대해서

어디서 Ctrl 해주는가? 를 찾아내보자.

 

-----

 

별도의 dram 코드에 대해서만

신규 dummy project로 

bitstream 생성해서

RTL Schematic을 보자.

 

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

 

synthesis는 되는데

implementation은 안된다.

(이건 나중에 공부하고)

 

RTL은 다음과 같다.

 

코드 수정해서 다시 합성해보자.

 

ce와 we는 알아서 처리해준다고 생각하고

addr[12]과 d1[16]의 흐름만 보자.

 

 

addr와 d1는 ram_reg에 들어가서 RO1으로 나와서 q1_reg의 D로 들어가고, 최종적으로 q1 포트로 나온다.

 

이를 바탕으로 프로젝트 전체구조에서 살펴보면

빨간색 박스가 addr cnt 이고 그렇게 나온 신호가 

mem0_addr_cnt_reg[8]_0[8:0]을 통해서

ram_reg_0[8:0]으로 dpbram에 들어가고.

이는 ADDRARDADDR[15:0]으로 들어간다.

(ip, axi 등의 이유로 인해서 정확하게 일치하게 나오진 않는다. 하지만 시간대비 ROI는 훌륭했다.)

 

 

ADDRARDADDR과 

ADDRBRWADDR가

뭐하는 포트인지 확인하자.

 

단순한 주소포트다!!!

 

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

 

RAMB36E1 - 2022.1 English

Primitive: 36K-bit Configurable Synchronous Block RAM Introduction 7 series devices contain several block RAM memories that can be configured as FIFOs, automatic error correction RAM, or general-purpose 36 Kb or 18 Kb RAM/ROM memories. These block RAM memo

docs.xilinx.com

 

좋아 어떻게 이동하는지에 대해서는 

경로를 알게 되었다.

 

근데 Ctrl은 어디서 일어나지?

 

 

여기서 이상한점 하나 발견해서

이 부분 확인해보자.

addr을 안쓰고 wdata를 쓰나?

 

 

와우 문서에서 잘못된 부분을 찾았다.

파랑색으로 처리해둔 부분이 

WRADDR이 아니고 RDADDR이 맞는 듯 하다.

 

조금 간결하게 파악해보자면

 

주소는 16비트(hex)가 ADDRARDADDR을 통해서 가고

데이터는 32비트가 DIADI를 통해서 간다.

 

조금 더 엄밀하게 이야기 해보자면

입력으로 들어온 8비트 ram_reg_0[8:0]은

ADDRARDADDR[15:0]의 [13:5]로 들어간다. 

ADDRARDADDR[13:5]

 

 

0x40000000 8비트

0x40000FFF 8비트

 

-----

 

오키! 포트에 대해서는 어느정도 장악했다.

다시 Code로 넘어오자.

 

지금 우리가 0c로 보내기만 하는데 알아서 주소를 차곡차곡 쌓아주는 이유는

우리는 axi_awaddr에 0c로 보내주는거고

 

그게 카운터를 거쳐서

addr로 전달된다.

 

즉 주소값을 관찰하기 위하여 
ADDRARDADDR에다가 

Probe붙이면 되는데 

ILA는 AXI에만 붙어있어 거기까진 관찰이 되지 않는다.

 

project 다시 만들자.

음 근데 lab01 내부에서 hierachy를 더 쪼개서 ila 붙일수는 없나본데 ㅠㅠ 아직 합성하기 전이니깐.

다른데에는 붙는데 ila는 이미 최대로 붙어있는 것으로 간주하나봄

이 방법은 파기한다.

 

우리는 그럼 

ADDRARDADDR을 보는것이 목표이니.

다른 방법을 찾자.

 

우선 방법이 잘 찾아지지 않으므로 질문좀 남겨두고 ... ㅠ_ㅠ 

https://www.inflearn.com/questions/602972

 

합성된 이후, 원하는 신호에 대해 ILA처럼 Probe를 하는 방법 - 인프런 | 질문 & 답변

안녕하세요. 강의 너무 재미있고 도움되게 듣고 있습니다. 13강 bram과 관련된 부분에 대해 복습중입니다. 한가지만 짧게 여쭙고 싶습니다. (혹시 답변이 가능하지 않은 범위라면, 괜찮습니다.)  

www.inflearn.com

 

오 중간에 발견한 추가적인것은 

schematic에 대해 pdf export가 가능하구나

schematic.pdf
0.27MB