---
AXI Outstanding
AHB 대비 AXI 프로토콜의 장점 몇 가지
http://egloos.zum.com/donghyun53/v/4087409
---
07_axi4_lite_project 라는 프로젝트를 생성해주고
Tools > Create new IP
레지스터 개수가 512인 이유는 template이 대략 지원하는 범위라서 그렇고
실무적으로 512개까지 쓰는 경우도 거의 없다.
자동으로 timing diagram을 보여준다.
open block design을 해주자.
우리가 만든 부분은 이 부분인데
자동으로 AXI VIP 부분과 연결이 되어있다.
(시뮬레이션을 위한 펑션을 검증하기 위한 모듈이라서
합성을 한다거나 하는 목적으로 활용하지는 않음)
다시 diagram으로 돌아오면
우리가 레지스터 4개를 사용했으니깐
이렇게 나오는건데
Write를 4번하고
Read를 4번한후에
그 둘이 맞는지를 검증하는
시뮬레이션이 셋팅되어있는 것이다.
tb가 system verilog로 작성되어 있는 것
`timescale 1ns / 1ps
`include "lab7_axi4_lite_v1_0_tb_include.svh"
import axi_vip_pkg::*;
import lab7_axi4_lite_v1_0_bfm_1_master_0_0_pkg::*;
module lab7_axi4_lite_v1_0_tb();
xil_axi_uint error_cnt = 0;
xil_axi_uint comparison_cnt = 0;
axi_transaction wr_transaction;
axi_transaction rd_transaction;
axi_monitor_transaction mst_monitor_transaction;
axi_monitor_transaction master_moniter_transaction_queue[$];
xil_axi_uint master_moniter_transaction_queue_size =0;
axi_monitor_transaction mst_scb_transaction;
axi_monitor_transaction passthrough_monitor_transaction;
axi_monitor_transaction passthrough_master_moniter_transaction_queue[$];
xil_axi_uint passthrough_master_moniter_transaction_queue_size =0;
axi_monitor_transaction passthrough_mst_scb_transaction;
axi_monitor_transaction passthrough_slave_moniter_transaction_queue[$];
xil_axi_uint passthrough_slave_moniter_transaction_queue_size =0;
axi_monitor_transaction passthrough_slv_scb_transaction;
axi_monitor_transaction slv_monitor_transaction;
axi_monitor_transaction slave_moniter_transaction_queue[$];
xil_axi_uint slave_moniter_transaction_queue_size =0;
axi_monitor_transaction slv_scb_transaction;
xil_axi_uint mst_agent_verbosity = 0;
xil_axi_uint slv_agent_verbosity = 0;
xil_axi_uint passthrough_agent_verbosity = 0;
bit clock;
bit reset;
integer result_slave;
bit [31:0] S00_AXI_test_data[3:0];
localparam LC_AXI_BURST_LENGTH = 8;
localparam LC_AXI_DATA_WIDTH = 32;
task automatic COMPARE_DATA;
input [(LC_AXI_BURST_LENGTH * LC_AXI_DATA_WIDTH)-1:0]expected;
input [(LC_AXI_BURST_LENGTH * LC_AXI_DATA_WIDTH)-1:0]actual;
begin
if (expected === 'hx || actual === 'hx) begin
$display("TESTBENCH ERROR! COMPARE_DATA cannot be performed with an expected or actual vector that is all 'x'!");
result_slave = 0; $stop;
end
if (actual != expected) begin
$display("TESTBENCH ERROR! Data expected is not equal to actual.", " expected = 0x%h",expected, " actual = 0x%h",actual);
result_slave = 0;
$stop;
end
else
begin
$display("TESTBENCH Passed! Data expected is equal to actual.",
" expected = 0x%h",expected, " actual = 0x%h",actual);
end
end
endtask
integer i;
integer j;
xil_axi_uint trans_cnt_before_switch = 48;
xil_axi_uint passthrough_cmd_switch_cnt = 0;
event passthrough_mastermode_start_event;
event passthrough_mastermode_end_event;
event passthrough_slavemode_end_event;
xil_axi_uint mtestID;
xil_axi_ulong mtestADDR;
xil_axi_len_t mtestBurstLength;
xil_axi_size_t mtestDataSize;
xil_axi_burst_t mtestBurstType;
xil_axi_lock_t mtestLOCK;
xil_axi_cache_t mtestCacheType = 0;
xil_axi_prot_t mtestProtectionType = 3'b000;
xil_axi_region_t mtestRegion = 4'b000;
xil_axi_qos_t mtestQOS = 4'b000;
xil_axi_data_beat dbeat;
xil_axi_data_beat [255:0] mtestWUSER;
xil_axi_data_beat mtestAWUSER = 'h0;
xil_axi_data_beat mtestARUSER = 0;
xil_axi_data_beat [255:0] mtestRUSER;
xil_axi_uint mtestBUSER = 0;
xil_axi_resp_t mtestBresp;
xil_axi_resp_t[255:0] mtestRresp;
bit [63:0] mtestWDataL;
bit [63:0] mtestRDataL;
axi_transaction pss_wr_transaction;
axi_transaction pss_rd_transaction;
axi_transaction reactive_transaction;
axi_transaction rd_payload_transaction;
axi_transaction wr_rand;
axi_transaction rd_rand;
axi_transaction wr_reactive;
axi_transaction rd_reactive;
axi_transaction wr_reactive2;
axi_transaction rd_reactive2;
axi_ready_gen bready_gen;
axi_ready_gen rready_gen;
axi_ready_gen awready_gen;
axi_ready_gen wready_gen;
axi_ready_gen arready_gen;
axi_ready_gen bready_gen2;
axi_ready_gen rready_gen2;
axi_ready_gen awready_gen2;
axi_ready_gen wready_gen2;
axi_ready_gen arready_gen2;
xil_axi_payload_byte data_mem[xil_axi_ulong];
lab7_axi4_lite_v1_0_bfm_1_master_0_0_mst_t mst_agent_0;
`BD_WRAPPER DUT(
.ARESETN(reset),
.ACLK(clock)
);
initial begin
mst_agent_0 = new("master vip agent",DUT.`BD_INST_NAME.master_0.inst.IF);//ms
mst_agent_0.vif_proxy.set_dummy_drive_type(XIL_AXI_VIF_DRIVE_NONE);
mst_agent_0.set_agent_tag("Master VIP");
mst_agent_0.set_verbosity(mst_agent_verbosity);
mst_agent_0.start_master();
$timeformat (-12, 1, " ps", 1);
end
initial begin
reset <= 1'b0;
#200ns;
reset <= 1'b1;
repeat (5) @(negedge clock);
end
always #5 clock <= ~clock;
initial begin
S_AXI_TEST ( );
#1ns;
$finish;
end
task automatic S_AXI_TEST;
begin
#1;
$display("Sequential write transfers example similar to AXI BFM WRITE_BURST method starts");
mtestID = 0;
mtestADDR = 64'h00000000;
mtestBurstLength = 0;
mtestDataSize = xil_axi_size_t'(xil_clog2(32/8));
mtestBurstType = XIL_AXI_BURST_TYPE_INCR;
mtestLOCK = XIL_AXI_ALOCK_NOLOCK;
mtestCacheType = 0;
mtestProtectionType = 0;
mtestRegion = 0;
mtestQOS = 0;
result_slave = 1;
mtestWDataL[31:0] = 32'h00000001;
for(int i = 0; i < 4;i++) begin
S00_AXI_test_data[i] <= mtestWDataL[31:0];
mst_agent_0.AXI4LITE_WRITE_BURST(
mtestADDR,
mtestProtectionType,
mtestWDataL,
mtestBresp
);
mtestWDataL[31:0] = mtestWDataL[31:0] + 1;
mtestADDR = mtestADDR + 64'h4;
end
$display("Sequential write transfers example similar to AXI BFM WRITE_BURST method completes");
$display("Sequential read transfers example similar to AXI BFM READ_BURST method starts");
mtestID = 0;
mtestADDR = 64'h00000000;
mtestBurstLength = 0;
mtestDataSize = xil_axi_size_t'(xil_clog2(32/8));
mtestBurstType = XIL_AXI_BURST_TYPE_INCR;
mtestLOCK = XIL_AXI_ALOCK_NOLOCK;
mtestCacheType = 0;
mtestProtectionType = 0;
mtestRegion = 0;
mtestQOS = 0;
for(int i = 0; i < 4;i++) begin
mst_agent_0.AXI4LITE_READ_BURST(
mtestADDR,
mtestProtectionType,
mtestRDataL,
mtestRresp
);
mtestADDR = mtestADDR + 64'h4;
COMPARE_DATA(S00_AXI_test_data[i],mtestRDataL);
end
$display("Sequential read transfers example similar to AXI BFM READ_BURST method completes");
$display("Sequential read transfers example similar to AXI VIP READ_BURST method completes");
$display("---------------------------------------------------------");
$display("EXAMPLE TEST S00_AXI: PTGEN_TEST_FINISHED!");
if ( result_slave ) begin
$display("PTGEN_TEST: PASSED!");
end else begin
$display("PTGEN_TEST: FAILED!");
end
$display("---------------------------------------------------------");
end
endtask
endmodule
이제 AXI를 펼쳐보자
여기서 Outstanding 개념이 나오는데
AXI Performance 향상에 주요 개념이다.
간단하게 짚고 넘어가면
Template Code에서는
Multiple Outstanding을 지원하지 않는다.
정도로 가볍게 확인해볼 수 있다.
자 이제 하나씩 살펴보자
<Write Address>
두개가 1로 set되는 handshake구간의 값을 확인하면 된다.
거기서 쓰고자 하는 값이 있고
<Write Response>
그 값이 잘 쓰여졌는지에 대한 Response를 보내주고
response의 값이 0이라는 것은 정상이라는 것
즉 현재 시뮬레이션은 모두 0
<Write Address>
address는 이렇게 주고있고
(왜 4씩 증가하냐? 4바이트라서.
AXI의 address는 Byte단위라서
4바이트씩 접근해야
0,1,2,3을 순차적으로 접근할 수 있는 것)
이제는 Read
여기까지의 과정을 통해서
개념과 waveform의 matching을 마쳤다.
---
이제부터는 code review
---
커스터마이징을 위한 유저 파라미터 영역도 뚫려있다.
이런 코멘트 영역이 많다.
먼저 hierachy 를 보자.
32비트 4레지스터
5개의 채널의 시그널
그리고나서 Instantiation이 되어있으며
이 모듈들이 실제 AXI 역할을 수행
---
clk, reset을 시작으로
in out port 들이 선언되어있다.
권한관련 내용 - 미사용
wstrb는 write strobe라는 내용인데 조금 생소함
4바이트를 바이트 단위로 write를 할 수 있으며
one hot encoding으로 동작한다.
조금 복잡한 내용이라 우리는 우선 전체를 사용.
---
레지스터 선언
신호들을 캡처 또는 래칭할 때 사용
이 부분은 address 부분에서 하위 2bits를 안보겠다는 이야기
(레지스터 접근할때 4씩 증가하기 때문에, 4 이전의 2bits는 필요가 없음.)
이 레지스터들이 우리가 쓰는 레지스터
포트와 신호들이 assign 되어있다.
그 다음부터의 @always 들이 실질적인 동작
여기서부터는 그냥 베릴로그임.
어떤 상황일때 어떤 레지스터를 이용할거냐는 부분도 있고
여기서부터는 read
원하는 레지스터의 값을 뽑아서 본다.
마지막으로 read data 출력
---
마무리
'적극적 생각 > FPGA' 카테고리의 다른 글
gigglehd - xilinx, zynq, zybo (0) | 2022.07.16 |
---|---|
0716 - 섹션3 - AXI4Lite (0) | 2022.07.16 |
0715 - 섹션3 - AXI4-Lite Interface 개념 (0) | 2022.07.15 |
0715 - 섹션2 - 기초 PL영역을 활용한 LED Blinking (2) (0) | 2022.07.15 |
0714 - 섹션2 - 기초 PL영역을 활용한 LED Blinking (0) | 2022.07.14 |