最简单的IP核,AXI4_lite GPIO 编写
GPIO对于相对来说算是最简单的一个功能IP了,就只是单纯的输出0或1,复杂点的就是GPIO的三态输出。不过熟悉GPIO的原理后,用Verilog来实现并不困难,难度点主要是寄存器的分配计算,可能计算起来确实挺麻烦。
话不多说,直接上代码:
顶层文件Axi4_Gpio.v,例化了上一篇文章讲到的Axi4_lite_slave.v及接下来的Gpio_ctrl.v模块。
1 //************************************************************************** 2 // *** file name : Axi4_Gpio.v 3 // *** version : 1.0 4 // *** Description : AXI4-Lite GPIO 5 // *** Blogs : https://www.cnblogs.com/WenGalois123/ 6 // *** Author : Galois_V 7 // *** Date : 2022.3.31 8 // *** Changes : 9 //************************************************************************** 10 `timescale 1ns/1ps 11 module Axi4_Gpio 12 #( 13 parameter IO_NUM = 64 14 ) 15 ( 16 input wire i_s_axi_aclk , 17 input wire i_s_axi_aresetn , 18 input wire [31:0] i_s_axi_awaddr , 19 input wire [2:0] i_s_axi_awprot , 20 input wire i_s_axi_awvalid , 21 output wire o_s_axi_awready , 22 input wire [31:0] i_s_axi_wdata , 23 input wire [3:0] i_s_axi_wstrb , 24 input wire i_s_axi_wvalid , 25 output wire o_s_axi_wready , 26 output wire [1:0] o_s_axi_bresp , 27 output wire o_s_axi_bvalid , 28 input wire i_s_axi_bready , 29 input wire [31:0] i_s_axi_araddr , 30 input wire [2:0] i_s_axi_arprot , 31 input wire i_s_axi_arvalid , 32 output wire o_s_axi_arready , 33 output wire [31:0] o_s_axi_rdata , 34 output wire [1:0] o_s_axi_rresp , 35 output wire o_s_axi_rvalid , 36 input wire i_s_axi_rready , 37 input [IO_NUM-1:0] i_gpio_if_i , 38 output [IO_NUM-1:0] o_gpio_if_o , 39 output [IO_NUM-1:0] o_gpio_if_t 40 ); 41 42 wire [31:0] w_ctrl_wr_addr ; 43 wire w_ctrl_wr_en ; 44 wire [31:0] w_ctrl_wr_data ; 45 wire [3:0] w_ctrl_wr_mask ; 46 wire [31:0] w_ctrl_rd_addr ; 47 wire [31:0] w_ctrl_rd_data ; 48 49 /******************************************************************************\ 50 Axi4_lite_slave interface 51 \******************************************************************************/ 52 Axi4_lite_slave u_Axi4_lite_slave 53 ( 54 .i_s_axi_aclk (i_s_axi_aclk ), 55 .i_s_axi_aresetn (i_s_axi_aresetn ), 56 .i_s_axi_awaddr (i_s_axi_awaddr ), 57 .i_s_axi_awprot (i_s_axi_awprot ), 58 .i_s_axi_awvalid (i_s_axi_awvalid ), 59 .o_s_axi_awready (o_s_axi_awready ), 60 .i_s_axi_wdata (i_s_axi_wdata ), 61 .i_s_axi_wstrb (i_s_axi_wstrb ), 62 .i_s_axi_wvalid (i_s_axi_wvalid ), 63 .o_s_axi_wready (o_s_axi_wready ), 64 .o_s_axi_bresp (o_s_axi_bresp ), 65 .o_s_axi_bvalid (o_s_axi_bvalid ), 66 .i_s_axi_bready (i_s_axi_bready ), 67 .i_s_axi_araddr (i_s_axi_araddr ), 68 .i_s_axi_arprot (i_s_axi_arprot ), 69 .i_s_axi_arvalid (i_s_axi_arvalid ), 70 .o_s_axi_arready (o_s_axi_arready ), 71 .o_s_axi_rdata (o_s_axi_rdata ), 72 .o_s_axi_rresp (o_s_axi_rresp ), 73 .o_s_axi_rvalid (o_s_axi_rvalid ), 74 .i_s_axi_rready (i_s_axi_rready ), 75 .o_ctrl_wr_addr (w_ctrl_wr_addr ), 76 .o_ctrl_wr_en (w_ctrl_wr_en ), 77 .o_ctrl_wr_data (w_ctrl_wr_data ), 78 .o_ctrl_wr_mask (w_ctrl_wr_mask ), 79 .o_ctrl_rd_addr (w_ctrl_rd_addr ), 80 .i_ctrl_rd_data (w_ctrl_rd_data ) 81 ); 82 83 /******************************************************************************\ 84 GPIO control 85 \******************************************************************************/ 86 Gpio_ctrl 87 #( 88 .IO_NUM (IO_NUM ) 89 ) 90 u_Gpio_ctrl 91 ( 92 .i_s_axi_aclk (i_s_axi_aclk ), 93 .i_s_axi_aresetn (i_s_axi_aresetn ), 94 .i_ctrl_wr_addr (w_ctrl_wr_addr ), 95 .i_ctrl_wr_en (w_ctrl_wr_en ), 96 .i_ctrl_wr_data (w_ctrl_wr_data ), 97 .i_ctrl_wr_mask (w_ctrl_wr_mask ), 98 .i_ctrl_rd_addr (w_ctrl_rd_addr ), 99 .o_ctrl_rd_data (w_ctrl_rd_data ), 100 .i_gpio_if_i (i_gpio_if_i ), 101 .o_gpio_if_o (o_gpio_if_o ), 102 .o_gpio_if_t (o_gpio_if_t ) 103 ); 104 105 endmodule
Axi4_lite_slave.v
1 //************************************************************************** 2 // *** file name : Axi4_lite_slave.v 3 // *** version : 1.0 4 // *** Description : AXI4-Lite slave interface 5 // *** Blogs : https://www.cnblogs.com/WenGalois123/ 6 // *** Author : Galois_V 7 // *** Date : 2022.3.29 8 // *** Changes : 9 //************************************************************************** 10 `timescale 1ns/1ps 11 module Axi4_lite_slave 12 ( 13 input wire i_s_axi_aclk , 14 input wire i_s_axi_aresetn , 15 input wire [31:0] i_s_axi_awaddr , 16 input wire [2:0] i_s_axi_awprot , 17 input wire i_s_axi_awvalid , 18 output reg o_s_axi_awready , 19 input wire [31:0] i_s_axi_wdata , 20 input wire [3:0] i_s_axi_wstrb , 21 input wire i_s_axi_wvalid , 22 output reg o_s_axi_wready , 23 output wire [1:0] o_s_axi_bresp , 24 output reg o_s_axi_bvalid , 25 input wire i_s_axi_bready , 26 input wire [31:0] i_s_axi_araddr , 27 input wire [2:0] i_s_axi_arprot , 28 input wire i_s_axi_arvalid , 29 output reg o_s_axi_arready , 30 output reg [31:0] o_s_axi_rdata , 31 output wire [1:0] o_s_axi_rresp , 32 output reg o_s_axi_rvalid , 33 input wire i_s_axi_rready , 34 output reg [31:0] o_ctrl_wr_addr , 35 output wire o_ctrl_wr_en , 36 output wire [31:0] o_ctrl_wr_data , 37 output wire [3:0] o_ctrl_wr_mask , 38 output reg [31:0] o_ctrl_rd_addr , 39 input wire [31:0] i_ctrl_rd_data 40 ); 41 42 reg r_wr_en; 43 reg r_rd_en; 44 wire w_raddr_en; 45 /******************************************************************************\ 46 Write Address operation 47 \******************************************************************************/ 48 always@(posedge i_s_axi_aclk) 49 begin 50 if(~i_s_axi_aresetn) 51 begin 52 r_wr_en <= 1'b1; 53 end 54 else if(o_ctrl_wr_en) 55 begin 56 r_wr_en <= 1'b0; 57 end 58 else if(o_s_axi_bvalid & i_s_axi_bready) 59 begin 60 r_wr_en <= 1'b1; 61 end 62 end 63 64 always@(posedge i_s_axi_aclk) 65 begin 66 if(~i_s_axi_aresetn) 67 begin 68 o_s_axi_awready <= 'd0; 69 end 70 else if(~o_s_axi_awready & i_s_axi_wvalid & i_s_axi_awvalid & r_wr_en) 71 begin 72 o_s_axi_awready <= 1'b1; 73 end 74 else 75 begin 76 o_s_axi_awready <= 'd0; 77 end 78 end 79 80 always@(posedge i_s_axi_aclk) 81 begin 82 if(~i_s_axi_aresetn) 83 begin 84 o_ctrl_wr_addr <= 'd0; 85 end 86 else if(~o_s_axi_awready & i_s_axi_awvalid & i_s_axi_wvalid) 87 begin 88 o_ctrl_wr_addr <= i_s_axi_awaddr; 89 end 90 end 91 /******************************************************************************\ 92 Write data operation 93 \******************************************************************************/ 94 always@(posedge i_s_axi_aclk) 95 begin 96 if(~i_s_axi_aresetn) 97 begin 98 o_s_axi_wready <= 'd0; 99 end 100 else if(~o_s_axi_wready & i_s_axi_wvalid & i_s_axi_awvalid & r_wr_en) 101 begin 102 o_s_axi_wready <= 1'b1; 103 end 104 else 105 begin 106 o_s_axi_wready <= 'd0; 107 end 108 end 109 110 assign o_ctrl_wr_data = i_s_axi_wdata; 111 assign o_ctrl_wr_mask = i_s_axi_wstrb; 112 assign o_ctrl_wr_en = o_s_axi_awready & i_s_axi_awvalid & i_s_axi_wvalid & o_s_axi_wready; 113 114 /******************************************************************************\ 115 write response and response 116 \******************************************************************************/ 117 always@(posedge i_s_axi_aclk) 118 begin 119 if(~i_s_axi_aresetn) 120 begin 121 o_s_axi_bvalid <= 'd0; 122 end 123 else if(~o_s_axi_bvalid & o_ctrl_wr_en) 124 begin 125 o_s_axi_bvalid <= 1'b1; 126 end 127 else if(o_s_axi_bvalid & i_s_axi_bready) 128 begin 129 o_s_axi_bvalid <= 'd0; 130 end 131 end 132 133 /******************************************************************************\ 134 Read Address operation 135 \******************************************************************************/ 136 always@(posedge i_s_axi_aclk) 137 begin 138 if(~i_s_axi_aresetn) 139 begin 140 r_rd_en <= 1'b1; 141 end 142 else if(w_raddr_en) 143 begin 144 r_rd_en <= 1'b0; 145 end 146 else if(o_s_axi_rvalid & i_s_axi_rready) 147 begin 148 r_rd_en <= 1'b1; 149 end 150 end 151 152 always@(posedge i_s_axi_aclk) 153 begin 154 if(~i_s_axi_aresetn) 155 begin 156 o_s_axi_arready <= 'd0; 157 end 158 else if(~o_s_axi_arready & i_s_axi_arvalid & r_rd_en) 159 begin 160 o_s_axi_arready <= 1'b1; 161 end 162 else 163 begin 164 o_s_axi_arready <= 'd0; 165 end 166 end 167 168 always@(posedge i_s_axi_aclk) 169 begin 170 if(~i_s_axi_aresetn) 171 begin 172 o_ctrl_rd_addr <= 'd0; 173 end 174 else if(~o_s_axi_arready & i_s_axi_arvalid) 175 begin 176 o_ctrl_rd_addr <= i_s_axi_araddr; 177 end 178 end 179 180 assign w_raddr_en = o_s_axi_arready & i_s_axi_arvalid & (~o_s_axi_rvalid); 181 /******************************************************************************\ 182 Read data operation 183 \******************************************************************************/ 184 always@(posedge i_s_axi_aclk) 185 begin 186 if(~i_s_axi_aresetn) 187 begin 188 o_s_axi_rvalid <= 'd0; 189 end 190 else if(w_raddr_en) 191 begin 192 o_s_axi_rvalid <= 1'b1; 193 end 194 else if(o_s_axi_rvalid & i_s_axi_rready) 195 begin 196 o_s_axi_rvalid <= 'd0; 197 end 198 end 199 200 always@(posedge i_s_axi_aclk) 201 begin 202 if(~i_s_axi_aresetn) 203 begin 204 o_s_axi_rdata <= 'd0; 205 end 206 else if(w_raddr_en) 207 begin 208 o_s_axi_rdata <= i_ctrl_rd_data; 209 end 210 end 211 212 213 assign o_s_axi_rresp = 2'b00; 214 assign o_s_axi_bresp = 2'b00; 215 216 endmodule
Gpio_ctrl.v
1 //************************************************************************** 2 // *** file name : Gpio_ctrl.v 3 // *** version : 1.0 4 // *** Description : Gpio control 5 // *** Blogs : https://www.cnblogs.com/WenGalois123/ 6 // *** Author : Galois_V 7 // *** Date : 2022.3.31 8 // *** Changes : 9 //************************************************************************** 10 `timescale 1ns/1ps 11 module Gpio_ctrl 12 #( 13 parameter IO_NUM = 512 14 ) 15 ( 16 input wire i_s_axi_aclk , 17 input wire i_s_axi_aresetn , 18 input wire [31:0] i_ctrl_wr_addr , 19 input wire i_ctrl_wr_en , 20 input wire [31:0] i_ctrl_wr_data , 21 input wire [3:0] i_ctrl_wr_mask , 22 input wire [31:0] i_ctrl_rd_addr , 23 output reg [31:0] o_ctrl_rd_data , 24 input wire [IO_NUM-1:0] i_gpio_if_i , 25 output reg [IO_NUM-1:0] o_gpio_if_o , 26 output reg [IO_NUM-1:0] o_gpio_if_t 27 ); 28 29 30 31 parameter GPIO_CH = IO_NUM / 32; 32 33 34 wire [31:0] w_gpio_map[3*GPIO_CH:0] ; 35 36 genvar i; 37 generate 38 for(i = 1; i <= GPIO_CH; i = i + 1) 39 begin 40 assign w_gpio_map[i-1] = o_gpio_if_o[(i*32-1)-:32]; 41 assign w_gpio_map[i + GPIO_CH-1] = o_gpio_if_t[(i*32-1)-:32]; 42 assign w_gpio_map[i + GPIO_CH*2-1] = i_gpio_if_i[(i*32-1)-:32]; 43 44 /******************************************************************************\ 45 GPIO o io registers 46 \******************************************************************************/ 47 always@(posedge i_s_axi_aclk) 48 begin 49 if(~i_s_axi_aresetn) 50 begin 51 o_gpio_if_o[(i*8-1)-:8] <= 'd0; 52 end 53 else if((i_ctrl_wr_addr[7:2] == i-1) & i_ctrl_wr_en & i_ctrl_wr_mask[0]) 54 begin 55 o_gpio_if_o[(i*8-1)-:8] <= i_ctrl_wr_data[7:0]; 56 end 57 end 58 always@(posedge i_s_axi_aclk) 59 begin 60 if(~i_s_axi_aresetn) 61 begin 62 o_gpio_if_o[(i*16-1)-:8] <= 'd0; 63 end 64 else if((i_ctrl_wr_addr[7:2] == i-1) & i_ctrl_wr_en & i_ctrl_wr_mask[1]) 65 begin 66 o_gpio_if_o[(i*16-1)-:8] <= i_ctrl_wr_data[15:8]; 67 end 68 end 69 always@(posedge i_s_axi_aclk) 70 begin 71 if(~i_s_axi_aresetn) 72 begin 73 o_gpio_if_o[(i*24-1)-:8] <= 'd0; 74 end 75 else if((i_ctrl_wr_addr[7:2] == i-1) & i_ctrl_wr_en & i_ctrl_wr_mask[2]) 76 begin 77 o_gpio_if_o[(i*24-1)-:8] <= i_ctrl_wr_data[23:16]; 78 end 79 end 80 always@(posedge i_s_axi_aclk) 81 begin 82 if(~i_s_axi_aresetn) 83 begin 84 o_gpio_if_o[(i*32-1)-:8] <= 'd0; 85 end 86 else if((i_ctrl_wr_addr[7:2] == i-1) & i_ctrl_wr_en & i_ctrl_wr_mask[3]) 87 begin 88 o_gpio_if_o[(i*32-1)-:8] <= i_ctrl_wr_data[31:24]; 89 end 90 end 91 /******************************************************************************\ 92 GPIO t io registers 93 \******************************************************************************/ 94 always@(posedge i_s_axi_aclk) 95 begin 96 if(~i_s_axi_aresetn) 97 begin 98 o_gpio_if_t[(i*8-1)-:8] <= 'd0; 99 end 100 else if((i_ctrl_wr_addr[7:2] == GPIO_CH+i-1) & i_ctrl_wr_en & i_ctrl_wr_mask[0]) 101 begin 102 o_gpio_if_t[(i*8-1)-:8] <= i_ctrl_wr_data[7:0]; 103 end 104 end 105 always@(posedge i_s_axi_aclk) 106 begin 107 if(~i_s_axi_aresetn) 108 begin 109 o_gpio_if_t[(i*16-1)-:8] <= 'd0; 110 end 111 else if((i_ctrl_wr_addr[7:2] == GPIO_CH+i-1) & i_ctrl_wr_en & i_ctrl_wr_mask[1]) 112 begin 113 o_gpio_if_t[(i*16-1)-:8] <= i_ctrl_wr_data[15:8]; 114 end 115 end 116 always@(posedge i_s_axi_aclk) 117 begin 118 if(~i_s_axi_aresetn) 119 begin 120 o_gpio_if_t[(i*24-1)-:8] <= 'd0; 121 end 122 else if((i_ctrl_wr_addr[7:2] == GPIO_CH+i-1) & i_ctrl_wr_en & i_ctrl_wr_mask[2]) 123 begin 124 o_gpio_if_t[(i*24-1)-:8] <= i_ctrl_wr_data[23:16]; 125 end 126 end 127 always@(posedge i_s_axi_aclk) 128 begin 129 if(~i_s_axi_aresetn) 130 begin 131 o_gpio_if_t[(i*32-1)-:8] <= 'd0; 132 end 133 else if((i_ctrl_wr_addr[7:2] == GPIO_CH+i-1) & i_ctrl_wr_en & i_ctrl_wr_mask[3]) 134 begin 135 o_gpio_if_t[(i*32-1)-:8] <= i_ctrl_wr_data[31:24]; 136 end 137 end 138 end 139 endgenerate 140 /******************************************************************************\ 141 GPIO all registers read operation 142 \******************************************************************************/ 143 always@(*) 144 begin 145 o_ctrl_rd_data <= w_gpio_map[i_ctrl_rd_addr[7:2]]; 146 end 147 148 endmodule
以上便是最简单的AXI4_GPIO的代码,具体寄存器地址根据设置的IO_NUM定。
如果IO_NUM=32:
o_gpio_if_o[31:0] R/W 0x00
o_gpio_if_t[31:0] R/W 0x04
i_gpio_if_i[31:0] R 0x08
如果是IO_NUM=64:
o_gpio_if_o[31:0] R/W 0x00
o_gpio_if_o[63:32] R/W 0x04
o_gpio_if_t[31:0] R/W 0x08
o_gpio_if_t[63:32] R/W 0x0C
i_gpio_if_i[31:0] R 0x10
i_gpio_if_i[63:32] R 0x14
可以根据代码计算出相应的寄存器地址,这里的地址是IP核内的,实际地址应该还有前面设备地址高24位,组成的完整地址应该是32bit。
后续将介绍用vivado软件进行对此IP核的封装。