黑金例程DDR学习

黑金例程pl_read_write_ps_ddr学习以及代码精读

最近学习一下DDR的使用,先学习了AXI4总线协议,又看了看DDRx相关资料,做个总结

先声明一下,黑金的例程可以,视频教程可以,pdf用户手册有点垃圾

可以先看看视频学个大概

【34】ALINX Zynq MPSoC XILINX FPGA视频教程 SDK 裸机开发—AXI总线协议介绍_哔哩哔哩_bilibili

【34】ALINX Zynq MPSoC XILINX FPGA视频教程 SDK 裸机开发—AXI总线协议介绍_哔哩哔哩_bilibili

https://www.bilibili.com/video/BV1Ha411H7Hc/?spm_id_from=333.788

推荐文章

了解AXI4总线协议,看着很详细,调着看

【数字IC基础】一文搞懂AXI (Advanced eXtensible Interface) 协议_数字IC前端入门-CSDN专栏

学习算DDR容量

DDR-SDRAM内存颗粒 容量计算2-SDRAM,DDR3,DDR4实例计算,兼容设计_哔哩哔哩_bilibili

在这里插入图片描述

另外一些Debug博客

在vivado环境中如何debug? - 知乎 (zhihu.com)

FPGA的开发流程梳理: Vivado的RTL分析(RTL analysis)、综合(Synthesis)和实现(Implementation)的区别?分别负责什么工作-CSDN博客

然后废话就不多说了直接上代码,几乎都有注释,我都注明了作用

top.v

`timescale 1ns / 1ps
//
// Company: ALINX榛戦噾
// Engineer: 鑰佹
// 
// Create Date: 2016/11/17 10:27:06
// Design Name: 
// Module Name: mem_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

module top(  
   (*mark_debug="true"*) output error
    );
	
	
// AXI4协议学习 https://download.csdn.net/blog/column/11976230/129024896
	
wire rst_n;	
wire M_AXI_ACLK;
// Master Write Address
wire [0:0]  M_AXI_AWID;
wire [31:0] M_AXI_AWADDR;
wire [7:0]  M_AXI_AWLEN;    // Burst Length: 0-255
wire [2:0]  M_AXI_AWSIZE;   // Burst Size: Fixed 2'b011   数据宽度64位,也就是2^(3)字节
wire [1:0]  M_AXI_AWBURST;  // Burst Type: Fixed 2'b01(Incremental Burst) (Incrementing-address burst :可指定长度的增量式突发传输)
wire        M_AXI_AWLOCK;   // Lock: Fixed 2'b00 	
wire [3:0]  M_AXI_AWCACHE;  // Cache: Fiex 2'b0011
wire [2:0]  M_AXI_AWPROT;   // Protect: Fixed 2'b000
wire [3:0]  M_AXI_AWQOS;    // QoS: Fixed 2'b0000
wire [0:0]  M_AXI_AWUSER;   // User: Fixed 32'd0	自定义用户信息
wire        M_AXI_AWVALID;		//写地址有效信号
wire        M_AXI_AWREADY;		//写地址准备信号,等待从机返回

// Master Write Data
wire [63:0] M_AXI_WDATA;    //64位写数据
wire [7:0]  M_AXI_WSTRB;	//数据选通,对上面64位数据进行有效使能,每一位对应上面一个字节
wire        M_AXI_WLAST;	//表示一次突发的最后一个数据
wire [0:0]  M_AXI_WUSER;	// 自定义的用户信息
wire        M_AXI_WVALID;	// 写数据有效信号
wire        M_AXI_WREADY;	// 写数据准备信号,等待从机返回

// Master Write Response
wire [0:0]   M_AXI_BID;		// 响应ID,必须和AWID主机ID保持一致,等待从设备返回
wire [1:0]   M_AXI_BRESP;	// 写响应信号,从设备告诉主机写传输的状态
wire [0:0]   M_AXI_BUSER;	//	从设备自定义用户信号
wire         M_AXI_BVALID;	//  写响应有效信号,从设备发出。
wire         M_AXI_BREADY;	//  主机发出准备信号,表示可以接受响应信号
    
// Master Read Address
wire [0:0]  M_AXI_ARID;		// 读通道 ID 这个信号是读地址信号组的ID标签
wire [31:0] M_AXI_ARADDR;   // 读通道地址
wire [7:0]  M_AXI_ARLEN;    // Burst Length: 0-255
wire [2:0]  M_AXI_ARSIZE;   // Burst Size: Fixed 2'b011   数据宽度64位,也就是2^(3)字节
wire [1:0]  M_AXI_ARBURST;  // Burst Type: Fixed 2'b01(Incremental Burst) (Incrementing-address burst :可指定长度的增量式突发传输)
wire        M_AXI_ARLOCK;   //
wire [3:0]  M_AXI_ARCACHE;  //
wire [2:0]  M_AXI_ARPROT;   //
wire [3:0]  M_AXI_ARQOS;    //
wire [0:0]  M_AXI_ARUSER;   // 主机自定义用户信号
wire        M_AXI_ARVALID;  // 地址有效信号
wire        M_AXI_ARREADY;  // 地址准备好接收信号,从机发出
    
// Master Read Data 
wire [0:0]   M_AXI_RID;     // 响应ID,必须和AWID主机ID保持一致,等待从设备返回
wire [63:0]  M_AXI_RDATA;   // 所读出的数据,从机发出
wire [1:0]   M_AXI_RRESP;   // 读响应信号,从设备告诉主机写传输的状态
wire         M_AXI_RLAST;   // 表示一次突发的最后一个数据
wire [0:0]   M_AXI_RUSER;   // 主机自定义用户信号
wire         M_AXI_RVALID;  // 数据有效信号
wire         M_AXI_RREADY;  // 读数据准备信号,主机发出
wire [31:0]  DEBUG;

(*mark_debug="true"*)wire wr_burst_data_req;
(*mark_debug="true"*)wire wr_burst_finish;
(*mark_debug="true"*)wire rd_burst_finish;
(*mark_debug="true"*)wire rd_burst_req;
(*mark_debug="true"*)wire wr_burst_req;
(*mark_debug="true"*)wire[9:0] rd_burst_len;
(*mark_debug="true"*)wire[9:0] wr_burst_len;
(*mark_debug="true"*)wire[31:0] rd_burst_addr;
(*mark_debug="true"*)wire[31:0] wr_burst_addr;
(*mark_debug="true"*)wire rd_burst_data_valid;
(*mark_debug="true"*)wire[63 : 0] rd_burst_data;
(*mark_debug="true"*)wire[63 : 0] wr_burst_data;
(*mark_debug="true"*)wire[23 : 0] debug_reg_wr_len;
(*mark_debug="true"*)wire[2 : 0] debug_wr_state;
(*mark_debug="true"*)wire[2 : 0] debug_rd_state;

assign debug_reg_wr_len = DEBUG[31:8];
assign debug_wr_state = DEBUG[6:4];
assign debug_rd_state = DEBUG[2:0];

mem_test
#(
	.MEM_DATA_BITS(64),    //数据位宽64
	.ADDR_BITS(27)         //地址位宽27
)
mem_test_m0
(
	.rst(~rst_n),                                 
	.mem_clk(M_AXI_ACLK),                             
	.rd_burst_req(rd_burst_req),                  /*读请求*/
	.wr_burst_req(wr_burst_req),                  /*写请求*/
	.rd_burst_len(rd_burst_len),                  /*读数据长度*/
	.wr_burst_len(wr_burst_len),                  /*写数据长度*/
	.rd_burst_addr(rd_burst_addr),                /*读首地址*/
	.wr_burst_addr(wr_burst_addr),                /*写首地址*/
	.rd_burst_data_valid(rd_burst_data_valid),    /*读出数据有效*/
	.wr_burst_data_req(wr_burst_data_req),        /*写数据信号*/
	.rd_burst_data(rd_burst_data),                /*读出的数据*/
	.wr_burst_data(wr_burst_data),                /*写入的数据*/
	.rd_burst_finish(rd_burst_finish),            /*读完成*/
	.wr_burst_finish(wr_burst_finish),            /*写完成*/

	.error(error)
); 
aq_axi_master u_aq_axi_master
(
	.ARESETN(rst_n),
	.ACLK(M_AXI_ACLK),
	
	.M_AXI_AWID(M_AXI_AWID),
	.M_AXI_AWADDR(M_AXI_AWADDR),     
	.M_AXI_AWLEN(M_AXI_AWLEN),
	.M_AXI_AWSIZE(M_AXI_AWSIZE),
	.M_AXI_AWBURST(M_AXI_AWBURST),
	.M_AXI_AWLOCK(M_AXI_AWLOCK),
	.M_AXI_AWCACHE(M_AXI_AWCACHE),
	.M_AXI_AWPROT(M_AXI_AWPROT),
	.M_AXI_AWQOS(M_AXI_AWQOS),
	.M_AXI_AWUSER(M_AXI_AWUSER),
	.M_AXI_AWVALID(M_AXI_AWVALID),
	.M_AXI_AWREADY(M_AXI_AWREADY),
	
	.M_AXI_WDATA(M_AXI_WDATA),
	.M_AXI_WSTRB(M_AXI_WSTRB),
	.M_AXI_WLAST(M_AXI_WLAST),
	.M_AXI_WUSER(M_AXI_WUSER),
	.M_AXI_WVALID(M_AXI_WVALID),
	.M_AXI_WREADY(M_AXI_WREADY),
	
	.M_AXI_BID(M_AXI_BID),
	.M_AXI_BRESP(M_AXI_BRESP),
	.M_AXI_BUSER(M_AXI_BUSER),
	.M_AXI_BVALID(M_AXI_BVALID),
	.M_AXI_BREADY(M_AXI_BREADY),
	
	.M_AXI_ARID(M_AXI_ARID),
	.M_AXI_ARADDR(M_AXI_ARADDR),
	.M_AXI_ARLEN(M_AXI_ARLEN),
	.M_AXI_ARSIZE(M_AXI_ARSIZE),
	.M_AXI_ARBURST(M_AXI_ARBURST),
	.M_AXI_ARLOCK(M_AXI_ARLOCK),
	.M_AXI_ARCACHE(M_AXI_ARCACHE),
	.M_AXI_ARPROT(M_AXI_ARPROT),
	.M_AXI_ARQOS(M_AXI_ARQOS),
	.M_AXI_ARUSER(M_AXI_ARUSER),
	.M_AXI_ARVALID(M_AXI_ARVALID),
	.M_AXI_ARREADY(M_AXI_ARREADY),
	
	.M_AXI_RID(M_AXI_RID),
	.M_AXI_RDATA(M_AXI_RDATA),
	.M_AXI_RRESP(M_AXI_RRESP),
	.M_AXI_RLAST(M_AXI_RLAST),
	.M_AXI_RUSER(M_AXI_RUSER),
	.M_AXI_RVALID(M_AXI_RVALID),
	.M_AXI_RREADY(M_AXI_RREADY),
	
	.MASTER_RST(~rst_n),
															 //
	.WR_START(wr_burst_req),                                 //
	.WR_ADRS({wr_burst_addr[28:0],3'd0}),					 // 在地址后面补3位,因为地址按64位宽设置的,但是在存取DDR的过程中,每位地址储存8位数据,故地址要*8				
	.WR_LEN({wr_burst_len,3'd0}),                            //	后面增加3位选通信号,好像没有起什么作用
	.WR_READY(),                                             //
	.WR_FIFO_RE(wr_burst_data_req),                          //
	.WR_FIFO_EMPTY(1'b0),                                    //
	.WR_FIFO_AEMPTY(1'b0),                                   //
	.WR_FIFO_DATA(wr_burst_data),                            //
	.WR_DONE(wr_burst_finish),                               //
															 //
	.RD_START(rd_burst_req),                                 //
	.RD_ADRS({rd_burst_addr[28:0],3'd0}),                    //
	.RD_LEN({rd_burst_len,3'd0}),                            //
	.RD_READY(),                                             //
	.RD_FIFO_WE(rd_burst_data_valid),                        //
	.RD_FIFO_FULL(1'b0),                                     //
	.RD_FIFO_AFULL(1'b0),                                    //
	.RD_FIFO_DATA(rd_burst_data),                            //
	.RD_DONE(rd_burst_finish),                               //
	.DEBUG(DEBUG)                                                 //
);

	
design_1_wrapper ps_block
(
    	
	.S_AXI_HP0_araddr       (M_AXI_ARADDR          ),
	.S_AXI_HP0_arburst      (M_AXI_ARBURST         ),
	.S_AXI_HP0_arcache      (M_AXI_ARCACHE         ),
	.S_AXI_HP0_arid         (M_AXI_ARID            ),
	.S_AXI_HP0_arlen        (M_AXI_ARLEN           ),
	.S_AXI_HP0_arlock       (M_AXI_ARLOCK          ),
	.S_AXI_HP0_arprot       (M_AXI_ARPROT          ),
	.S_AXI_HP0_arqos        (M_AXI_ARQOS           ),
	.S_AXI_HP0_arready      (M_AXI_ARREADY         ),
	.S_AXI_HP0_arsize       (M_AXI_ARSIZE          ),
	.S_AXI_HP0_arvalid      (M_AXI_ARVALID         ),
	.S_AXI_HP0_rdata        (M_AXI_RDATA           ),
	.S_AXI_HP0_rid          (M_AXI_RID             ),
	.S_AXI_HP0_rlast        (M_AXI_RLAST           ),
	.S_AXI_HP0_rready       (M_AXI_RREADY          ),
	.S_AXI_HP0_rresp        (M_AXI_RRESP           ),
	.S_AXI_HP0_rvalid       (M_AXI_RVALID          ),		
	.S_AXI_HP0_awaddr       (M_AXI_AWADDR          ),
	.S_AXI_HP0_awburst      (M_AXI_AWBURST         ),
	.S_AXI_HP0_awcache      (M_AXI_AWCACHE         ),
	.S_AXI_HP0_awid         (M_AXI_AWID            ),
	.S_AXI_HP0_awlen        (M_AXI_AWLEN           ),
	.S_AXI_HP0_awlock       (M_AXI_AWLOCK          ),
	.S_AXI_HP0_awprot       (M_AXI_AWPROT          ),
	.S_AXI_HP0_awqos        (M_AXI_AWQOS           ),
	.S_AXI_HP0_awready      (M_AXI_AWREADY         ),
	.S_AXI_HP0_awsize       (M_AXI_AWSIZE          ),
	.S_AXI_HP0_awvalid      (M_AXI_AWVALID         ),
	.S_AXI_HP0_bid          (M_AXI_BID             ),
	.S_AXI_HP0_bready       (M_AXI_BREADY          ),
	.S_AXI_HP0_bresp        (M_AXI_BRESP           ),
	.S_AXI_HP0_bvalid       (M_AXI_BVALID          ),
	.S_AXI_HP0_wdata        (M_AXI_WDATA           ),
	.S_AXI_HP0_wlast        (M_AXI_WLAST           ),
	.S_AXI_HP0_wready       (M_AXI_WREADY          ),
	.S_AXI_HP0_wstrb        (M_AXI_WSTRB           ),
	.S_AXI_HP0_wvalid       (M_AXI_WVALID          ),
	
	.axim_rst_n(rst_n),
	.pl_clk0(M_AXI_ACLK),
	.axi_hp_clk(M_AXI_ACLK)
);
endmodule

mem_test.v

//
// Company: ALINX黑金
// Engineer: 老梅
// 
// Create Date: 2016/11/17 10:27:06
// Design Name: 
// Module Name: mem_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module mem_test
#(
	parameter MEM_DATA_BITS = 64,
	parameter ADDR_BITS = 32
)
(
	input rst,                                 			/*复位*/
	input mem_clk,                               		/*接口时钟*/
	output reg rd_burst_req,                     	    /*读请求*/
	output reg wr_burst_req,                     	    /*写请求*/
	output reg[9:0] rd_burst_len,                	    /*读数据长度*/
	output reg[9:0] wr_burst_len,                       /*写数据长度*/
	output reg[ADDR_BITS - 1:0] rd_burst_addr,          /*读首地址*/
	output reg[ADDR_BITS - 1:0] wr_burst_addr,          /*写首地址*/
	input rd_burst_data_valid,                  		/*读出数据有效*/
	input wr_burst_data_req,                    		/*写数据信号*/
	input[MEM_DATA_BITS - 1:0] rd_burst_data,   		/*读出的数据*/
	output[MEM_DATA_BITS - 1:0] wr_burst_data,    		/*写入的数据*/
	input rd_burst_finish,                      		/*读完成*/
	input wr_burst_finish,                      		/*写完成*/

	output reg error
);

//状态机
localparam IDLE = 3'd0;
localparam MEM_READ = 3'd1;
localparam MEM_WRITE  = 3'd2;
localparam BURST_LEN = 128; 				//突发长度

reg[2:0] state;								//状态
reg[7:0] wr_cnt;							//写计数
reg[MEM_DATA_BITS - 1:0] wr_burst_data_reg; //写数据寄存器
assign wr_burst_data = wr_burst_data_reg;
reg[7:0] rd_cnt;							//读计数
reg[31:0] write_read_len;					//
//assign error = (state == MEM_READ) && rd_burst_data_valid && (rd_burst_data != {(MEM_DATA_BITS/8){rd_cnt}});

/*错误检测,检测是否读出的数据与所构想设计的一样*/
always@(posedge mem_clk or posedge rst)
begin
	if(rst)
		error <= 1'b0;
	else if(state == MEM_READ && rd_burst_data_valid && rd_burst_data != {(MEM_DATA_BITS/8){rd_cnt}})
		error <= 1'b1;
end

/*写数据设计,在开始写入的时候,按规律构建数据*/
always@(posedge mem_clk or posedge rst)
begin
	if(rst)
	begin
		wr_burst_data_reg <= {MEM_DATA_BITS{1'b0}};					//初始化写数据写入64‘d0,写计数为零
		wr_cnt <= 8'd0;
	end
	else if(state == MEM_WRITE)
	begin
		if(wr_burst_data_req)
			begin
				wr_burst_data_reg <= {(MEM_DATA_BITS/8){wr_cnt}};	//开始设计写入数据,记得debug是先写入的1还是0???
				wr_cnt <= wr_cnt + 8'd1;
			end
		else if(wr_burst_finish)
			wr_cnt <= 8'd0;											//写完计数归零
	end
end

/* 读数据计数 */
always@(posedge mem_clk or posedge rst)
begin
	if(rst)
	begin
		rd_cnt <= 8'd0;
	end
	else if(state == MEM_READ)
	begin
		if(rd_burst_data_valid)
			begin
				rd_cnt <= rd_cnt + 8'd1;
			end
		else if(rd_burst_finish)
			rd_cnt <= 8'd0;
	end
	else
		rd_cnt <= 8'd0;
end

/* */
always@(posedge mem_clk or posedge rst)
begin
	if(rst)
	begin
		state <= IDLE;									//初始化读写请求,读写突发长度,读写地址
		wr_burst_req <= 1'b0;
		rd_burst_req <= 1'b0;
		rd_burst_len <= BURST_LEN;
		wr_burst_len <= BURST_LEN;
		rd_burst_addr <= 0;
		wr_burst_addr <= 0;
		write_read_len <= 32'd0;
	end
	else
	begin
		case(state)
			IDLE:										//初始状态,进入写状态,打开写请求,设定突发长度,设定写地址
			begin
				state <= MEM_WRITE;
				wr_burst_req <= 1'b1;
				wr_burst_len <= BURST_LEN;
				wr_burst_addr <='h2000000;
				write_read_len <= 32'd0;
			end
			MEM_WRITE:									//写状态,在这个状态下,如果没有写完,就一直进行空循环,如果写完了,进入读状态,关闭写请求,打开读请求,设定读突发长度,读地址,写地址累加,等待下一次写
			begin
				if(wr_burst_finish)
				begin
					state <= MEM_READ;
					wr_burst_req <= 1'b0;
					rd_burst_req <= 1'b1;
					rd_burst_len <= BURST_LEN;
					rd_burst_addr <= wr_burst_addr;
					write_read_len <= write_read_len + BURST_LEN;
				end
			end
			MEM_READ:									//一直读,读完进入判断,若地址规律,回归初始状态,否则继续写
			begin
				if(rd_burst_finish)
				begin
				    if(write_read_len == 32'h2000000)
				    begin
						rd_burst_req <= 1'b0;
						state <= IDLE;
				    end
				    else
				    begin
						state <= MEM_WRITE;
						wr_burst_req <= 1'b1;
						wr_burst_len <= BURST_LEN;
						rd_burst_req <= 1'b0;
						wr_burst_addr <= wr_burst_addr + BURST_LEN;
					end
				end
			end
			default:
				state <= IDLE;
		endcase
	end
end

endmodule

aq_axi_master.v

/*
 * Copyright (C)2014-2015 AQUAXIS TECHNOLOGY.
 *  Don't remove this header. 
 * When you use this source, there is a need to inherit this header.
 *
 * License
 *  For no commercial -
 *   License:     The Open Software License 3.0
 *   License URI: http://www.opensource.org/licenses/OSL-3.0
 *
 *  For commmercial -
 *   License:     AQUAXIS License 1.0
 *   License URI: http://www.aquaxis.com/licenses
 *
 * For further information please contact.
 *	URI:    http://www.aquaxis.com/
 *	E-Mail: info(at)aquaxis.com
 */
 
 //
// Company: ALINX黑金
// Engineer: 老梅
// 
// Create Date: 2016/11/17 10:27:06
// Design Name: 
// Module Name: mem_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//
module aq_axi_master(
  // Reset, Clock
  input           ARESETN,
  input           ACLK,

  // Master Write Address
  output [0:0]  M_AXI_AWID,
  output [31:0] M_AXI_AWADDR,
  output [7:0]  M_AXI_AWLEN,    // Burst Length: 0-255
  output [2:0]  M_AXI_AWSIZE,   // Burst Size: Fixed 2'b011
  output [1:0]  M_AXI_AWBURST,  // Burst Type: Fixed 2'b01(Incremental Burst)
  output        M_AXI_AWLOCK,   // Lock: Fixed 2'b00
  output [3:0]  M_AXI_AWCACHE,  // Cache: Fiex 2'b0011
  output [2:0]  M_AXI_AWPROT,   // Protect: Fixed 2'b000
  output [3:0]  M_AXI_AWQOS,    // QoS: Fixed 2'b0000
  output [0:0]  M_AXI_AWUSER,   // User: Fixed 32'd0
  output        M_AXI_AWVALID,  //写地址有效信号
  input         M_AXI_AWREADY,  //写地址准备信号,等待从机返回

  // Master Write Data
  output [63:0] M_AXI_WDATA,    //64位写数据
  output [7:0]  M_AXI_WSTRB,    //数据选通,对上面64位数据进行有效使能,每一位对应上面一个字节
  output        M_AXI_WLAST,    //表示一次突发的最后一个数据
  output [0:0]  M_AXI_WUSER,    // 自定义的用户信息
  output        M_AXI_WVALID,   // 写数据有效信号
  input         M_AXI_WREADY,   // 写数据准备信号,等待从机返回

  // Master Write Response
  input [0:0]   M_AXI_BID,      // 响应ID,必须和AWID主机ID保持一致,等待从设备返回
  input [1:0]   M_AXI_BRESP,    // 写响应信号,从设备告诉主机写传输的状态
  input [0:0]   M_AXI_BUSER,    //	从设备自定义用户信号
  input         M_AXI_BVALID,   //  写响应有效信号,从设备发出。
  output        M_AXI_BREADY,   //  主机发出准备信号,表示可以接受响应信号
    
  // Master Read Address
  output [0:0]  M_AXI_ARID,     // 读通道 ID 这个信号是读地址信号组的ID标签
  output [31:0] M_AXI_ARADDR,   // 读通道地址
  output [7:0]  M_AXI_ARLEN,    // Burst Length: 0-255
  output [2:0]  M_AXI_ARSIZE,   // Burst Size: Fixed 2'b011   数据宽度64位,也就是2^(3)字节
  output [1:0]  M_AXI_ARBURST,  // Burst Type: Fixed 2'b01(Incremental Burst) (Incrementing-address burst :可指定长度的增量式突发传输)
  output [1:0]  M_AXI_ARLOCK,   //
  output [3:0]  M_AXI_ARCACHE,  //
  output [2:0]  M_AXI_ARPROT,   //
  output [3:0]  M_AXI_ARQOS,    //
  output [0:0]  M_AXI_ARUSER,   // 主机自定义用户信号
  output        M_AXI_ARVALID,  // 地址有效信号
  input         M_AXI_ARREADY,  // 地址准备好接收信号,从机发出
    
  // Master Read Data 
  input [0:0]   M_AXI_RID,      // 响应ID,必须和AWID主机ID保持一致,等待从设备返回
  input [63:0]  M_AXI_RDATA,    // 所读出的数据,从机发出
  input [1:0]   M_AXI_RRESP,    // 读响应信号,从设备告诉主机写传输的状态
  input         M_AXI_RLAST,    // 表示一次突发的最后一个数据
  input [0:0]   M_AXI_RUSER,    // 主机自定义用户信号
  input         M_AXI_RVALID,   // 数据有效信号
  output        M_AXI_RREADY,   // 读数据准备信号,主机发出
        
  // Local Bus
  input         MASTER_RST,
  
  input         WR_START,       // 
  input [31:0]  WR_ADRS,        //
  input [31:0]  WR_LEN,         //
  output        WR_READY,       //
  output        WR_FIFO_RE,     //
  input         WR_FIFO_EMPTY,  //
  input         WR_FIFO_AEMPTY, //
  input [63:0]  WR_FIFO_DATA,   //
  output        WR_DONE,        //
								//
  input         RD_START,       //
  input [31:0]  RD_ADRS,        //
  input [31:0]  RD_LEN,         //
  output        RD_READY,       //
  output        RD_FIFO_WE,     //
  input         RD_FIFO_FULL,   //
  input         RD_FIFO_AFULL,  //
  output [63:0] RD_FIFO_DATA,   //
  output        RD_DONE,        //
								//
  output [31:0] DEBUG           //
);

  localparam S_WR_IDLE  = 3'd0;
  localparam S_WA_WAIT  = 3'd1;
  localparam S_WA_START = 3'd2;
  localparam S_WD_WAIT  = 3'd3;
  localparam S_WD_PROC  = 3'd4;
  localparam S_WR_WAIT  = 3'd5;
  localparam S_WR_DONE  = 3'd6;
  
  reg [2:0]   wr_state;
  reg [31:0]  reg_wr_adrs;
  reg [31:0]  reg_wr_len;
  reg         reg_awvalid, reg_wvalid, reg_w_last;
  reg [7:0]   reg_w_len;
  reg [7:0]   reg_w_stb;
  reg [1:0]   reg_wr_status;
  reg [3:0]   reg_w_count, reg_r_count;

  reg [7:0]   rd_chkdata, wr_chkdata;
  reg [1:0]   resp;
  reg rd_first_data;
  reg rd_fifo_enable;
  reg[31:0] rd_fifo_cnt;
assign WR_DONE = (wr_state == S_WR_DONE);



assign WR_FIFO_RE         = rd_first_data | (reg_wvalid & ~WR_FIFO_EMPTY & M_AXI_WREADY & rd_fifo_enable);    //写数据请求,给men模块,让其发送数据可能是先让其输出一个数据占据寄存器,有效的时候能够立即输出,经过Debug验证正确
//assign WR_FIFO_RE         = reg_wvalid & ~WR_FIFO_EMPTY & M_AXI_WREADY;
always @(posedge ACLK or negedge ARESETN)
begin
	if(!ARESETN)
		rd_fifo_cnt <= 32'd0;
	else if(WR_FIFO_RE)
		rd_fifo_cnt <= rd_fifo_cnt + 32'd1;
	else if(wr_state == S_WR_IDLE)
		rd_fifo_cnt <= 32'd0;	
end

always @(posedge ACLK or negedge ARESETN)
begin
	if(!ARESETN)
		rd_fifo_enable <= 1'b0;
	else if(wr_state == S_WR_IDLE && WR_START)
		rd_fifo_enable <= 1'b1;
	else if(WR_FIFO_RE && (rd_fifo_cnt == RD_LEN[31:3] - 32'd1) )
		rd_fifo_enable <= 1'b0;		
end

  // Write State
  always @(posedge ACLK or negedge ARESETN) begin
    if(!ARESETN) begin
      wr_state            <= S_WR_IDLE;
      reg_wr_adrs[31:0]   <= 32'd0;										//写地址
      reg_wr_len[31:0]    <= 32'd0;                                     //写入长度,固定,32位,与传入信号长度并不匹配,
      reg_awvalid         <= 1'b0;                                      //写地址有效信号
      reg_wvalid          <= 1'b0;                                      //写数据有效信号
      reg_w_last          <= 1'b0;										//一次突发写入的最后一次发送
      reg_w_len[7:0]      <= 8'd0;                                      //写入数据长度,但是只有在127的时候awvalid有效,之后按照传输进行累减,表明传输数据。
      reg_w_stb[7:0]      <= 8'd0;                                      //数据选通信号
      reg_wr_status[1:0]  <= 2'd0;                                      //输入写入状态信号
      reg_w_count[3:0]    <= 4'd0;                                      //被注释了,谁知道干嘛的
      reg_r_count[3:0]  <= 4'd0;                                        //被注释了,谁知道干嘛的
      wr_chkdata          <= 8'd0;                                      //被注释了,谁知道干嘛的
      rd_chkdata <= 8'd0;                                               //被注释了,谁知道干嘛的
      resp <= 2'd0;                                                     //被注释了,谁知道干嘛的
	  rd_first_data <= 1'b0;                                            //看不懂,应该和fifo有关,但是此代码也没用到,只是模拟
  end else begin
    if(MASTER_RST) begin												//看不懂,感觉脱裤子放屁
      wr_state <= S_WR_IDLE;
    end else begin
      case(wr_state)
        S_WR_IDLE: begin												//初始状态,进行写操作的一些初始化配置
          if(WR_START) begin
            wr_state          <= S_WA_WAIT;								//进入写地址等待阶段
            reg_wr_adrs[31:0] <= WR_ADRS[31:0];							//初始化写地址
            reg_wr_len[31:0]  <= WR_LEN[31:0] -32'd1;					//初始化写长度,0-255,从0开始故要减一,在输入的时候已经后面补了3’b000,数据个数在[10:3]内
			rd_first_data <= 1'b1;										//看不懂,跳过。
          end
          reg_awvalid         <= 1'b0;									//写地址有效信号归零
          reg_wvalid          <= 1'b0;									//写数据有效信号归零
          reg_w_last          <= 1'b0;                                  //一次突发写入的最后一次发送,而不是每次发送的最后一位数据
          reg_w_len[7:0]      <= 8'd0;                                  //写数据长度归零
          reg_w_stb[7:0]      <= 8'd0;                                  //写数据选通归零
          reg_wr_status[1:0]  <= 2'd0;                                  //写状态
        end
        S_WA_WAIT: begin
          if(!WR_FIFO_AEMPTY | (reg_wr_len[31:11] == 21'd0)) begin		//如果FIFO不空,里面有数据,或者 一次突发长度小于256开始写地址,因为FIFO没用,没理解或的作用
            wr_state          <= S_WA_START;
          end
		  rd_first_data <= 1'b0;
        end
        S_WA_START: begin												//写地址开始
          wr_state            <= S_WD_WAIT;								//进入下一阶段,写数据
          reg_awvalid         <= 1'b1;									//写地址有效	
          reg_wr_len[31:11]    <= reg_wr_len[31:11] - 21'd1;		    //注意此次减一和下一句判断是同步执行的,不要按顺序执行看代码,但也没弄明白为啥减一
          if(reg_wr_len[31:11] != 21'd0) begin                          //如果一次突发长度大于256
            reg_w_len[7:0]  <= 8'hFF;                                   //此次传输最大长度256
            reg_w_last      <= 1'b0;                                    //不是这次突发传输的结束
            reg_w_stb[7:0]  <= 8'hFF;                                   //选通,64位数据全都有效
          end else begin                                                //突发传输长度小于256
            reg_w_len[7:0]  <= reg_wr_len[10:3];						//赋值正确的传输数据长度
            reg_w_last      <= 1'b1;                                    //是最后一次传输
            reg_w_stb[7:0]  <= 8'hFF;                                   //64位全部有效
/*
            case(reg_wr_len[2:0]) begin
              case 3'd0: reg_w_stb[7:0]  <= 8'b0000_0000;
              case 3'd1: reg_w_stb[7:0]  <= 8'b0000_0001;
              case 3'd2: reg_w_stb[7:0]  <= 8'b0000_0011;
              case 3'd3: reg_w_stb[7:0]  <= 8'b0000_0111;
              case 3'd4: reg_w_stb[7:0]  <= 8'b0000_1111;
              case 3'd5: reg_w_stb[7:0]  <= 8'b0001_1111;
              case 3'd6: reg_w_stb[7:0]  <= 8'b0011_1111;
              case 3'd7: reg_w_stb[7:0]  <= 8'b0111_1111;
              default:   reg_w_stb[7:0]  <= 8'b1111_1111;
            endcase
*/
          end
        end
        S_WD_WAIT: begin                                                 //写数据等待
          if(M_AXI_AWREADY) begin                                        //如果写地址准备信号好了,在这一时钟地址已经传输进去了
            wr_state        <= S_WD_PROC;                                //下一阶段位数据传输周期阶段
            reg_awvalid     <= 1'b0;                                     //失效写地址有效信号
            reg_wvalid      <= 1'b1;                                     //使能写数据有效信号
          end                                                            
        end                                                              
        S_WD_PROC: begin                                                 //写循环周期
          if(M_AXI_WREADY & ~WR_FIFO_EMPTY) begin                        //如果写数据准备信号OK,且FIFO不口,这只是判断,硬件综合后,无论是否进入此阶段,只要awready有效就能开始写入,此阶段只是进行写数据计数,感觉有点别扭不可控
            if(reg_w_len[7:0] == 8'd0) begin                             //如果写完了
              wr_state        <= S_WR_WAIT;                              //进入写等待
              reg_wvalid      <= 1'b0;                                   //失效写数据信号
              reg_w_stb[7:0]  <= 8'h00;                                  //数据选通归零
            end else begin                                               
              reg_w_len[7:0]  <= reg_w_len[7:0] -8'd1;                   //每进入一次,计数减一
            end
          end
        end
        S_WR_WAIT: begin                                                 //等待写完反馈
          if(M_AXI_BVALID) begin                                         //如果反馈信号有效
            reg_wr_status[1:0]  <= reg_wr_status[1:0] | M_AXI_BRESP[1:0];//写数据状态赋值
            if(reg_w_last) begin                                         //是不是最后一段数据
              wr_state          <= S_WR_DONE;                            //是 写结束
            end else begin                                               
              wr_state          <= S_WA_WAIT;                            //不是 进入下一次写循环
              reg_wr_adrs[31:0] <= reg_wr_adrs[31:0] + 32'd2048;         //地址累加 128*8   128个数据  每个数据64位也就是8个8位
            end
          end
        end
        S_WR_DONE: begin
            wr_state <= S_WR_IDLE;										 //进入初始状态,等待下次发送请求	
          end
        
        default: begin
          wr_state <= S_WR_IDLE;
        end
      endcase
/*
      if(WR_FIFO_RE) begin
        reg_w_count[3:0]  <= reg_w_count[3:0] + 4'd1;
      end
      if(RD_FIFO_WE)begin
        reg_r_count[3:0]  <= reg_r_count[3:0] + 4'd1;
      end
      if(M_AXI_AWREADY & M_AXI_AWVALID) begin
        wr_chkdata <= 8'hEE;
      end else if(M_AXI_WSTRB[7] & M_AXI_WVALID) begin
        wr_chkdata <= WR_FIFO_DATA[63:56];
      end
      if(M_AXI_AWREADY & M_AXI_AWVALID) begin
        rd_chkdata <= 8'hDD;
      end else if(M_AXI_WSTRB[7] & M_AXI_WREADY) begin
        rd_chkdata <= WR_FIFO_DATA[63:56];
      end
      if(M_AXI_BVALID & M_AXI_BREADY) begin
        resp <= M_AXI_BRESP;
      end
*/
      end
    end
  end
   
  assign M_AXI_AWID         = 1'b0;												//UID,默认,不去修改
  assign M_AXI_AWADDR[31:0] = reg_wr_adrs[31:0];								//写地址赋值
  assign M_AXI_AWLEN[7:0]   = reg_w_len[7:0];									//虽然reg_w_len在累减,但是只有在127的时候valid有效
  assign M_AXI_AWSIZE[2:0]  = 2'b011;                                           //一个数据的大小 64位 = 8个8位 8=2^3
  assign M_AXI_AWBURST[1:0] = 2'b01;                                            //Burst type
  assign M_AXI_AWLOCK       = 1'b0;                                             //
  assign M_AXI_AWCACHE[3:0] = 4'b0011;                                          //
  assign M_AXI_AWPROT[2:0]  = 3'b000;                                           //
  assign M_AXI_AWQOS[3:0]   = 4'b0000;                                          //
  assign M_AXI_AWUSER[0]    = 1'b1;                                             //
  assign M_AXI_AWVALID      = reg_awvalid;                                      //写地址有效信号赋值
																				//
  assign M_AXI_WDATA[63:0]  = WR_FIFO_DATA[63:0];                               //写数据赋值
//  assign M_AXI_WSTRB[7:0]   = (reg_w_len[7:0] == 8'd0)?reg_w_stb[7:0]:8'hFF;  //
//  assign M_AXI_WSTRB[7:0]   = (wr_state == S_WD_PROC)?8'hFF:8'h00;            //
  assign M_AXI_WSTRB[7:0]   = (reg_wvalid & ~WR_FIFO_EMPTY)?8'hFF:8'h00;        //写数据选通
  assign M_AXI_WLAST        = (reg_w_len[7:0] == 8'd0)?1'b1:1'b0;               //一次突发的最后一个数据 和reg_w_last不同
  assign M_AXI_WUSER        = 1;                                                //
  assign M_AXI_WVALID       = reg_wvalid & ~WR_FIFO_EMPTY;                      //写数据有效信号
//  assign M_AXI_WVALID       = (wr_state == S_WD_PROC)?1'b1:1'b0;

  assign M_AXI_BREADY       = M_AXI_BVALID;										//只要有效就准备好接受

  assign WR_READY           = (wr_state == S_WR_IDLE)?1'b1:1'b0;				//只要在写初始化,表示主机这边准备好了,但是没见这个信号用在哪里
  
//  assign WR_FIFO_RE         = (wr_state == S_WD_PROC)?M_AXI_WREADY:1'b0;

  localparam S_RD_IDLE  = 3'd0;
  localparam S_RA_WAIT  = 3'd1;
  localparam S_RA_START = 3'd2;
  localparam S_RD_WAIT  = 3'd3;
  localparam S_RD_PROC  = 3'd4;
  localparam S_RD_DONE  = 3'd5;
  
  reg [2:0]   rd_state;
  reg [31:0]  reg_rd_adrs;
  reg [31:0]  reg_rd_len;
  reg         reg_arvalid, reg_r_last;
  reg [7:0]   reg_r_len;
 assign RD_DONE = (rd_state == S_RD_DONE) ; 									//进入读完状态后就输出读完了
  // Read State
  always @(posedge ACLK or negedge ARESETN) begin                               //
    if(!ARESETN) begin                                                          //复位,初始化各变量
      rd_state          <= S_RD_IDLE;                                           //
      reg_rd_adrs[31:0] <= 32'd0;                                               //
      reg_rd_len[31:0]  <= 32'd0;                                               //
      reg_arvalid       <= 1'b0;                                                //
      reg_r_len[7:0]    <= 8'd0;                                                //
    end else begin                                                              //
      case(rd_state)                                                            //
        S_RD_IDLE: begin                                                        //读状态初始化
          if(RD_START) begin                                                    //
            rd_state          <= S_RA_WAIT;                                     //进入写读地址等待阶段
            reg_rd_adrs[31:0] <= RD_ADRS[31:0];                                 //读地址赋值
            reg_rd_len[31:0]  <= RD_LEN[31:0] -32'd1;                           //读长度赋值,减一也是因为0-255
          end                                                                   //
          reg_arvalid     <= 1'b0;                                              //写地址有效信号失效
          reg_r_len[7:0]  <= 8'd0;                                              //读长度归零
        end                                                                     //
        S_RA_WAIT: begin                                                        //读地址等待阶段
          if(~RD_FIFO_AFULL) begin                                              //如果FIFO不满,可以往里面写
            rd_state          <= S_RA_START;                                    //进入写读地址阶段
          end                                                                   //
        end                                                                     //
        S_RA_START: begin                                                       //写读地址阶段
          rd_state          <= S_RD_WAIT;                                       //进入读数据阶段
          reg_arvalid       <= 1'b1;                                            //写读地址有效信号
          reg_rd_len[31:11] <= reg_rd_len[31:11] -21'd1;                        //
          if(reg_rd_len[31:11] != 21'd0) begin                                  //判断是否超过256
            reg_r_last      <= 1'b0;                                            //超过,不是最后一次传输
            reg_r_len[7:0]  <= 8'd255;                                          //长度最大值为256
          end else begin                                                        //
            reg_r_last      <= 1'b1;                                            //不超过,是最后一次传输
            reg_r_len[7:0]  <= reg_rd_len[10:3];                                //长度赋值
          end                                                                   //
        end                                                                     //
        S_RD_WAIT: begin                                                        //写数据等待
          if(M_AXI_ARREADY) begin                                               //如果写地址准备信号好了,在这一时钟地址已经传输进去了
            rd_state        <= S_RD_PROC;                                       //进入写数据循环阶段
            reg_arvalid     <= 1'b0;                                            //写地址有效信号失效
          end                                                                   //
        end                                                                     //
        S_RD_PROC: begin                                                        //写数据循环阶段
          if(M_AXI_RVALID) begin                                                //如果接受到从机的数据有效信号
            if(M_AXI_RLAST) begin                                               //如果是最后一个数据
              if(reg_r_last) begin                                              //如果是最后一次接收
                rd_state          <= S_RD_DONE;                                 //直接进入接收完成状态
              end else begin                                                    //如果不是最后一次接收
                rd_state          <= S_RA_WAIT;                                 //进入下一次接受状态
                reg_rd_adrs[31:0] <= reg_rd_adrs[31:0] + 32'd2048;              //地址累加
              end                                                               //
            end else begin                                                      //如果不是最后一个数据
              reg_r_len[7:0] <= reg_r_len[7:0] -8'd1;                           //接受长度累减
            end                                                                 //
          end
        end
		S_RD_DONE:begin
			rd_state          <= S_RD_IDLE;										//进入初始化阶段等待下一次读取请求
		end
			
	  endcase
    end
  end
   
  // Master Read Address                                                        //
  assign M_AXI_ARID         = 1'b0;                                             //
  assign M_AXI_ARADDR[31:0] = reg_rd_adrs[31:0];                                //读地址赋值
  assign M_AXI_ARLEN[7:0]   = reg_r_len[7:0];                                   //读长度赋值
  assign M_AXI_ARSIZE[2:0]  = 3'b011;                                           //读数据大小
  assign M_AXI_ARBURST[1:0] = 2'b01;                                            //
  assign M_AXI_ARLOCK       = 1'b0;                                             //
  assign M_AXI_ARCACHE[3:0] = 4'b0011;                                          //
  assign M_AXI_ARPROT[2:0]  = 3'b000;                                           //
  assign M_AXI_ARQOS[3:0]   = 4'b0000;                                          //
  assign M_AXI_ARUSER[0]    = 1'b1;                                             //
  assign M_AXI_ARVALID      = reg_arvalid;                                      //地址有效信号
																				//
  assign M_AXI_RREADY       = M_AXI_RVALID & ~RD_FIFO_FULL;						//主机已经准备好接受的信号,与从机发送的数据有效信号同步, debug看下时序,就是相当于连起来了,同步执行

  assign RD_READY           = (rd_state == S_RD_IDLE)?1'b1:1'b0;				//读数据准备
  assign RD_FIFO_WE         = M_AXI_RVALID;                                     //传给FIFO,读有效
  assign RD_FIFO_DATA[63:0] = M_AXI_RDATA[63:0];                                //传出读出的数据
																				//
  assign DEBUG[31:0] = {reg_wr_len[31:8],                                       //
                        1'd0, wr_state[2:0], 1'd0, rd_state[2:0]};              //
   
endmodule


有两个时序值得说一下

第一个 这个判断是下一个时序才会起效,req在上一个时钟使能,在下一个时钟判断起效

在这里插入图片描述

在这里插入图片描述

第二个 valid

在这里插入图片描述
在valid和ready使能的同时,此时钟下的信号就是将要写进去的信号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值