uiFDMA用状态机改写 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki
原版代码
uiFDMA.v
`timescale 1ns / 1ns
/*
Company : Liyang Milian Electronic Technology Co., Ltd.
Technical forum:uisrc.com
taobao1: milianke.taobao.com
taobao2: osrc.taobao.com
jd:milianke.jd.com
Create Date: 2019/12/17
Module Name: uiFDMA2.0
Description:
Copyright: Copyright (c) msxbo
Revision: 1.0
Signal description:
1) _i input
2) _o output
3) _n activ low
4) _dg debug signal
5) _r delay or register
6) _s state mechine
*/
////////////////////////////////////////////////////////////////////////////////
module uiFDMA#
(
parameter integer M_AXI_ID_WIDTH = 1 ,
parameter integer M_AXI_ID = 0 ,
parameter integer M_AXI_ADDR_WIDTH = 32 ,
parameter integer M_AXI_DATA_WIDTH = 128
)
(
input wire [M_AXI_ADDR_WIDTH-1 : 0] fdma_waddr ,
input fdma_wareq ,
input wire [15 : 0] fdma_wsize ,
output fdma_wbusy ,
input wire [M_AXI_DATA_WIDTH-1 :0] fdma_wdata ,
output wire fdma_wvalid ,
input wire fdma_wready ,
input wire [M_AXI_ADDR_WIDTH-1 : 0] fdma_raddr ,
input fdma_rareq ,
input wire [15 : 0] fdma_rsize ,
output fdma_rbusy ,
output wire [M_AXI_DATA_WIDTH-1 :0] fdma_rdata ,
output wire fdma_rvalid ,
input wire fdma_rready ,
input wire M_AXI_ACLK ,
input wire M_AXI_ARESETN ,
output wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_AWID ,//д��ַID��������־һ��д�ź�
output wire [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 ,//��������QoS
output wire M_AXI_AWVALID ,//��Ч�źţ�������ͨ���ĵ�ַ�����ź���Ч
input wire M_AXI_AWREADY ,//�������ӡ����Խ��յ�ַ�Ͷ�Ӧ�Ŀ����ź�
output wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_WID ,//д��ӦID tag
output wire [M_AXI_DATA_WIDTH-1 : 0] M_AXI_WDATA ,//���
output wire [M_AXI_DATA_WIDTH/8-1 : 0] M_AXI_WSTRB ,//д������Ч���ֽ��ߣ�����������8bits��������Ч��
output wire M_AXI_WLAST ,//�����˴δ��������һ��ͻ������
output wire M_AXI_WVALID ,//д��Ч�������˴�д��Ч
input wire M_AXI_WREADY ,//�����ӻ����Խ���д����
input wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_BID ,//д��ӦID tag
input wire [1 : 0] M_AXI_BRESP ,//д��Ӧ������д�����״̬
input wire M_AXI_BVALID ,//д��Ӧ��Ч
output wire M_AXI_BREADY , //���������ܹ�����д��Ӧ
output wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_ARID ,
output wire [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 M_AXI_ARVALID ,
input wire M_AXI_ARREADY ,
input wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_RID ,
input wire [M_AXI_DATA_WIDTH-1 : 0] M_AXI_RDATA ,
input wire [1 : 0] M_AXI_RRESP ,
input wire M_AXI_RLAST ,
input wire M_AXI_RVALID ,
output wire M_AXI_RREADY
);
localparam AXI_BYTES = M_AXI_DATA_WIDTH/8;
function integer clogb2 (input integer bit_depth);
begin
for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
bit_depth = bit_depth >> 1;
end
endfunction
//fdma axi write----------------------------------------------
reg [M_AXI_ADDR_WIDTH-1 : 0] axi_awaddr =0;
reg axi_awvalid = 1'b0;
wire [M_AXI_DATA_WIDTH-1 : 0] axi_wdata ;
wire axi_wlast ;
reg axi_wvalid = 1'b0;
wire w_next = (M_AXI_WVALID & M_AXI_WREADY);
reg [8 :0] wburst_len = 1 ;
reg [8 :0] wburst_cnt = 0 ;
reg [15:0] wfdma_cnt = 0 ;
reg axi_wstart_locked =0;
wire [15:0] axi_wburst_size = wburst_len * AXI_BYTES;
assign M_AXI_AWID = M_AXI_ID;
assign M_AXI_AWADDR = axi_awaddr;
assign M_AXI_AWLEN = wburst_len - 1;
assign M_AXI_AWSIZE = clogb2(AXI_BYTES-1);
assign M_AXI_AWBURST = 2'b01;
assign M_AXI_AWLOCK = 1'b0;
assign M_AXI_AWCACHE = 4'b0010;
assign M_AXI_AWPROT = 3'h0;
assign M_AXI_AWQOS = 4'h0;
assign M_AXI_AWVALID = axi_awvalid;
assign M_AXI_WDATA = axi_wdata;
assign M_AXI_WSTRB = {(AXI_BYTES){1'b1}};
assign M_AXI_WLAST = axi_wlast;
assign M_AXI_WVALID = axi_wvalid & fdma_wready;
assign M_AXI_BREADY = 1'b1;
//----------------------------------------------------------------------------
//AXI4 FULL Write
assign axi_wdata = fdma_wdata;
assign fdma_wvalid = w_next;
reg fdma_wstart_locked = 1'b0;
wire fdma_wend;
wire fdma_wstart;
assign fdma_wbusy = fdma_wstart_locked ;
always @(posedge M_AXI_ACLK)
if(M_AXI_ARESETN == 1'b0 || fdma_wend == 1'b1 )
fdma_wstart_locked <= 1'b0;
else if(fdma_wstart)
fdma_wstart_locked <= 1'b1;
assign fdma_wstart = (fdma_wstart_locked == 1'b0 && fdma_wareq == 1'b1);
//AXI4 write burst lenth busrt addr ------------------------------
always @(posedge M_AXI_ACLK)
if(fdma_wstart)
axi_awaddr <= fdma_waddr;
else if(axi_wlast == 1'b1)
axi_awaddr <= axi_awaddr + axi_wburst_size ;
//AXI4 write cycle -----------------------------------------------
reg axi_wstart_locked_r1 = 1'b0, axi_wstart_locked_r2 = 1'b0;
always @(posedge M_AXI_ACLK)begin
axi_wstart_locked_r1 <= axi_wstart_locked;
axi_wstart_locked_r2 <= axi_wstart_locked_r1;
end
always @(posedge M_AXI_ACLK)
if((fdma_wstart_locked == 1'b1) && axi_wstart_locked == 1'b0)
axi_wstart_locked <= 1'b1;
else if(axi_wlast == 1'b1 || fdma_wstart == 1'b1)
axi_wstart_locked <= 1'b0;
//AXI4 addr valid and write addr-----------------------------------
always @(posedge M_AXI_ACLK)
if((axi_wstart_locked_r1 == 1'b1) && axi_wstart_locked_r2 == 1'b0)
axi_awvalid <= 1'b1;
else if((axi_wstart_locked == 1'b1 && M_AXI_AWREADY == 1'b1)|| axi_wstart_locked == 1'b0)
axi_awvalid <= 1'b0;
//AXI4 write data---------------------------------------------------
always @(posedge M_AXI_ACLK)
if((axi_wstart_locked_r1 == 1'b1) && axi_wstart_locked_r2 == 1'b0)
axi_wvalid <= 1'b1;
else if(axi_wlast == 1'b1 || axi_wstart_locked == 1'b0)
axi_wvalid <= 1'b0;//
//AXI4 write data burst len counter----------------------------------
always @(posedge M_AXI_ACLK)
if(axi_wstart_locked == 1'b0)
wburst_cnt <= 'd0;
else if(w_next)
wburst_cnt <= wburst_cnt + 1'b1;
assign axi_wlast = (w_next == 1'b1) && (wburst_cnt == M_AXI_AWLEN);
//fdma write data burst len counter----------------------------------
reg wburst_len_req = 1'b0;
reg [15:0] fdma_wleft_cnt =16'd0;
always @(posedge M_AXI_ACLK)
wburst_len_req <= fdma_wstart|axi_wlast;
always @(posedge M_AXI_ACLK)
if( fdma_wstart )begin
wfdma_cnt <= 1'd0;
fdma_wleft_cnt <= fdma_wsize;
end
else if(w_next)begin
wfdma_cnt <= wfdma_cnt + 1'b1;
fdma_wleft_cnt <= (fdma_wsize - 1'b1) - wfdma_cnt;
end
assign fdma_wend = w_next && (fdma_wleft_cnt == 1 );
always @(posedge M_AXI_ACLK)begin
if(wburst_len_req)begin
if(fdma_wleft_cnt[15:8] >0) wburst_len <= 256;
else
wburst_len <= fdma_wleft_cnt[7:0];
end
else wburst_len <= wburst_len;
end
//fdma axi read----------------------------------------------
reg [M_AXI_ADDR_WIDTH-1 : 0] axi_araddr =0 ;
reg axi_arvalid =1'b0;
wire axi_rlast ;
reg axi_rready = 1'b0;
wire r_next = (M_AXI_RVALID && M_AXI_RREADY);
reg [8 :0] rburst_len = 1 ;
reg [8 :0] rburst_cnt = 0 ;
reg [15:0] rfdma_cnt = 0 ;
reg axi_rstart_locked =0;
wire [15:0] axi_rburst_size = rburst_len * AXI_BYTES;
assign M_AXI_ARID = M_AXI_ID;
assign M_AXI_ARADDR = axi_araddr;
assign M_AXI_ARLEN = rburst_len - 1;
assign M_AXI_ARSIZE = clogb2((AXI_BYTES)-1);
assign M_AXI_ARBURST = 2'b01;
assign M_AXI_ARLOCK = 1'b0;
assign M_AXI_ARCACHE = 4'b0010;
assign M_AXI_ARPROT = 3'h0;
assign M_AXI_ARQOS = 4'h0;
assign M_AXI_ARVALID = axi_arvalid;
assign M_AXI_RREADY = axi_rready&&fdma_rready;
assign fdma_rdata = M_AXI_RDATA;
assign fdma_rvalid = r_next;
//AXI4 FULL Read-----------------------------------------
reg fdma_rstart_locked = 1'b0;
wire fdma_rend;
wire fdma_rstart;
assign fdma_rbusy = fdma_rstart_locked ;
always @(posedge M_AXI_ACLK)
if(M_AXI_ARESETN == 1'b0 || fdma_rend == 1'b1)
fdma_rstart_locked <= 1'b0;
else if(fdma_rstart)
fdma_rstart_locked <= 1'b1;
assign fdma_rstart = (fdma_rstart_locked == 1'b0 && fdma_rareq == 1'b1);
//AXI4 read burst lenth busrt addr ------------------------------
always @(posedge M_AXI_ACLK)
if(fdma_rstart == 1'b1)
axi_araddr <= fdma_raddr;
else if(axi_rlast == 1'b1)
axi_araddr <= axi_araddr + axi_rburst_size ;
//AXI4 r_cycle_flag-------------------------------------
reg axi_rstart_locked_r1 = 1'b0, axi_rstart_locked_r2 = 1'b0;
always @(posedge M_AXI_ACLK)begin
axi_rstart_locked_r1 <= axi_rstart_locked;
axi_rstart_locked_r2 <= axi_rstart_locked_r1;
end
always @(posedge M_AXI_ACLK)
if((fdma_rstart_locked == 1'b1) && axi_rstart_locked == 1'b0)
axi_rstart_locked <= 1'b1;
else if(axi_rlast == 1'b1 || fdma_rstart == 1'b1)
axi_rstart_locked <= 1'b0;
//AXI4 addr valid and read addr-----------------------------------
always @(posedge M_AXI_ACLK)
if((axi_rstart_locked_r1 == 1'b1) && axi_rstart_locked_r2 == 1'b0)
axi_arvalid <= 1'b1;
else if((axi_rstart_locked == 1'b1 && M_AXI_ARREADY == 1'b1)|| axi_rstart_locked == 1'b0)
axi_arvalid <= 1'b0;
//AXI4 read data---------------------------------------------------
always @(posedge M_AXI_ACLK)
if((axi_rstart_locked_r1 == 1'b1) && axi_rstart_locked_r2 == 1'b0)
axi_rready <= 1'b1;
else if(axi_rlast == 1'b1 || axi_rstart_locked == 1'b0)
axi_rready <= 1'b0;//
//AXI4 read data burst len counter----------------------------------
always @(posedge M_AXI_ACLK)
if(axi_rstart_locked == 1'b0)
rburst_cnt <= 'd0;
else if(r_next)
rburst_cnt <= rburst_cnt + 1'b1;
assign axi_rlast = (r_next == 1'b1) && (rburst_cnt == M_AXI_ARLEN);
//fdma read data burst len counter----------------------------------
reg rburst_len_req = 1'b0;
reg [15:0] fdma_rleft_cnt =16'd0;
always @(posedge M_AXI_ACLK)
rburst_len_req <= fdma_rstart | axi_rlast;
always @(posedge M_AXI_ACLK)
if(fdma_rstart )begin
rfdma_cnt <= 1'd0;
fdma_rleft_cnt <= fdma_rsize;
end
else if(r_next)begin
rfdma_cnt <= rfdma_cnt + 1'b1;
fdma_rleft_cnt <= (fdma_rsize - 1'b1) - rfdma_cnt;
end
assign fdma_rend = r_next && (fdma_rleft_cnt == 1 );
//axi auto burst len caculate-----------------------------------------
always @(posedge M_AXI_ACLK)begin
if(rburst_len_req)begin
if(fdma_rleft_cnt[15:8] >0)
rburst_len <= 256;
else
rburst_len <= fdma_rleft_cnt[7:0];
end
else rburst_len <= rburst_len;
end
endmodule
状态机改写后的代码(chatgpt)
uiFDMA.sv
module uiFDMA#
(
parameter integer M_AXI_ID_WIDTH = 1,
parameter integer M_AXI_ID = 0,
parameter integer M_AXI_ADDR_WIDTH = 32,
parameter integer M_AXI_DATA_WIDTH = 128
)
(
input wire [M_AXI_ADDR_WIDTH-1 : 0] fdma_waddr,
input fdma_wareq,
input wire [15 : 0] fdma_wsize,
output reg fdma_wbusy,
input wire [M_AXI_DATA_WIDTH-1 :0] fdma_wdata,
output reg fdma_wvalid,
input wire fdma_wready,
input wire [M_AXI_ADDR_WIDTH-1 : 0] fdma_raddr,
input fdma_rareq,
input wire [15 : 0] fdma_rsize,
output reg fdma_rbusy,
output wire [M_AXI_DATA_WIDTH-1 :0] fdma_rdata,
output reg fdma_rvalid,
input wire fdma_rready,
input wire M_AXI_ACLK,
input wire M_AXI_ARESETN,
output wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_AWID,
output reg [M_AXI_ADDR_WIDTH-1 : 0] M_AXI_AWADDR,
output reg [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 reg M_AXI_AWVALID,
input wire M_AXI_AWREADY,
output wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_WID,
output reg [M_AXI_DATA_WIDTH-1 : 0] M_AXI_WDATA,
output wire [M_AXI_DATA_WIDTH/8-1 : 0] M_AXI_WSTRB,
output reg M_AXI_WLAST,
output reg M_AXI_WVALID,
input wire M_AXI_WREADY,
input wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_BID,
input wire [1 : 0] M_AXI_BRESP,
input wire M_AXI_BVALID,
output wire M_AXI_BREADY,
output wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_ARID,
output reg [M_AXI_ADDR_WIDTH-1 : 0] M_AXI_ARADDR,
output reg [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 reg M_AXI_ARVALID,
input wire M_AXI_ARREADY,
input wire [M_AXI_ID_WIDTH-1 : 0] M_AXI_RID,
input wire [M_AXI_DATA_WIDTH-1 : 0] M_AXI_RDATA,
input wire [1 : 0] M_AXI_RRESP,
input wire M_AXI_RLAST,
input wire M_AXI_RVALID,
output reg M_AXI_RREADY
);
localparam AXI_BYTES = M_AXI_DATA_WIDTH / 8;
// Write state machine states
typedef enum logic [2:0] {
W_IDLE,
W_ADDR,
W_DATA,
W_RESP
} w_state_t;
w_state_t w_state = W_IDLE;
// Read state machine states
typedef enum logic [2:0] {
R_IDLE,
R_ADDR,
R_DATA
} r_state_t;
r_state_t r_state = R_IDLE;
reg [15:0] wfdma_cnt = 0;
reg [15:0] rfdma_cnt = 0;
reg [8:0] wburst_len = 0;
reg [8:0] rburst_len = 0;
assign M_AXI_AWID = M_AXI_ID;
assign M_AXI_WID = M_AXI_ID;
assign M_AXI_AWLEN = wburst_len - 1;
assign M_AXI_AWSIZE = clogb2(AXI_BYTES - 1);
assign M_AXI_AWBURST = 2'b01;
assign M_AXI_AWLOCK = 1'b0;
assign M_AXI_AWCACHE = 4'b0010;
assign M_AXI_AWPROT = 3'h0;
assign M_AXI_AWQOS = 4'h0;
assign M_AXI_WSTRB = {(AXI_BYTES){1'b1}};
assign M_AXI_BREADY = 1'b1;
assign M_AXI_ARID = M_AXI_ID;
assign M_AXI_ARLEN = rburst_len - 1;
assign M_AXI_ARSIZE = clogb2(AXI_BYTES - 1);
assign M_AXI_ARBURST = 2'b01;
assign M_AXI_ARLOCK = 1'b0;
assign M_AXI_ARCACHE = 4'b0010;
assign M_AXI_ARPROT = 3'h0;
assign M_AXI_ARQOS = 4'h0;
assign fdma_rdata = M_AXI_RDATA;
function integer clogb2(input integer bit_depth);
integer i;
begin
clogb2 = 0;
for (i = 0; bit_depth > 0; i = i + 1)
bit_depth = bit_depth >> 1;
clogb2 = i;
end
endfunction
// Write state machine
always @(posedge M_AXI_ACLK) begin
if (!M_AXI_ARESETN) begin
w_state <= W_IDLE;
M_AXI_AWADDR <= 0;
M_AXI_AWVALID <= 1'b0;
M_AXI_WDATA <= 0;
M_AXI_WVALID <= 1'b0;
M_AXI_WLAST <= 1'b0;
wfdma_cnt <= 0;
fdma_wbusy <= 1'b0;
fdma_wvalid <= 1'b0;
end else begin
case (w_state)
W_IDLE: begin
fdma_wbusy <= 1'b0;
if (fdma_wareq) begin
M_AXI_AWADDR <= fdma_waddr;
wburst_len <= (fdma_wsize > 256) ? 256 : fdma_wsize[7:0];
w_state <= W_ADDR;
end
end
W_ADDR: begin
fdma_wbusy <= 1'b1;
M_AXI_AWVALID <= 1'b1;
if (M_AXI_AWREADY) begin
M_AXI_AWVALID <= 1'b0;
w_state <= W_DATA;
end
end
W_DATA: begin
M_AXI_WDATA <= fdma_wdata;
M_AXI_WVALID <= 1'b1;
M_AXI_WLAST <= (wfdma_cnt == (wburst_len - 1));
fdma_wvalid <= M_AXI_WREADY;
if (M_AXI_WREADY) begin
wfdma_cnt <= wfdma_cnt + 1;
if (M_AXI_WLAST) begin
w_state <= W_RESP;
end
end
end
W_RESP: begin
M_AXI_WVALID <= 1'b0;
if (M_AXI_BVALID) begin
w_state <= W_IDLE;
end
end
endcase
end
end
// Read state machine
always @(posedge M_AXI_ACLK) begin
if (!M_AXI_ARESETN) begin
r_state <= R_IDLE;
M_AXI_ARADDR <= 0;
M_AXI_ARVALID <= 1'b0;
M_AXI_RREADY <= 1'b0;
rfdma_cnt <= 0;
fdma_rbusy <= 1'b0;
fdma_rvalid <= 1'b0;
rburst_len <= 0;
end else begin
case (r_state)
R_IDLE: begin
fdma_rbusy <= 1'b0;
if (fdma_rareq) begin
M_AXI_ARADDR <= fdma_raddr;
rburst_len <= (fdma_rsize > 256) ? 256 : fdma_rsize[7:0];
M_AXI_ARLEN <= rburst_len - 1; // 使用 rburst_len 设置 ARLEN 信号
r_state <= R_ADDR;
end
end
R_ADDR: begin
fdma_rbusy <= 1'b1;
M_AXI_ARVALID <= 1'b1;
if (M_AXI_ARREADY) begin
M_AXI_ARVALID <= 1'b0;
r_state <= R_DATA;
end
end
R_DATA: begin
M_AXI_RREADY <= 1'b1;
if (M_AXI_RVALID) begin
fdma_rvalid <= 1'b1;
rfdma_cnt <= rfdma_cnt + 1;
if (M_AXI_RLAST) begin
r_state <= R_IDLE;
end
end
end
endcase
end
end
endmodule