Created
October 21, 2025 04:48
-
-
Save nickfox-taterli/a3623931090590aa3b0936a550a3a907 to your computer and use it in GitHub Desktop.
s2mm 对接 AXI DataMover
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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