Skip to content

Instantly share code, notes, and snippets.

@nickfox-taterli
Created October 21, 2025 04:48
Show Gist options
  • Select an option

  • Save nickfox-taterli/a3623931090590aa3b0936a550a3a907 to your computer and use it in GitHub Desktop.

Select an option

Save nickfox-taterli/a3623931090590aa3b0936a550a3a907 to your computer and use it in GitHub Desktop.
s2mm 对接 AXI DataMover
// Language: Verilog 2001
`timescale 1ns/1ps
`default_nettype none
module s2mm_2k_burst #
(
parameter integer AXIS_DW = 32, // DataMover S_AXIS_S2MM 数据位宽
parameter [63:0] BASE_ADDR = 64'h0000_0000_1000_0000 // 目标 DDR 地址(64b)
)
(
// 同域时钟复位
(* X_INTERFACE_PARAMETER = "XIL_INTERFACENAME aclk, ASSOCIATED_BUSIF S_AXIS_S2MM:S_AXIS_S2MM_CMD:M_AXIS_S2MM_STS, ASSOCIATED_RESET aresetn" *)
(* X_INTERFACE_INFO = "xilinx.com:signal:clock:1.0 aclk CLK" *)
input wire aclk,
(* X_INTERFACE_INFO = "xilinx.com:signal:reset:1.0 aresetn RST" *)
input wire aresetn,
input wire start, // VIO 上升沿触发
// ------ S_AXIS_S2MM(数据)------
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 S_AXIS_S2MM TDATA" *)
output reg [AXIS_DW-1:0] s_axis_s2mm_tdata,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 S_AXIS_S2MM TKEEP" *)
output reg [(AXIS_DW/8)-1:0] s_axis_s2mm_tkeep,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 S_AXIS_S2MM TLAST" *)
output reg s_axis_s2mm_tlast,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 S_AXIS_S2MM TVALID" *)
output reg s_axis_s2mm_tvalid,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 S_AXIS_S2MM TREADY" *)
input wire s_axis_s2mm_tready,
// ------ S_AXIS_S2MM_CMD(命令,64b地址→104b,单拍,无TLAST)------
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 S_AXIS_S2MM_CMD TDATA" *)
output reg [103:0] s_axis_s2mm_cmd_tdata,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 S_AXIS_S2MM_CMD TVALID" *)
output reg s_axis_s2mm_cmd_tvalid,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 S_AXIS_S2MM_CMD TREADY" *)
input wire s_axis_s2mm_cmd_tready,
// ------ M_AXIS_S2MM_STS(状态 8b 单拍)------
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 M_AXIS_S2MM_STS TDATA" *)
input wire [7:0] m_axis_s2mm_sts_tdata,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 M_AXIS_S2MM_STS TKEEP" *)
input wire [0:0] m_axis_s2mm_sts_tkeep,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 M_AXIS_S2MM_STS TLAST" *)
input wire m_axis_s2mm_sts_tlast,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 M_AXIS_S2MM_STS TVALID" *)
input wire m_axis_s2mm_sts_tvalid,
(* X_INTERFACE_INFO = "xilinx.com:interface:axis:1.0 M_AXIS_S2MM_STS TREADY" *)
output wire m_axis_s2mm_sts_tready
);
// 常量
localparam integer BYTES_TOTAL = 2048;
localparam integer BEAT_BYTES = (AXIS_DW/8);
localparam integer BEATS_TOTAL = BYTES_TOTAL/BEAT_BYTES; // 32bit→512 拍
// Verilog-2001 版 CLOG2
function integer CLOG2;
input integer x; integer v; begin v=0; x=x-1; while (x>0) begin x=x>>1; v=v+1; end CLOG2=v; end
endfunction
localparam integer CNT_W = CLOG2(BEATS_TOTAL);
// start 边沿
reg start_d;
always @(posedge aclk) begin
if (!aresetn) start_d <= 1'b0;
else start_d <= start;
end
wire start_pulse = start & ~start_d;
// 计数
reg [CNT_W-1:0] beat_cnt;
wire last_beat = (beat_cnt == BEATS_TOTAL-1);
// 状态口一直 ready
assign m_axis_s2mm_sts_tready = 1'b1;
// FSM(2001),并让它 KEEP + DEBUG 方便 ILA 盯
localparam [1:0] IDLE = 2'd0,
SEND_CMD = 2'd1,
SEND_DATA = 2'd2,
WAIT_STS = 2'd3;
(* keep = "true", mark_debug = "true" *) reg [1:0] state;
// 单 always 时序 FSM;条件里直接写 AXIS 端口名
always @(posedge aclk) begin
if (!aresetn) begin
state <= IDLE;
s_axis_s2mm_cmd_tdata <= 104'd0;
s_axis_s2mm_cmd_tvalid <= 1'b0;
s_axis_s2mm_tdata <= {AXIS_DW{1'b0}};
s_axis_s2mm_tkeep <= {BEAT_BYTES{1'b1}};
s_axis_s2mm_tlast <= 1'b0;
s_axis_s2mm_tvalid <= 1'b0;
beat_cnt <= {CNT_W{1'b0}};
end else begin
case (state)
IDLE: begin
if (start_pulse) begin
// {USER[3:0],CACHE[3:0],RSVD[3:0],TAG[3:0],SADDR[63:0],DRR,EOF,DSA[5:0],TYPE,BTT[22:0]}
s_axis_s2mm_cmd_tdata <= {4'h0,4'h0,4'h0,4'h0, BASE_ADDR[63:0], 1'b0, 1'b1, 6'd0, 1'b1, BYTES_TOTAL[22:0]};
s_axis_s2mm_cmd_tvalid <= 1'b1;
s_axis_s2mm_tdata <= {AXIS_DW{1'b0}}; // 0..(BEATS_TOTAL-1)
s_axis_s2mm_tkeep <= {BEAT_BYTES{1'b1}};
s_axis_s2mm_tlast <= (BEATS_TOTAL==1);
s_axis_s2mm_tvalid <= 1'b0;
beat_cnt <= {CNT_W{1'b0}};
state <= SEND_CMD;
end
end
// 命令单拍:握手发生 → 立刻点火数据 TVALID,下一拍开始送
SEND_CMD: begin
if (s_axis_s2mm_cmd_tvalid & s_axis_s2mm_cmd_tready) begin
s_axis_s2mm_cmd_tvalid <= 1'b0;
s_axis_s2mm_tvalid <= 1'b1;
s_axis_s2mm_tlast <= (BEATS_TOTAL==1);
state <= SEND_DATA;
end
end
// 送满 2KB,最后一拍 TLAST=1
SEND_DATA: begin
if (s_axis_s2mm_tvalid & s_axis_s2mm_tready) begin
if (last_beat) begin
// 本拍为最后一拍:该拍握手同时 TLAST=1,然后收尾
s_axis_s2mm_tvalid <= 1'b0;
s_axis_s2mm_tlast <= 1'b0;
state <= WAIT_STS;
end else begin
beat_cnt <= beat_cnt + {{(CNT_W-1){1'b0}},1'b1};
s_axis_s2mm_tdata <= s_axis_s2mm_tdata + {{(AXIS_DW-1){1'b0}},1'b1};
// 预置"下一拍是否最后一拍"
s_axis_s2mm_tlast <= (beat_cnt + 1 == BEATS_TOTAL-1);
end
end
end
// 收状态一拍即可回到空闲(如需更严谨,可检查 m_axis_s2mm_sts_tdata[7])
WAIT_STS: begin
if (m_axis_s2mm_sts_tvalid & m_axis_s2mm_sts_tlast) begin
state <= IDLE;
end
end
endcase
end
end
endmodule
`default_nettype wire
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment