[23.04.25] AXI protocol - AXI slave 구현
1. AXI protocol concept
1-1 concept
AXI4-Lite 기준으로 구현할 것이며, 특징으로는 burst length가 1이고 32-bit 와 64 bit 중 32bit로 구현한다.
AXI4-Lite signal은 위와 같다. AWPROT과 AWPROT [2:0]은 0으로 고정시킬 것이고, BRESP과 RRESP[1:0]는 00으로 셋팅하여 OKAY를 reponse하도록 했다.
busrt 1회에 1~16개 보낼 수 있고 1개에 최대 128byte 전송 가능하다. 즉, busrt에 최대 128byte x 16 = 2048bytes를 보낼 수 있다. 여기서 size는 한 번에 몇 byte를 보내는지를 정해주는 신호이다.
현재 Lite 기준이므로 single busrt이고 최대 32bit (4byte) 보낼 수 있다.
WSTRB는 원하는 4byte중에 특정 byte에만 접근하고 싶을 때 원하는 byte 주소만 1로 셋팅하면 된다.
read/write 동작에서 위의 채널들을 사용하므로, 시뮬레이션 상에서도 잘 동작하는지 확인해야 한다.
1-2 구현
AXI slave를 구현하고 Interconnect에 AXI slave를 연결하여 led를 컨트롤해보자.
위의 부분에서 address신호 관련 AW채널과 write 신호 관련 W채널, write후 reponse 신호 관련 B채널 세 가지를 따로 봐야 한다.
AW채널 신호와 W채널 신호는 동시에 나올 수도 있고, W채널 신호가 뒤에 올 수도 있다. B채널의 response신호는 write동작이 끝난 후에 나와야 한다.
<WRITE>
AWVALID가 1이 되면 AWADDR값을 받아오고, 1클럭 후에 AWREADY가 1이 되도록 작성한다.
위와 같이 작성한다.
AWVALID가 1이면 AWADDR값을 regwaddr에 저장하고 이 값에 따라 메모리 혹은 레지스터에 접근하여 write하게 된다.
W채널의 WVALID와 WREADY도 위와 같이 작성한다.
(주소를 받고나서 wdata를 받을 수도 있지만) 주소와 wdata를 같은 타이밍에 받아와서 주소에 write하도록 구현했다. - 총실행시간이 짧아짐
wready가 1일 때 write동작을 시작하라는 의미이기 때문에, 이 때 BVALID가 1로 올라간다. 그리고 bready가 1일 때 low로 떨어질 수 있다.
wready는 regwrite에 assign하여 reg/mem에 write할 수 있도록 포트에 연결해준다.
<READ>
read에서 중요한 부분은 arvalid가 1이 되고 바로 값을 read하지 않고 2clock wait 후에 read한다는 것이다. 메모리값을 read하기 위해서 2clock wait이 필요하기 때문이다.
코드를 보면 arvalid가 1이 되고 1clock 후에 arready가 1이 되고 또 1clock 후에 regread가 1이 되면 rvalid가 1이 된다. (값 read)
rvalid가 1이 되면 regraddr에 할당되어 read된 값이 master로 보내진다.
2. AXI 검증 -read/write
vitis test code
int main(void)
{
int i;
u32 Data;
volatile int Delay;
while (1) {
for (i=0; i<8; i++)
{
Data = 0xF << i;
XGpio_WriteReg(AXI_BASEADDR, i*4, Data);
xil_printf("Reg_Write_Test Addr: 0x%0X\tWDara: 0x%X\r\n", i*4, Data);
}
Data = 0x12345678;
for (i=0; i<512; i++)
{
XGpio_WriteReg(AXI_BASEADDR, 0x800+i*4, Data);
xil_printf("MEM_Write_Test Addr: 0x%0X\tWDara: 0x%X\r\n", 0x800+i*4, Data);
Data = Data + 0x1111;
usleep(1000);
}
for (i=0; i<8; i++)
{
Data = XGpio_ReadReg(AXI_BASEADDR, i*4);
xil_printf("Reg_Read_Test Addr: 0x%0X\tRDara: 0x%X\r\n", i*4, Data);
}
for (i=0; i<512; i++)
{
Data = XGpio_ReadReg(AXI_BASEADDR, 0x800+i*4);
xil_printf("MEM_Read_Test Addr: 0x%0X\tRDara: 0x%X\r\n", 0x800+i*4, Data);
usleep(1000);
}
}
}
위와 같이 코드를 작성하여 reg/mem에 read write하는 것을 확인할 수 있다. 터미널로 띄워서 확인한다.
ila에서 위에 버튼을 누르고
vitis에서 debug 후 F5를 누르면 한 줄씩 실행시킬 수 있고, F7을 누르면 모든 구문이 자동실행된다. 실행 시킨 후 ila 에서 확인하면 된다.
<reg write>
reg 주소 0x8에 0x3c값을 write하고 있다. AW, W, B 채널 신호가 정상적으로 동작했는지 확인했다.
<reg read>
reg 주소 0x0에 저장된 값 0xF를 read하고 있다. RVALID가 1일 때 read한다. AR, R 채널 신호가 정상적으로 동작했는지 확인했다.
<mem write>
메모리 주소 0x0800에 0x12345678 데이터값을 write하는 것을 확인했다.
<mem read>
메모리 주소 0x0a1c에 저장된 값 123d566f 을 read하는 것을 확인했다.
위의 시뮬레이션은 한순간만 캡쳐했지만 모든 메모리/레지스터 주소에 read/write 동작을 확인했다.