当前位置:   article > 正文

Xilinx AXI4 协议_axi4协议

axi4协议

一、AXI4协议介绍

AXI4 相对复杂,但 SOC 开发者必须掌握。AXI 协议的具体内容可参考 Xilinx UG761 AXI Reference Guide。

在这里我们简单了解一下。

AXI4 所采用的是一种 READY,VALID 握手通信机制,即主从模块进行数据通信前,先根

据操作对各所用到的数据、地址通道进行握手。主要操作包括传输发送者 A 等到传输接受者 B

的 READY 信号后,A 将数据与 VALID 信号同时发送给 B,这是一种典型的握手机制。

AXI 总线分为五个通道:

 读地址通道,包含 ARVALID, ARADDR, ARREADY 信号;

 写地址通道,包含 AWVALID,AWADDR, AWREADY 信号;

 读数据通道,包含 RVALID, RDATA, RREADY, RRESP 信号;

 写数据通道,包含 WVALID, WDATA,WSTRB, WREADY 信号;

 写应答通道,包含 BVALID, BRESP, BREADY 信号;

 系统通道,包含:ACLK,ARESETN 信号;

其中 ACLK 为 axi 总线时钟,ARESETN 是 axi 总线复位信号,低电平有效;读写数据与读

写地址类信号宽度都为 32bit;READY 与 VALID 是对应的通道握手信号;WSTRB 信号为 1 的

bit 对应 WDATA 有效数据字节,WSTRB 宽度是 32bit/8=4bit;BRESP 与 RRESP 分别为写回

应信号,读回应信号,宽度都为 2bit,‘h0 代表成功,其他为错误。

读操作顺序为主与从进行读地址通道握手并传输地址内容,然后在读数据通道握手并传输

所读内容以及读取操作的回应,时钟上升沿有效。如图所示:

写操作顺序为主与从进行写地址通道握手并传输地址内容,然后在写数据通道握手并传输

所读内容,最后再写回应通道握手,并传输写回应数据,时钟上升沿有效。如图所示:

二、axi协议应用举例

在我们不擅长写 FPGA 的一些代码时我们往往要借鉴别人的代码或者使用 IP core。在这里

笔者从 github 上找到一个 AXI master 的代码,地址是

https://github.com/aquaxis/IPCORE/tree/master/aq_axi_vdma。这个工程是一个自己写的

VDMA,里面包含了大量可参考的代码。笔者这里主要使用了 aq_axi_master.v 这个代码用于

AXI master 读写操作。借鉴别人代码有时会节省很多时间,但如果不能理解的去借鉴,出现问

题了很难解决。aq_axi_master.v 代码如下,有部分修改。

  1. /*
  2. * Copyright (C)2014-2015 AQUAXIS TECHNOLOGY.
  3. * Don't remove this header.
  4. * When you use this source, there is a need to inherit this header.
  5. *
  6. * License
  7. * For no commercial -
  8. * License: The Open Software License 3.0
  9. * License URI: http://www.opensource.org/licenses/OSL-3.0
  10. *
  11. * For commmercial -
  12. * License: AQUAXIS License 1.0
  13. * License URI: http://www.aquaxis.com/licenses
  14. *
  15. * For further information please contact.
  16. * URI: http://www.aquaxis.com/
  17. * E-Mail: info(at)aquaxis.com
  18. */
  19. //
  20. // Company:
  21. // Engineer:
  22. //
  23. // Create Date: 2016/11/17 10:27:06
  24. // Design Name:
  25. // Module Name: mem_test
  26. // Project Name:
  27. // Target Devices:
  28. // Tool Versions:
  29. // Description:
  30. //
  31. // Dependencies:
  32. //
  33. // Revision:
  34. // Revision 0.01 - File Created
  35. // Additional Comments:
  36. //
  37. //
  38. module aq_axi_master(
  39. // Reset, Clock
  40. input ARESETN,
  41. input ACLK,
  42. // Master Write Address
  43. output[0:0] M_AXI_AWID,
  44. output[31:0] M_AXI_AWADDR,
  45. output[7:0] M_AXI_AWLEN,// Burst Length: 0-255
  46. output[2:0] M_AXI_AWSIZE,// Burst Size: Fixed 2'b011
  47. output[1:0] M_AXI_AWBURST,// Burst Type: Fixed 2'b01(Incremental Burst)
  48. output M_AXI_AWLOCK,// Lock: Fixed 2'b00
  49. output[3:0] M_AXI_AWCACHE,// Cache: Fiex 2'b0011
  50. output[2:0] M_AXI_AWPROT,// Protect: Fixed 2'b000
  51. output[3:0] M_AXI_AWQOS,// QoS: Fixed 2'b0000
  52. output[0:0] M_AXI_AWUSER,// User: Fixed 32'd0
  53. output M_AXI_AWVALID,
  54. input M_AXI_AWREADY,
  55. // Master Write Data
  56. output[63:0] M_AXI_WDATA,
  57. output[7:0] M_AXI_WSTRB,
  58. output M_AXI_WLAST,
  59. output[0:0] M_AXI_WUSER,
  60. output M_AXI_WVALID,
  61. input M_AXI_WREADY,
  62. // Master Write Response
  63. input[0:0] M_AXI_BID,
  64. input[1:0] M_AXI_BRESP,
  65. input[0:0] M_AXI_BUSER,
  66. input M_AXI_BVALID,
  67. output M_AXI_BREADY,
  68. // Master Read Address
  69. output[0:0] M_AXI_ARID,
  70. output[31:0] M_AXI_ARADDR,
  71. output[7:0] M_AXI_ARLEN,
  72. output[2:0] M_AXI_ARSIZE,
  73. output[1:0] M_AXI_ARBURST,
  74. output[1:0] M_AXI_ARLOCK,
  75. output[3:0] M_AXI_ARCACHE,
  76. output[2:0] M_AXI_ARPROT,
  77. output[3:0] M_AXI_ARQOS,
  78. output[0:0] M_AXI_ARUSER,
  79. output M_AXI_ARVALID,
  80. input M_AXI_ARREADY,
  81. // Master Read Data
  82. input[0:0] M_AXI_RID,
  83. input[63:0] M_AXI_RDATA,
  84. input[1:0] M_AXI_RRESP,
  85. input M_AXI_RLAST,
  86. input[0:0] M_AXI_RUSER,
  87. input M_AXI_RVALID,
  88. output M_AXI_RREADY,
  89. // Local Bus
  90. input MASTER_RST,
  91. input WR_START,
  92. input[31:0] WR_ADRS,
  93. input[31:0] WR_LEN,
  94. output WR_READY,
  95. output WR_FIFO_RE,
  96. input WR_FIFO_EMPTY,
  97. input WR_FIFO_AEMPTY,
  98. input[63:0] WR_FIFO_DATA,
  99. output WR_DONE,
  100. input RD_START,
  101. input[31:0] RD_ADRS,
  102. input[31:0] RD_LEN,
  103. output RD_READY,
  104. output RD_FIFO_WE,
  105. input RD_FIFO_FULL,
  106. input RD_FIFO_AFULL,
  107. output[63:0] RD_FIFO_DATA,
  108. output RD_DONE,
  109. output[31:0] DEBUG
  110. );
  111. localparam S_WR_IDLE =3'd0;
  112. localparam S_WA_WAIT =3'd1;
  113. localparam S_WA_START =3'd2;
  114. localparam S_WD_WAIT =3'd3;
  115. localparam S_WD_PROC =3'd4;
  116. localparam S_WR_WAIT =3'd5;
  117. localparam S_WR_DONE =3'd6;
  118. reg[2:0] wr_state;
  119. reg[31:0] reg_wr_adrs;
  120. reg[31:0] reg_wr_len;
  121. reg reg_awvalid, reg_wvalid, reg_w_last;
  122. reg[7:0] reg_w_len;
  123. reg[7:0] reg_w_stb;
  124. reg[1:0] reg_wr_status;
  125. reg[3:0] reg_w_count, reg_r_count;
  126. reg[7:0] rd_chkdata, wr_chkdata;
  127. reg[1:0] resp;
  128. reg rd_first_data;
  129. reg rd_fifo_enable;
  130. reg[31:0] rd_fifo_cnt;
  131. assign WR_DONE =(wr_state == S_WR_DONE);
  132. assign WR_FIFO_RE = rd_first_data |(reg_wvalid &~WR_FIFO_EMPTY &
  133. M_AXI_WREADY & rd_fifo_enable);
  134. //assign WR_FIFO_RE = reg_wvalid & ~WR_FIFO_EMPTY & M_AXI_WREADY;
  135. always@(posedge ACLK ornegedge ARESETN)
  136. begin
  137. if(!ARESETN)
  138. rd_fifo_cnt <=32'd0;
  139. elseif(WR_FIFO_RE)
  140. rd_fifo_cnt <= rd_fifo_cnt +32'd1;
  141. elseif(wr_state == S_WR_IDLE)
  142. rd_fifo_cnt <=32'd0;
  143. end
  144. always@(posedge ACLK ornegedge ARESETN)
  145. begin
  146. if(!ARESETN)
  147. rd_fifo_enable <=1'b0;
  148. elseif(wr_state == S_WR_IDLE && WR_START)
  149. rd_fifo_enable <=1'b1;
  150. elseif(WR_FIFO_RE &&(rd_fifo_cnt == RD_LEN[31:3]-32'd1))
  151. rd_fifo_enable <=1'b0;
  152. end
  153. // Write State
  154. always@(posedge ACLK ornegedge ARESETN)begin
  155. if(!ARESETN)begin
  156. wr_state <= S_WR_IDLE;
  157. reg_wr_adrs[31:0]<=32'd0;
  158. reg_wr_len[31:0]<=32'd0;
  159. reg_awvalid <=1'b0;
  160. reg_wvalid <=1'b0;
  161. reg_w_last <=1'b0;
  162. reg_w_len[7:0]<=8'd0;
  163. reg_w_stb[7:0]<=8'd0;
  164. reg_wr_status[1:0]<=2'd0;
  165. reg_w_count[3:0]<=4'd0;
  166. reg_r_count[3:0]<=4'd0;
  167. wr_chkdata <=8'd0;
  168. rd_chkdata <=8'd0;
  169. resp <=2'd0;
  170. rd_first_data <=1'b0;
  171. endelsebegin
  172. if(MASTER_RST)begin
  173. wr_state <= S_WR_IDLE;
  174. endelsebegin
  175. case(wr_state)
  176. S_WR_IDLE:begin
  177. if(WR_START)begin
  178. wr_state <= S_WA_WAIT;
  179. reg_wr_adrs[31:0]<= WR_ADRS[31:0];
  180. reg_wr_len[31:0]<= WR_LEN[31:0]-32'd1;
  181. rd_first_data <=1'b1;
  182. end
  183. reg_awvalid <=1'b0;
  184. reg_wvalid <=1'b0;
  185. reg_w_last <=1'b0;
  186. reg_w_len[7:0]<=8'd0;
  187. reg_w_stb[7:0]<=8'd0;
  188. reg_wr_status[1:0]<=2'd0;
  189. end
  190. S_WA_WAIT:begin
  191. if(!WR_FIFO_AEMPTY |(reg_wr_len[31:11]==21'd0))begin
  192. wr_state <= S_WA_START;
  193. end
  194. rd_first_data <=1'b0;
  195. end
  196. S_WA_START:begin
  197. wr_state <= S_WD_WAIT;
  198. reg_awvalid <=1'b1;
  199. reg_wr_len[31:11]<= reg_wr_len[31:11]-21'd1;
  200. if(reg_wr_len[31:11]!=21'd0)begin
  201. reg_w_len[7:0]<=8'hFF;
  202. reg_w_last <=1'b0;
  203. reg_w_stb[7:0]<=8'hFF;
  204. endelsebegin
  205. reg_w_len[7:0]<= reg_wr_len[10:3];
  206. reg_w_last <=1'b1;
  207. reg_w_stb[7:0]<=8'hFF;
  208. /*
  209. case(reg_wr_len[2:0]) begin
  210. case 3'd0: reg_w_stb[7:0] <= 8'b0000_0000;
  211. case 3'd1: reg_w_stb[7:0] <= 8'b0000_0001;
  212. case 3'd2: reg_w_stb[7:0] <= 8'b0000_0011;
  213. case 3'd3: reg_w_stb[7:0] <= 8'b0000_0111;
  214. case 3'd4: reg_w_stb[7:0] <= 8'b0000_1111;
  215. case 3'd5: reg_w_stb[7:0] <= 8'b0001_1111;
  216. case 3'd6: reg_w_stb[7:0] <= 8'b0011_1111;
  217. case 3'd7: reg_w_stb[7:0] <= 8'b0111_1111;
  218. default: reg_w_stb[7:0] <= 8'b1111_1111;
  219. endcase
  220. */
  221. end
  222. end
  223. S_WD_WAIT:begin
  224. if(M_AXI_AWREADY)begin
  225. wr_state <= S_WD_PROC;
  226. reg_awvalid <=1'b0;
  227. reg_wvalid <=1'b1;
  228. end
  229. end
  230. S_WD_PROC:begin
  231. if(M_AXI_WREADY &~WR_FIFO_EMPTY)begin
  232. if(reg_w_len[7:0]==8'd0)begin
  233. wr_state <= S_WR_WAIT;
  234. reg_wvalid <=1'b0;
  235. reg_w_stb[7:0]<=8'h00;
  236. endelsebegin
  237. reg_w_len[7:0]<= reg_w_len[7:0]-8'd1;
  238. end
  239. end
  240. end
  241. S_WR_WAIT:begin
  242. if(M_AXI_BVALID)begin
  243. reg_wr_status[1:0]<= reg_wr_status[1:0]| M_AXI_BRESP[1:0];
  244. if(reg_w_last)begin
  245. wr_state <= S_WR_DONE;
  246. endelsebegin
  247. wr_state <= S_WA_WAIT;
  248. reg_wr_adrs[31:0]<= reg_wr_adrs[31:0]+32'd2048;
  249. end
  250. end
  251. end
  252. S_WR_DONE:begin
  253. wr_state <= S_WR_IDLE;
  254. end
  255. default:begin
  256. wr_state <= S_WR_IDLE;
  257. end
  258. endcase
  259. /*
  260. if(WR_FIFO_RE) begin
  261. reg_w_count[3:0] <= reg_w_count[3:0] + 4'd1;
  262. end
  263. if(RD_FIFO_WE)begin
  264. reg_r_count[3:0] <= reg_r_count[3:0] + 4'd1;
  265. end
  266. if(M_AXI_AWREADY & M_AXI_AWVALID) begin
  267. wr_chkdata <= 8'hEE;
  268. end else if(M_AXI_WSTRB[7] & M_AXI_WVALID) begin
  269. wr_chkdata <= WR_FIFO_DATA[63:56];
  270. end
  271. if(M_AXI_AWREADY & M_AXI_AWVALID) begin
  272. rd_chkdata <= 8'hDD;
  273. end else if(M_AXI_WSTRB[7] & M_AXI_WREADY) begin
  274. rd_chkdata <= WR_FIFO_DATA[63:56];
  275. end
  276. if(M_AXI_BVALID & M_AXI_BREADY) begin
  277. resp <= M_AXI_BRESP;
  278. end
  279. */
  280. end
  281. end
  282. end
  283. assign M_AXI_AWID =1'b0;
  284. assign M_AXI_AWADDR[31:0]= reg_wr_adrs[31:0];
  285. assign M_AXI_AWLEN[7:0]= reg_w_len[7:0];
  286. assign M_AXI_AWSIZE[2:0]=2'b011;
  287. assign M_AXI_AWBURST[1:0]=2'b01;
  288. assign M_AXI_AWLOCK =1'b0;
  289. assign M_AXI_AWCACHE[3:0]=4'b0011;
  290. assign M_AXI_AWPROT[2:0]=3'b000;
  291. assign M_AXI_AWQOS[3:0]=4'b0000;
  292. assign M_AXI_AWUSER[0]=1'b1;
  293. assign M_AXI_AWVALID = reg_awvalid;
  294. assign M_AXI_WDATA[63:0]= WR_FIFO_DATA[63:0];
  295. // assign M_AXI_WSTRB[7:0] = (reg_w_len[7:0] ==
  296. 8'd0)?reg_w_stb[7:0]:8'hFF;
  297. // assign M_AXI_WSTRB[7:0] = (wr_state == S_WD_PROC)?8'hFF:8'h00;
  298. assign M_AXI_WSTRB[7:0]=(reg_wvalid &~WR_FIFO_EMPTY)?8'hFF:8'h00;
  299. assign M_AXI_WLAST =(reg_w_len[7:0]==8'd0)?1'b1:1'b0;
  300. assign M_AXI_WUSER =1;
  301. assign M_AXI_WVALID = reg_wvalid &~WR_FIFO_EMPTY;
  302. // assign M_AXI_WVALID = (wr_state == S_WD_PROC)?1'b1:1'b0;
  303. assign M_AXI_BREADY = M_AXI_BVALID;
  304. assign WR_READY =(wr_state == S_WR_IDLE)?1'b1:1'b0;
  305. // assign WR_FIFO_RE = (wr_state == S_WD_PROC)?M_AXI_WREADY:1'b0;
  306. localparam S_RD_IDLE =3'd0;
  307. localparam S_RA_WAIT =3'd1;
  308. localparam S_RA_START =3'd2;
  309. localparam S_RD_WAIT =3'd3;
  310. localparam S_RD_PROC =3'd4;
  311. localparam S_RD_DONE =3'd5;
  312. reg[2:0] rd_state;
  313. reg[31:0] reg_rd_adrs;
  314. reg[31:0] reg_rd_len;
  315. reg reg_arvalid, reg_r_last;
  316. reg[7:0] reg_r_len;
  317. assign RD_DONE =(rd_state == S_RD_DONE);
  318. // Read State
  319. always@(posedge ACLK ornegedge ARESETN)begin
  320. if(!ARESETN)begin
  321. rd_state <= S_RD_IDLE;
  322. reg_rd_adrs[31:0]<=32'd0;
  323. reg_rd_len[31:0]<=32'd0;
  324. reg_arvalid <=1'b0;
  325. reg_r_len[7:0]<=8'd0;
  326. endelsebegin
  327. case(rd_state)
  328. S_RD_IDLE:begin
  329. if(RD_START)begin
  330. rd_state <= S_RA_WAIT;
  331. reg_rd_adrs[31:0]<= RD_ADRS[31:0];
  332. reg_rd_len[31:0]<= RD_LEN[31:0]-32'd1;
  333. end
  334. reg_arvalid <=1'b0;
  335. reg_r_len[7:0]<=8'd0;
  336. end
  337. S_RA_WAIT:begin
  338. if(~RD_FIFO_AFULL)begin
  339. rd_state <= S_RA_START;
  340. end
  341. end
  342. S_RA_START:begin
  343. rd_state <= S_RD_WAIT;
  344. reg_arvalid <=1'b1;
  345. reg_rd_len[31:11]<= reg_rd_len[31:11]-21'd1;
  346. if(reg_rd_len[31:11]!=21'd0)begin
  347. reg_r_last <=1'b0;
  348. reg_r_len[7:0]<=8'd255;
  349. endelsebegin
  350. reg_r_last <=1'b1;
  351. reg_r_len[7:0]<= reg_rd_len[10:3];
  352. end
  353. end
  354. S_RD_WAIT:begin
  355. if(M_AXI_ARREADY)begin
  356. rd_state <= S_RD_PROC;
  357. reg_arvalid <=1'b0;
  358. end
  359. end
  360. S_RD_PROC:begin
  361. if(M_AXI_RVALID)begin
  362. if(M_AXI_RLAST)begin
  363. if(reg_r_last)begin
  364. rd_state <= S_RD_DONE;
  365. endelsebegin
  366. rd_state <= S_RA_WAIT;
  367. reg_rd_adrs[31:0]<= reg_rd_adrs[31:0]+32'd2048;
  368. end
  369. endelsebegin
  370. reg_r_len[7:0]<= reg_r_len[7:0]-8'd1;
  371. end
  372. end
  373. end
  374. S_RD_DONE:begin
  375. rd_state <= S_RD_IDLE;
  376. end
  377. endcase
  378. end
  379. end
  380. // Master Read Address
  381. assign M_AXI_ARID =1'b0;
  382. assign M_AXI_ARADDR[31:0]= reg_rd_adrs[31:0];
  383. assign M_AXI_ARLEN[7:0]= reg_r_len[7:0];
  384. assign M_AXI_ARSIZE[2:0]=3'b011;
  385. assign M_AXI_ARBURST[1:0]=2'b01;
  386. assign M_AXI_ARLOCK =1'b0;
  387. assign M_AXI_ARCACHE[3:0]=4'b0011;
  388. assign M_AXI_ARPROT[2:0]=3'b000;
  389. assign M_AXI_ARQOS[3:0]=4'b0000;
  390. assign M_AXI_ARUSER[0]=1'b1;
  391. assign M_AXI_ARVALID = reg_arvalid;
  392. assign M_AXI_RREADY = M_AXI_RVALID &~RD_FIFO_FULL;
  393. assign RD_READY =(rd_state == S_RD_IDLE)?1'b1:1'b0;
  394. assign RD_FIFO_WE = M_AXI_RVALID;
  395. assign RD_FIFO_DATA[63:0]= M_AXI_RDATA[63:0];
  396. assign DEBUG[31:0]={reg_wr_len[31:8],
  397. 1'd0, wr_state[2:0],1'd0, rd_state[2:0]};
  398. endmodule

三、工程下载

下面有一个关于 PL 读写 PS 端 DDR 数据的真实工程,本人已经完全验证过了,即包括了ZYNQ处理器的搭建,逻辑封装,又包括PS端SDK的测试代码。

PL 读写PS 端 DDR 数据

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/539176
推荐阅读
相关标签
  

闽ICP备14008679号