)
本章节讲述如何使用FPGA纯verilog语言实现NVME SSD硬盘的读写控制。参考三、实战篇-NVME SSD控制之FPGA实现一-CSDN博客二、实战篇-NVME SSD控制之ZYNQ实现三-CSDN博客前面完成了FPGA和NVME SSD的PCIE CFG空间的配置。下面进行NVME SSD的寄存器配置NVME SSD内部寄存器位于BAR空间中。上一节通过S_AXI_CTL总线完成了PCIE配置空间的配置本节通过控制S_AXI总线完成NVME SSD内部寄存器配置。S_AXI_CTL总线采用AXI_FULL接口AXI_FUL接口信号比较多这里使用一个本地转AXI_FUL接口的模块LOCAL_2_AXI方便读写。通过这个模块这样我们通过本地接口就可以进行S_AXI总线接口的访问module LOCAL_2_AXI # ( parameter C_M_TARGET_SLAVE_BASE_ADDR 32h40000000, parameter integer C_M_AXI_ID_WIDTH 1, parameter integer C_M_AXI_ADDR_WIDTH 32, parameter integer C_M_AXI_DATA_WIDTH 128, parameter integer C_M_AXI_AWUSER_WIDTH 0, parameter integer C_M_AXI_ARUSER_WIDTH 0, parameter integer C_M_AXI_WUSER_WIDTH 0, parameter integer C_M_AXI_RUSER_WIDTH 0, parameter integer C_M_AXI_BUSER_WIDTH 0 ) ( // 本地读写接口 input wire local_wr_en, input wire [C_M_AXI_ADDR_WIDTH-1:0]local_wr_addr, input wire [C_M_AXI_DATA_WIDTH-1:0]local_wr_data, input [C_M_AXI_DATA_WIDTH/8-1:0] i_WSTRB, output reg local_wr_done, input wire local_rd_en, input wire [C_M_AXI_ADDR_WIDTH-1:0]local_rd_addr, output reg [C_M_AXI_DATA_WIDTH-1:0]local_rd_data, output reg local_rd_valid, // AXI4 时钟复位 input wire M_AXI_ACLK, input wire M_AXI_ARESETN, // 写地址通道 output wire [C_M_AXI_ID_WIDTH-1 : 0] M_AXI_AWID, output wire [C_M_AXI_ADDR_WIDTH-1 : 0] M_AXI_AWADDR, output wire [7 : 0] M_AXI_AWLEN, output wire [2 : 0] M_AXI_AWSIZE, output wire [1 : 0] M_AXI_AWBURST, output wire M_AXI_AWLOCK, output wire [3 : 0] M_AXI_AWCACHE, output wire [2 : 0] M_AXI_AWPROT, output wire [3 : 0] M_AXI_AWQOS, output wire [C_M_AXI_AWUSER_WIDTH-1 : 0] M_AXI_AWUSER, output wire M_AXI_AWVALID, input wire M_AXI_AWREADY, // 写数据通道 output wire [C_M_AXI_DATA_WIDTH-1 : 0] M_AXI_WDATA, output wire [C_M_AXI_DATA_WIDTH/8-1 : 0] M_AXI_WSTRB, output wire M_AXI_WLAST, output wire [C_M_AXI_WUSER_WIDTH-1 : 0] M_AXI_WUSER, output wire M_AXI_WVALID, input wire M_AXI_WREADY, // 写响应通道 input wire [C_M_AXI_ID_WIDTH-1 : 0] M_AXI_BID, input wire [1 : 0] M_AXI_BRESP, input wire [C_M_AXI_BUSER_WIDTH-1 : 0] M_AXI_BUSER, input wire M_AXI_BVALID, output wire M_AXI_BREADY, // 读地址通道 output wire [C_M_AXI_ID_WIDTH-1 : 0] M_AXI_ARID, output wire [C_M_AXI_ADDR_WIDTH-1 : 0] M_AXI_ARADDR, output wire [7 : 0] M_AXI_ARLEN, output wire [2 : 0] M_AXI_ARSIZE, output wire [1 : 0] M_AXI_ARBURST, output wire M_AXI_ARLOCK, output wire [3 : 0] M_AXI_ARCACHE, output wire [2 : 0] M_AXI_ARPROT, output wire [3 : 0] M_AXI_ARQOS, output wire [C_M_AXI_ARUSER_WIDTH-1 : 0] M_AXI_ARUSER, output wire M_AXI_ARVALID, input wire M_AXI_ARREADY, // 读数据通道 input wire [C_M_AXI_ID_WIDTH-1 : 0] M_AXI_RID, input wire [C_M_AXI_DATA_WIDTH-1 : 0] M_AXI_RDATA, input wire [1 : 0] M_AXI_RRESP, input wire M_AXI_RLAST, input wire [C_M_AXI_RUSER_WIDTH-1 : 0] M_AXI_RUSER, input wire M_AXI_RVALID, output wire M_AXI_RREADY );将LOCAL_2_AXI模块的M_AXI连接到S_AXI总线本地信号引出到外部进行控制。新建一个nvme_reg_cfg模块用于控制LOCAL_2_AXI模块的本地接口进行NVME SSD寄存器读写module nvme_reg_cfg#( parameter integer C_M_AXI_ADDR_WIDTH 32, parameter integer C_M_AXI_DATA_WIDTH 128, parameter NVME_ADMIN_QSIZE 16d16, parameter ADMIN_SQ_BASE 32h1010_0000, parameter ADMIN_CQ_BASE 32h1010_1000 )( input wire i_aclk, input wire i_aresetn, input i_cfg_start, output o_cfg_done, input i_wr_door_req, input [2:0] i_wr_door_type, input [31:0] i_wr_door_data, output o_wr_door_done, // 本地写接口 output o_wr_en, // 写使能高有效 output [C_M_AXI_ADDR_WIDTH-1:0] o_wr_addr, // 本地写地址偏移地址 output [C_M_AXI_DATA_WIDTH-1:0] o_wr_data, // 本地待写入数据 output [C_M_AXI_DATA_WIDTH/8-1:0] o_WSTRB, input i_wr_done, // 读接口 output o_rd_en, // 读使能高有效 output [C_M_AXI_ADDR_WIDTH-1:0] o_rd_addr, // 本地读地址偏移地址 input [C_M_AXI_DATA_WIDTH-1:0] i_rd_data, // 读回数据 input i_rd_valid // 读数据有效标志 );寄存器偏移地址都是固定的可以将其定义为parameterparameter RegOffset_CAP_L 32h0000_0000; parameter RegOffset_CAP_H 32h0000_0004; parameter RegOffset_VS 32h0000_0008; parameter RegOffset_CC 32h0000_0014; parameter RegOffset_CSTS 32h0000_001C; parameter RegOffset_AQA 32h0000_0024; parameter RegOffset_ASQ_L 32h0000_0028; parameter RegOffset_ASQ_H 32h0000_002C; parameter RegOffset_ACQ_L 32h0000_0030; parameter RegOffset_ACQ_H 32h0000_0034; parameter RegOffset_Admin_SQTDBL 32h0000_1000; parameter RegOffset_Admin_CQHDBL 32h0000_1004; parameter RegOffset_IO_SQ0TDBL 32h0000_1008; parameter RegOffset_IO_CQ0HDBL 32h0000_100C; parameter RegOffset_IO_SQ1TDBL 32h0000_1010; parameter RegOffset_IO_CQ1HDBL 32h0000_1014;主要状态流程如下// cstate always(posedge i_aclk or negedge i_aresetn)begin if(!i_aresetn)begin cstate0; end else begin cstatenstate; end end always(*)begin case(cstate) 0:begin if(start_pdg) nstate1; else nstate0;end 1:begin if(rd_cnt4) nstate2;//RD RC ID else nstate1;end 2:begin if(i_rd_valid) nstate3;//rd ready else nstate2;end 3:begin if(rd_vaild rdata[0]0) nstate4;// else nstate2;end 4:begin if(i_wr_done) nstate5;//wr cc else nstate4;end 5:begin if(i_wr_done) nstate6;//wr AQA else nstate5;end 6:begin if(i_wr_done) nstate7;//wr ASQ_L else nstate6;end 7:begin if(i_wr_done) nstate8;//wr ASQ_H else nstate7;end 8:begin if(i_wr_done) nstate9;//wr ACQ_L else nstate8;end 9:begin if(i_wr_done) nstate10;//wr ACQ_H else nstate9;end 10:begin if(i_wr_done) nstate11;//wr cc else nstate10;end 11:begin if(i_rd_valid) nstate12;//rd ready else nstate11;end 12:begin if(rd_vaild rdata[0]1) nstate13;// else nstate11;end //------ 13:begin if(wr_door_req) nstate14; else nstate13;end 14:begin if(i_wr_done) nstate15; else nstate14;end 15:begin nstate13;end endcase end读寄存器//rd always(posedge i_aclk or negedge i_aresetn)begin if(!i_aresetn)begin rd_en0; rd_addr0; end else begin if(cstate1)begin if(rd_cnt0)begin rd_addrRegOffset_CAP_L; if(i_rd_valid) rd_en0; else rd_en1; end else if(rd_cnt1)begin rd_addrRegOffset_CAP_H; if(i_rd_valid) rd_en0; else rd_en1; end else if(rd_cnt2)begin rd_addrRegOffset_VS; if(i_rd_valid) rd_en0; else rd_en1; end else if(rd_cnt3)begin rd_addrRegOffset_CC; if(i_rd_valid) rd_en0; else rd_en1; end else rd_en0; end else if(cstate2||cstate11)begin rd_addrRegOffset_CSTS; if(i_rd_valid) rd_en0; else rd_en1; end else begin rd_en0; end end end写寄存器//wr always(posedge i_aclk or negedge i_aresetn)begin if(!i_aresetn)begin wr_en0; wr_addr0; wr_data0; end else begin if(cstate4)begin wr_addrRegOffset_CC; wr_data32h0046_0000; if(i_wr_done) wr_en0; else wr_en1; end else if(cstate5)begin wr_addrRegOffset_AQA; wr_data{NVME_ADMIN_QSIZE,NVME_ADMIN_QSIZE}; if(i_wr_done) wr_en0; else wr_en1; end else if(cstate6)begin wr_addrRegOffset_ASQ_L; wr_dataADMIN_SQ_BASE; if(i_wr_done) wr_en0; else wr_en1; end else if(cstate7)begin wr_addrRegOffset_ASQ_H; wr_data32h0000_0000; if(i_wr_done) wr_en0; else wr_en1; end else if(cstate8)begin wr_addrRegOffset_ACQ_L; wr_dataADMIN_CQ_BASE; if(i_wr_done) wr_en0; else wr_en1; end else if(cstate9)begin wr_addrRegOffset_ACQ_H; wr_data32h0000_0000; if(i_wr_done) wr_en0; else wr_en1; end else if(cstate10)begin wr_addrRegOffset_CC; wr_data32h0046_0001; if(i_wr_done) wr_en0; else wr_en1; end else if(cstate14)begin wr_datai_wr_door_data; case(i_wr_door_type) 0:wr_addrRegOffset_Admin_SQTDBL; 1:wr_addrRegOffset_Admin_CQHDBL; 2:wr_addrRegOffset_IO_SQ0TDBL; 3:wr_addrRegOffset_IO_CQ0HDBL; 4:wr_addrRegOffset_IO_SQ1TDBL; 5:wr_addrRegOffset_IO_CQ1HDBL; default:wr_addrRegOffset_Admin_SQTDBL; endcase if(i_wr_done)begin wr_en0; end else begin wr_en1; end end else begin wr_en0; end end end主要寄存器配置流程和ZYNQ控制NVME SSD配置一致。