news 2026/4/16 1:52:19

vivado PL与PS的数据交互之AXI4_LITE 协议

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
vivado PL与PS的数据交互之AXI4_LITE 协议

以下内容仅记录本人工作中发现的问题以及解决方法,仅供参考。

文章记录了作者在基于zynq平台PL与PS的数据交互开发过程中,总结的AXI4_LITE通信协议开发经验,并在文章中详细介绍了VIVADO软件中AXI4_LITE IP核的生成、测试版本及正式版本工程BD(BLOCK DESIGN)的搭建、从机PL端AXI4_LITE IP核的协议层代码开发、主机PS端应用层的代码开发、仿真测试工程以及上板工程的完整代码及测试结果。

本文着重介绍PL与PS的AXI4-Lite协议交互,AXI4-Lite协议的PL端应用开发详见另一篇笔记:vivado PL端串口通信协议及AXI_Uartlite (2.0)IP驱动开发​​​​https://blog.csdn.net/weixin_46168087/article/details/155612353?spm=1001.2014.3001.5502

一、AXI4_LITE协议概述

AXI协议官方下载链接:https://developer.arm.com/documentation/ihi0022/latest

AXI4-Lite 是 AXI4 协议的轻量级子集,专为低速、低带宽的控制类交互设计(如寄存器读写、外设配置),是 Zynq-7000中 PS与 PL通信的核心总线之一,也是嵌入式硬件开发中最常用的 AXI 子协议。

协议适用场景核心差异
AXI4-Lite低速控制(寄存器读写)无突发、固定 32/64 位、轻量
AXI4高速数据传输(如 DDR)支持突发(最大 256 拍)、缓存
AXI-Stream流式数据(如视频 / 音频)无地址、连续数据流、低延迟

1.AXI4-LITE协议接口

AXI4-Lite 包括全局时钟复位和 5 个独立通道(写地址/写数据/写响应/读地址/读数据通道),主设备(如 Zynq PS)发起请求,从设备(如 PL 自定义 IP)响应,AXI4-Lite协议接口如下:

序号类型命名位宽(bit)输入/输出定义
1全局信号ACLK1input时钟
2ARESET1input复位:低有效
3写地址通道AWVALID1input写地址有效位:高有效
4AWREADY1output从机写地址通道准备就绪信号:高有效
5AWDATA4input写地址
7写数据通道WVALID1input写数据有效位:高有效
8WREADY1output从机写数据通道准备就绪信号:高有效
9WDATA32input写数据
10WSTRB4input

写数据选择:bit[0]=1=data[7:0]

bit[1]=1=data[15:8]以此类推,默认全高

11写响应通道BVALID1output写入响应有效位:高有效
12BREADY1input主机接收响应通道准备就绪信号:高有效
13BRESP2output写响应状态(一般不用)
14读地址通道ARVALID1input读地址有效位:高有效
15ARREADY1output从机读地址通道准备就绪信号:高有效
16ARDATA4input读地址
18读数据通道RVALID1output读数据有效位:高有效
19RREADY1input主机读数据通道准备就绪信号:高有效
20RDATA32output读数据
21RRESP2output读响应状态(00 = 成功,一般不用)

2.AXI4-Lite 写数据工作流程

写入、读取之间存在通道依赖关系。读写流程示意图中的单向箭头表示可在箭头起点信号前或后触发的信号。双向箭头表示必须在箭头起点信号触发后才能触发的信号。

根据写数据流程图可知,写数据只与三个通道有关,写地址通道/写数据通道/写响应通道,简单概括一下写数据的流程为:

step1:写入数据(WDATA)、写入地址(AWDATA)、写数据有效位拉高(WVALID)、写地址有效位拉高(AWVALID)

step2:等待从机写数据通道准备就绪(WREADY)、等待从机写地址通道准备就绪(AWREADY)

step3:等待写入响应有效(BVALID)、主机接收响应通道准备就绪信号拉高(BREADY)、返回step1循环

3.AXI4-Lite 读数据 工作流程

根据读数据流程图可知,读数据只与两个通道有关,读地址通道/读数据通道,简单概括一下读数据的流程为::

step1:写入读地址(ARDATA)、读地址有效位拉高(WVALID)

step2:等待从机读地址通道准备就绪(ARREADY)

step3:主机读数据通道准备就绪信号拉高(RREADY)

step4:等待从机读数据有效位拉高(RVALID)、提取数据(RDATA)、返回step1循环

二、AXI4_LITE IP核

1.AXI4-Lite IP核的生成

打开vivado软件,点击Tools下拉选项,点击Create and Package New IP。

点击next。

这里选择IP存放的路径,以及更改自定义IP的命名为axi4_lite_slave。

接口模式选择从机模式,寄存器数量先随便写4,后面再改。

选择编辑IP,进行下一步根据实际应用来更改IP。

2.AXI4-Lite IP核的应用

在上一章节点击完成后可以看到IP编辑界面已经打开,IP已经生成,观察代码可以发现读数据状态机的内容,即为重复4个寄存器的读写,若前面设置寄存器数量为128个,则状态机会重复128次,简化状态机,以及根据自己的需求定义读写数据寄存器的个数,定义AXI4_lite协议的基地址,将需要读出的值提出来,需要写入的值发出去,就是本节IP核的应用中改造这段代码的目的。

本实验自定义PL端从地址0x43c00000中读取来自PS端的6个32位的数data_out0~data_out5,PL端向PS端给地址0x43c00000写入4个32位的数data_in0~data_in3。

更改后的axi4_lite_slave_v1_0_S00_AXI.v文件:

module axi4_lite_slave_v1_0_S00_AXI #( parameter integer C_S_AXI_DATA_WIDTH = 32, parameter integer C_S_AXI_ADDR_WIDTH = 32, parameter integer S_AXI_RD_DATA_DEPTH = 6, parameter integer S_AXI_WR_DATA_DEPTH = 4, parameter integer S_AXI_RDADDR_BASE = 32'h43c00000 )( input wire S_AXI_ACLK , input wire S_AXI_ARESETN , input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR , input wire [2 : 0] S_AXI_AWPROT , input wire S_AXI_AWVALID , output wire S_AXI_AWREADY , input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA , input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB , input wire S_AXI_WVALID , output wire S_AXI_WREADY , output wire [1 : 0] S_AXI_BRESP , output wire S_AXI_BVALID , input wire S_AXI_BREADY , input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR , input wire [2 : 0] S_AXI_ARPROT , input wire S_AXI_ARVALID , output wire S_AXI_ARREADY , output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA , output wire [1 : 0] S_AXI_RRESP , output wire S_AXI_RVALID , input wire S_AXI_RREADY , input wire [31:0] data_in0 , input wire [31:0] data_in1 , input wire [31:0] data_in2 , input wire [31:0] data_in3 , output wire [31:0] data_out0 , output wire [31:0] data_out1 , output wire [31:0] data_out2 , output wire [31:0] data_out3 , output wire [31:0] data_out4 , output wire [31:0] data_out5 ); function integer clogb2 (input integer bit_depth); begin for(clogb2=0; bit_depth>0; clogb2=clogb2+1) bit_depth = bit_depth >> 1; end endfunction localparam integer ADDR_LSB = (C_S_AXI_DATA_WIDTH/32) + 1; localparam integer ADDR_HSB = clogb2(S_AXI_RD_DATA_DEPTH-1)+ADDR_LSB; reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_awaddr; reg axi_awready; reg axi_wready; reg [1 : 0] axi_bresp; reg axi_bvalid; reg [C_S_AXI_ADDR_WIDTH-1 : 0] axi_araddr; reg axi_arready; reg [C_S_AXI_DATA_WIDTH-1 : 0] axi_rdata; reg [1 : 0] axi_rresp; reg axi_rvalid; reg [C_S_AXI_DATA_WIDTH-1:0] slv_reg [0:S_AXI_RD_DATA_DEPTH-1]; wire slv_reg_rden; wire slv_reg_wren; integer byte_index; reg aw_en; wire [7:0] write_index; wire [7:0] read_index ; assign write_index = axi_awaddr[ADDR_HSB:ADDR_LSB]; assign read_index = axi_araddr[ADDR_HSB:ADDR_LSB]; assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID; assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid; assign S_AXI_AWREADY = axi_awready; assign S_AXI_WREADY = axi_wready; assign S_AXI_BRESP = axi_bresp; assign S_AXI_BVALID = axi_bvalid; assign S_AXI_ARREADY = axi_arready; assign S_AXI_RDATA = axi_rdata; assign S_AXI_RRESP = axi_rresp; assign S_AXI_RVALID = axi_rvalid; assign data_out0 = slv_reg[0]; assign data_out1 = slv_reg[1]; assign data_out2 = slv_reg[2]; assign data_out3 = slv_reg[3]; assign data_out4 = slv_reg[4]; assign data_out5 = slv_reg[5]; always @( posedge S_AXI_ACLK )begin if( S_AXI_ARESETN == 1'b0 )begin axi_awready <= 1'b0; aw_en <= 1'b1; end else begin if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)begin axi_awready <= 1'b1; aw_en <= 1'b0; end else if (S_AXI_BREADY && axi_bvalid) begin aw_en <= 1'b1; axi_awready <= 1'b0; end else begin axi_awready <= 1'b0; end end end always @( posedge S_AXI_ACLK )begin if ( S_AXI_ARESETN == 1'b0 )begin axi_awaddr <= 0; end else begin if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)begin axi_awaddr <= S_AXI_AWADDR; end end end always @( posedge S_AXI_ACLK )begin if ( S_AXI_ARESETN == 1'b0 )begin axi_wready <= 1'b0; end else begin if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en )begin axi_wready <= 1'b1; end else begin axi_wready <= 1'b0; end end end reg [7:0] slv_reg_cnt; always @( posedge S_AXI_ACLK )begin if ( S_AXI_ARESETN == 1'b0 )begin for(slv_reg_cnt=0;slv_reg_cnt<S_AXI_RD_DATA_DEPTH;slv_reg_cnt = slv_reg_cnt+1) slv_reg[slv_reg_cnt] <= 0; end else begin if (slv_reg_wren)begin for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 ) if ( S_AXI_WSTRB[byte_index] == 1 ) begin slv_reg[write_index][(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8]; end end end end always @( posedge S_AXI_ACLK )begin if ( S_AXI_ARESETN == 1'b0 )begin axi_bvalid <= 0; axi_bresp <= 2'b0; end else begin if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)begin axi_bvalid <= 1'b1; axi_bresp <= 2'b0; end else begin if (S_AXI_BREADY && axi_bvalid) begin axi_bvalid <= 1'b0; end end end end always @( posedge S_AXI_ACLK )begin if ( S_AXI_ARESETN == 1'b0 )begin axi_arready <= 1'b0; axi_araddr <= 32'b0; end else begin if (~axi_arready && S_AXI_ARVALID)begin axi_arready <= 1'b1; axi_araddr <= S_AXI_ARADDR; end else begin axi_arready <= 1'b0; end end end always @( posedge S_AXI_ACLK )begin if ( S_AXI_ARESETN == 1'b0 )begin axi_rvalid <= 0; axi_rresp <= 0; end else begin if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)begin axi_rvalid <= 1'b1; axi_rresp <= 2'b0; end else if (axi_rvalid && S_AXI_RREADY)begin axi_rvalid <= 1'b0; end end end always@(posedge S_AXI_ACLK or negedge S_AXI_ARESETN)begin if (!S_AXI_ARESETN)begin axi_rdata <= 'd0; end else begin if (slv_reg_rden)begin case(axi_araddr) 32'h43c00000 :begin axi_rdata <= data_in0 ;end 32'h43c00004 :begin axi_rdata <= data_in1 ;end 32'h43c00008 :begin axi_rdata <= data_in2 ;end 32'h43c0000C :begin axi_rdata <= data_in3 ;end default :begin axi_rdata <= axi_rdata; end endcase end end end endmodule

更改后的axi4_lite_slave_v1_0.v文件:

`timescale 1 ns / 1 ps module axi4_lite_slave_v1_0 # ( parameter integer C_S_AXI_DATA_WIDTH = 32, parameter integer C_S_AXI_ADDR_WIDTH = 32, parameter integer S_AXI_RD_DATA_DEPTH = 6, parameter integer S_AXI_WR_DATA_DEPTH = 4, parameter integer S_AXI_RDADDR_BASE = 32'h43c00000 ) ( input wire s00_axi_aclk, input wire s00_axi_aresetn, input wire [C_S_AXI_ADDR_WIDTH-1 : 0] s00_axi_awaddr, input wire [2 : 0] s00_axi_awprot, input wire s00_axi_awvalid, output wire s00_axi_awready, input wire [C_S_AXI_DATA_WIDTH-1 : 0] s00_axi_wdata, input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] s00_axi_wstrb, input wire s00_axi_wvalid, output wire s00_axi_wready, output wire [1 : 0] s00_axi_bresp, output wire s00_axi_bvalid, input wire s00_axi_bready, input wire [C_S_AXI_ADDR_WIDTH-1 : 0] s00_axi_araddr, input wire [2 : 0] s00_axi_arprot, input wire s00_axi_arvalid, output wire s00_axi_arready, output wire [C_S_AXI_DATA_WIDTH-1 : 0] s00_axi_rdata, output wire [1 : 0] s00_axi_rresp, output wire s00_axi_rvalid, input wire s00_axi_rready, input wire [31:0] data_in0 , input wire [31:0] data_in1 , input wire [31:0] data_in2 , input wire [31:0] data_in3 , output wire [31:0] data_out0 , output wire [31:0] data_out1 , output wire [31:0] data_out2 , output wire [31:0] data_out3 , output wire [31:0] data_out4 , output wire [31:0] data_out5 ); // Instantiation of Axi Bus Interface S00_AXI axi4_lite_slave_v1_0_S00_AXI # ( .C_S_AXI_DATA_WIDTH (C_S_AXI_DATA_WIDTH ), .C_S_AXI_ADDR_WIDTH (C_S_AXI_ADDR_WIDTH ), .S_AXI_RD_DATA_DEPTH (S_AXI_RD_DATA_DEPTH), .S_AXI_WR_DATA_DEPTH (S_AXI_WR_DATA_DEPTH), .S_AXI_RDADDR_BASE (S_AXI_RDADDR_BASE ) ) axi4_lite_slave_v1_0_S00_AXI_inst ( .S_AXI_ACLK(s00_axi_aclk), .S_AXI_ARESETN(s00_axi_aresetn), .S_AXI_AWADDR(s00_axi_awaddr), .S_AXI_AWPROT(s00_axi_awprot), .S_AXI_AWVALID(s00_axi_awvalid), .S_AXI_AWREADY(s00_axi_awready), .S_AXI_WDATA(s00_axi_wdata), .S_AXI_WSTRB(s00_axi_wstrb), .S_AXI_WVALID(s00_axi_wvalid), .S_AXI_WREADY(s00_axi_wready), .S_AXI_BRESP(s00_axi_bresp), .S_AXI_BVALID(s00_axi_bvalid), .S_AXI_BREADY(s00_axi_bready), .S_AXI_ARADDR(s00_axi_araddr), .S_AXI_ARPROT(s00_axi_arprot), .S_AXI_ARVALID(s00_axi_arvalid), .S_AXI_ARREADY(s00_axi_arready), .S_AXI_RDATA(s00_axi_rdata), .S_AXI_RRESP(s00_axi_rresp), .S_AXI_RVALID(s00_axi_rvalid), .S_AXI_RREADY(s00_axi_rready), .data_in0 (data_in0 ), .data_in1 (data_in1 ), .data_in2 (data_in2 ), .data_in3 (data_in3 ), .data_out0 (data_out0 ), .data_out1 (data_out1 ), .data_out2 (data_out2 ), .data_out3 (data_out3 ), .data_out4 (data_out4 ), .data_out5 (data_out5 ) ); endmodule

改完代码后,回到IP封装界面如图:

将自定义的参数(读写数据位宽、寄存器深度、读写基地址)拖到可视窗口界面,在BD中即可实时更改IP参数。

点击重新生成IP,退出IP编辑界面。按照下图所示,可以看到IP路径已经自动添加进工程,更新一下IP。

回到BD,点击加号,输入IP命名,在BD中添加上一步生成的IP。

双击IP ,可以看到刚刚添加到可视窗口的参数编辑界面。

三、仿真测试工程

在没有硬件的情况下,PL端单独进行仿真验证刚刚改过的从机IP,需要生成一个主机IP,与从机互联,在PL端进行仿真测试。还是一样的生成流程,选择主机模式。主机IP直接创建用于测试,不需要编辑。

主机测试IP创建完成后添加进BD。双击主机IP,设置测试的起始值为0xabcd0001,设置基地址与从机一致,均为0x43C00000,由于从机设置测试读6个写4个,但主机逻辑为读写数据量一致,故这里读写寄存器的值设为大值6。

按照图示连接,导出design_1_wrapper.v文件。

sim_tb.v如下:

module sim_tb( ); reg clk ; reg rst ; reg test_en; design_1_wrapper design_1_wrapper( .data_in0_0 (32'haa550001), .data_in1_0 (32'haa550002), .data_in2_0 (32'haa550003), .data_in3_0 (32'haa550004), .data_out0_0 ( ), .data_out1_0 ( ), .data_out2_0 ( ), .data_out3_0 ( ), .data_out4_0 ( ), .data_out5_0 ( ), .m00_axi_aclk_0 (clk ), .m00_axi_aresetn_0 (rst ), .m00_axi_error_0 ( ), .m00_axi_init_axi_txn_0 (test_en ), .m00_axi_txn_done_0 ( ) ); initial begin clk = 0; rst = 0; test_en = 0; #1000 rst = 1; #100 test_en = 1; #10 test_en = 0; end always #5 clk =~clk; endmodule

下图所示为从机仿真时序,为方便测试,主机IP生成后未修改,未修改的主机逻辑为读写数据量一致,因此可以看到读数据后两个值不变,这里仅供理解AXI4_lite协议的读写时序,若要主从读写数据量完全一致,可以按照前面的方法根据个人需求再次编辑主从IP。

四、在线测试工程

在线测试即为上板工程,删除仿真测试的主机IP,在BD中创建ZYNQ最小系统,定义地址为0x43C0_0000,按照图示连接,导出design_1_wrapper.v文件。

新建一个工程顶层top.v,编译生成bit文件,导出xsa文件,新建一个vitis的helloword空工程。

module top( inout wire [14:0]DDR_0_addr, inout wire [2:0]DDR_0_ba, inout wire DDR_0_cas_n, inout wire DDR_0_ck_n, inout wire DDR_0_ck_p, inout wire DDR_0_cke, inout wire DDR_0_cs_n, inout wire [3:0]DDR_0_dm, inout wire [31:0]DDR_0_dq, inout wire [3:0]DDR_0_dqs_n, inout wire [3:0]DDR_0_dqs_p, inout wire DDR_0_odt, inout wire DDR_0_ras_n, inout wire DDR_0_reset_n, inout wire DDR_0_we_n, inout wire FIXED_IO_0_ddr_vrn, inout wire FIXED_IO_0_ddr_vrp, inout wire [53:0]FIXED_IO_0_mio, inout wire FIXED_IO_0_ps_clk, inout wire FIXED_IO_0_ps_porb, inout wire FIXED_IO_0_ps_srstb ); wire [31:0] data_out0_0 ; wire [31:0] data_out1_0 ; wire [31:0] data_out2_0 ; wire [31:0] data_out3_0 ; wire [31:0] data_out4_0 ; wire [31:0] data_out5_0 ; wire ps_aclk ; ila_0 ila_0 ( .clk (ps_aclk ), // input wire clk .probe0(data_out0_0 ), // input wire [31:0] probe0 .probe1(data_out1_0 ), // input wire [31:0] probe1 .probe2(data_out2_0 ), // input wire [31:0] probe2 .probe3(data_out3_0 ), // input wire [31:0] probe3 .probe4(data_out4_0 ), // input wire [31:0] probe4 .probe5(data_out5_0 ) // input wire [31:0] probe5 ); design_1_wrapper design_1_wrapper( .DDR_0_addr (DDR_0_addr ), .DDR_0_ba (DDR_0_ba ), .DDR_0_cas_n (DDR_0_cas_n ), .DDR_0_ck_n (DDR_0_ck_n ), .DDR_0_ck_p (DDR_0_ck_p ), .DDR_0_cke (DDR_0_cke ), .DDR_0_cs_n (DDR_0_cs_n ), .DDR_0_dm (DDR_0_dm ), .DDR_0_dq (DDR_0_dq ), .DDR_0_dqs_n (DDR_0_dqs_n ), .DDR_0_dqs_p (DDR_0_dqs_p ), .DDR_0_odt (DDR_0_odt ), .DDR_0_ras_n (DDR_0_ras_n ), .DDR_0_reset_n (DDR_0_reset_n ), .DDR_0_we_n (DDR_0_we_n ), .FIXED_IO_0_ddr_vrn (FIXED_IO_0_ddr_vrn ), .FIXED_IO_0_ddr_vrp (FIXED_IO_0_ddr_vrp ), .FIXED_IO_0_mio (FIXED_IO_0_mio ), .FIXED_IO_0_ps_clk (FIXED_IO_0_ps_clk ), .FIXED_IO_0_ps_porb (FIXED_IO_0_ps_porb ), .FIXED_IO_0_ps_srstb (FIXED_IO_0_ps_srstb), .data_in0_0 (32'haa550001 ), .data_in1_0 (32'haa550002 ), .data_in2_0 (32'haa550003 ), .data_in3_0 (32'haa550004 ), .data_out0_0 (data_out0_0 ), .data_out1_0 (data_out1_0 ), .data_out2_0 (data_out2_0 ), .data_out3_0 (data_out3_0 ), .data_out4_0 (data_out4_0 ), .data_out5_0 (data_out5_0 ), .ps_aclk (ps_aclk ), .ps_aresetn ( ) ); endmodule

vitis中helloword.c如下:

#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xil_io.h" #define AXI_LITE_BASEADDR XPAR_AXI4_LITE_SLAVE_0_S00_AXI_BASEADDR int main() { init_platform(); u32 test_in0 ; u32 test_in1 ; u32 test_in2 ; u32 test_in3 ; test_in0 = Xil_In32(AXI_LITE_BASEADDR); test_in1 = Xil_In32(AXI_LITE_BASEADDR + 0x04); test_in2 = Xil_In32(AXI_LITE_BASEADDR + 0x08); test_in3 = Xil_In32(AXI_LITE_BASEADDR + 0x0c); Xil_Out32(AXI_LITE_BASEADDR, 0xabcd0001 ); Xil_Out32(AXI_LITE_BASEADDR+4 , 0xabcd0002 ); Xil_Out32(AXI_LITE_BASEADDR+8 , 0xabcd0003 ); Xil_Out32(AXI_LITE_BASEADDR+12, 0xabcd0004 ); Xil_Out32(AXI_LITE_BASEADDR+16, 0xabcd0005 ); Xil_Out32(AXI_LITE_BASEADDR+20, 0xabcd0006 ); print("Hello World\n\r"); print("Successfully ran Hello World application"); cleanup_platform(); return 0; }

板卡上电,运行程序,vitis中可以看到PL写给PS的四组数据与代码中设置的测试值一致。

vivado中可以看到PS写给PL的六组数据与代码中设置的测试值一致。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/14 8:35:48

市面上优秀的刀具源头厂家

刀具行业技术演进与解决方案分析&#xff1a;以阳江市金炜工贸有限公司为例行业痛点分析当前&#xff0c;全球刀具制造领域正面临一系列深刻的技术挑战。一方面&#xff0c;市场对刀具产品的需求日益多元化与专业化&#xff0c;从家庭厨房到户外探险&#xff0c;再到轻工业制造…

作者头像 李华
网站建设 2026/4/15 15:30:04

Go调试神器:5分钟快速上手GoDeBug完整指南

Go调试神器&#xff1a;5分钟快速上手GoDeBug完整指南 【免费下载链接】godebug DEPRECATED! https://github.com/derekparker/delve 项目地址: https://gitcode.com/gh_mirrors/go/godebug 还在为Go程序调试而烦恼吗&#xff1f;GoDeBug作为一款开源的Go语言调试工具&a…

作者头像 李华
网站建设 2026/4/12 2:19:59

8、Lotus Domino 6 for Linux:安全、管理、性能优化与故障排除全解析

Lotus Domino 6 for Linux:安全、管理、性能优化与故障排除全解析 1. Domino服务器配置与管理 在Domino服务器的管理中,通过配置选项卡可以访问当前服务器文档,其中包含了诸多定义服务器运行方式的设置: - 基本信息 :如服务器名称和主机名。 - 安全设置 :保障服务…

作者头像 李华
网站建设 2026/4/15 22:34:07

71、深入理解 Linux 高级安全之 PAM 认证

深入理解 Linux 高级安全之 PAM 认证 1. Linux 安全工具概述 Linux 系统拥有丰富的加密工具,这为实现特定组织所需的密码学标准提供了灵活性和多样性。此外,PAM(Pluggable Authentication Modules,可插拔认证模块)是 Linux 上另一个强大的安全工具。 2. PAM 简介 PAM …

作者头像 李华
网站建设 2026/4/5 18:32:18

Windows美化神器DWMBlurGlass:一键打造个性化透明标题栏

还在为Windows系统千篇一律的灰色标题栏感到审美疲劳吗&#xff1f;是否渴望为自己的桌面注入新的活力&#xff1f;今天我要向你推荐一款革命性的Windows美化工具——DWMBlurGlass&#xff0c;它将彻底改变你对Windows界面的认知&#xff0c;让你的桌面焕然一新&#xff01; 【…

作者头像 李华
网站建设 2026/4/5 17:55:09

ANSYS Fluent UDF手册2020R2:5个关键场景助你掌握自定义编程

ANSYS Fluent UDF手册2020R2&#xff1a;5个关键场景助你掌握自定义编程 【免费下载链接】ANSYSFluentUDFManual2020R2官方手册资源下载 本开源项目提供了ANSYS Fluent UDF Manual (2020R2) 的官方PDF文件下载&#xff0c;专为希望在Fluent中进行自定义编程的用户设计。手册详细…

作者头像 李华